picata 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. LICENSE.md +24 -0
  2. README.md +59 -0
  3. components/HelloWorld.tsx +11 -0
  4. entrypoint.tsx +268 -0
  5. manage.py +15 -0
  6. picata/__init__.py +1 -0
  7. picata/apps.py +33 -0
  8. picata/blocks.py +175 -0
  9. picata/helpers/__init__.py +70 -0
  10. picata/helpers/wagtail.py +61 -0
  11. picata/log_utils.py +47 -0
  12. picata/middleware.py +54 -0
  13. picata/migrations/0001_initial.py +264 -0
  14. picata/migrations/0002_alter_article_content_alter_basicpage_content.py +112 -0
  15. picata/migrations/0003_alter_article_content_alter_basicpage_content.py +104 -0
  16. picata/migrations/0004_alter_article_content_alter_basicpage_content.py +105 -0
  17. picata/migrations/0005_socialsettings.py +48 -0
  18. picata/migrations/0006_alter_article_content.py +71 -0
  19. picata/migrations/0007_splitviewpage.py +69 -0
  20. picata/migrations/0008_alter_splitviewpage_content.py +96 -0
  21. picata/migrations/0009_alter_splitviewpage_content.py +111 -0
  22. picata/migrations/0010_alter_splitviewpage_content.py +105 -0
  23. picata/migrations/0011_alter_splitviewpage_options_and_more.py +113 -0
  24. picata/migrations/0012_alter_splitviewpage_content.py +109 -0
  25. picata/migrations/0013_alter_article_content.py +43 -0
  26. picata/migrations/0014_alter_article_content_alter_article_summary.py +24 -0
  27. picata/migrations/0015_alter_article_options_article_tagline_and_more.py +28 -0
  28. picata/migrations/0016_alter_article_options_alter_articletag_options_and_more.py +33 -0
  29. picata/migrations/0017_articletagrelation_alter_article_tags_and_more.py +35 -0
  30. picata/migrations/0018_rename_articletag_pagetag_and_more.py +21 -0
  31. picata/migrations/0019_rename_name_plural_articletype__name_plural.py +18 -0
  32. picata/migrations/0020_rename__name_plural_articletype__pluralised_name.py +18 -0
  33. picata/migrations/0021_rename_article_type_article_page_type.py +18 -0
  34. picata/migrations/0022_homepage.py +28 -0
  35. picata/migrations/__init__.py +0 -0
  36. picata/models.py +486 -0
  37. picata/settings/__init__.py +1 -0
  38. picata/settings/base.py +345 -0
  39. picata/settings/dev.py +94 -0
  40. picata/settings/mypy.py +7 -0
  41. picata/settings/prod.py +12 -0
  42. picata/settings/test.py +6 -0
  43. picata/static/picata/ada-profile.jpg +0 -0
  44. picata/static/picata/ada-social-bear.jpg +0 -0
  45. picata/static/picata/favicon.ico +0 -0
  46. picata/static/picata/fonts/Bitter-Light.ttf +0 -0
  47. picata/static/picata/fonts/Bitter-LightItalic.ttf +0 -0
  48. picata/static/picata/fonts/FiraCode-Light.ttf +0 -0
  49. picata/static/picata/fonts/FiraCode-SemiBold.ttf +0 -0
  50. picata/static/picata/fonts/Sacramento-Regular.ttf +0 -0
  51. picata/static/picata/fonts/ZillaSlab-Bold.ttf +0 -0
  52. picata/static/picata/fonts/ZillaSlab-BoldItalic.ttf +0 -0
  53. picata/static/picata/fonts/ZillaSlab-Light.ttf +0 -0
  54. picata/static/picata/fonts/ZillaSlab-LightItalic.ttf +0 -0
  55. picata/static/picata/fonts/ZillaSlabHighlight-Bold.ttf +0 -0
  56. picata/static/picata/icons.svg +56 -0
  57. picata/templates/picata/3_column.html +28 -0
  58. picata/templates/picata/404.html +11 -0
  59. picata/templates/picata/500.html +13 -0
  60. picata/templates/picata/_post_list.html +24 -0
  61. picata/templates/picata/article.html +20 -0
  62. picata/templates/picata/base.html +135 -0
  63. picata/templates/picata/basic_page.html +10 -0
  64. picata/templates/picata/blocks/icon_link_item.html +7 -0
  65. picata/templates/picata/blocks/icon_link_list.html +4 -0
  66. picata/templates/picata/blocks/icon_link_list_stream.html +3 -0
  67. picata/templates/picata/dl_view.html +18 -0
  68. picata/templates/picata/home_page.html +21 -0
  69. picata/templates/picata/post_listing.html +17 -0
  70. picata/templates/picata/previews/3col.html +73 -0
  71. picata/templates/picata/previews/dl.html +10 -0
  72. picata/templates/picata/previews/split.html +10 -0
  73. picata/templates/picata/previews/theme_gallery.html +158 -0
  74. picata/templates/picata/search_results.html +28 -0
  75. picata/templates/picata/split_view.html +15 -0
  76. picata/templates/picata/tags/site_menu.html +8 -0
  77. picata/templatetags/__init__.py +1 -0
  78. picata/templatetags/absolute_static.py +15 -0
  79. picata/templatetags/menu_tags.py +42 -0
  80. picata/templatetags/stringify.py +23 -0
  81. picata/transformers.py +60 -0
  82. picata/typing/__init__.py +19 -0
  83. picata/typing/wagtail.py +31 -0
  84. picata/urls.py +48 -0
  85. picata/validators.py +36 -0
  86. picata/views.py +80 -0
  87. picata/wagtail_hooks.py +43 -0
  88. picata/wsgi.py +15 -0
  89. picata-0.0.1.dist-info/METADATA +87 -0
  90. picata-0.0.1.dist-info/RECORD +94 -0
  91. picata-0.0.1.dist-info/WHEEL +4 -0
  92. picata-0.0.1.dist-info/licenses/LICENSE.md +24 -0
  93. pygments.sass +382 -0
  94. styles.sass +300 -0
@@ -0,0 +1,23 @@
1
+ """Template tags to transform Python types into human-readable strings."""
2
+
3
+ from django import template
4
+
5
+ register = template.Library()
6
+
7
+
8
+ @register.filter
9
+ def stringify(value: list, quote_style: str | None = None) -> str:
10
+ """Convert a list of strings into a human-readable string with optional quoting."""
11
+ if not isinstance(value, list):
12
+ raise TypeError("The 'stringify' filter currently only supports lists.")
13
+
14
+ quote = "'" if quote_style == "single" else '"' if quote_style == "double" else ""
15
+ quoted_items = [f"{quote}{item!s}{quote}" for item in value]
16
+
17
+ if len(quoted_items) == 0:
18
+ return ""
19
+ if len(quoted_items) == 1:
20
+ return quoted_items[0]
21
+ if len(quoted_items) == 2: # noqa: PLR2004
22
+ return " and ".join(quoted_items)
23
+ return f"{', '.join(quoted_items[:-1])}, and {quoted_items[-1]}"
picata/transformers.py ADDED
@@ -0,0 +1,60 @@
1
+ """Callables to transform the response."""
2
+
3
+ from lxml import etree
4
+
5
+ from hpk.helpers import ALPHANUMERIC_REGEX, get_full_text
6
+
7
+
8
+ def add_heading_ids(tree: etree._Element) -> None:
9
+ """Add a unique id to any heading in <main> missing one, derived from its inner text."""
10
+ seen_ids = set()
11
+ main = tree.xpath("/html/body/main")
12
+ if not main:
13
+ return
14
+
15
+ for heading in main[0].xpath(".//h1|//h2|//h3|//h4|//h5|//h6"):
16
+ if heading.get("id"):
17
+ continue
18
+ heading_text = get_full_text(heading)
19
+ slug = heading_text.lower().replace(" ", "-")
20
+ unique_id = slug
21
+ count = 1
22
+ while unique_id in seen_ids:
23
+ unique_id = f"{slug}-{count}"
24
+ count += 1
25
+ seen_ids.add(unique_id)
26
+ heading.set("id", unique_id)
27
+
28
+
29
+ class AnchorInserter:
30
+ """Transformer to insert anchored pilcrows into targeted elements in the document."""
31
+
32
+ def __init__(self, root: str, targets: str) -> None:
33
+ """Remember the root paths we're to operate on."""
34
+ self.root_xpath = root
35
+ self.targets_xpath = targets
36
+
37
+ def __call__(self, tree: etree._Element) -> None:
38
+ """Inserts anchors into targets within the specified roots."""
39
+ for root_element in tree.xpath(self.root_xpath):
40
+ self._process_targets(root_element, self.targets_xpath)
41
+
42
+ def _process_targets(self, root: etree._Element, targets: str) -> None:
43
+ """Processes targets within a given root element, inserting anchors."""
44
+ for target in root.xpath(targets):
45
+ target_id = target.get("id")
46
+ if not target_id or target.xpath(".//a"):
47
+ continue
48
+
49
+ sanitized_id = self._sanitize_id(target_id)
50
+ if sanitized_id != target_id:
51
+ target.set("id", sanitized_id)
52
+
53
+ # Append an anchored pilcrow to the target element
54
+ anchor = etree.Element("a", href=f"#{target_id}", **{"class": "target-link"})
55
+ anchor.text = "¶"
56
+ target.append(anchor)
57
+
58
+ def _sanitize_id(self, id_value: str) -> str:
59
+ """Sanitize the ID by removing non-alphanumeric characters."""
60
+ return ALPHANUMERIC_REGEX.sub("", id_value)
@@ -0,0 +1,19 @@
1
+ """Reusable types for the hpk project."""
2
+
3
+ from typing import Any, TypedDict
4
+
5
+ from django.http import HttpRequest
6
+
7
+ # Generic arguments and keyword arguments
8
+ Args = tuple[Any, ...]
9
+ Kwargs = dict[str, Any]
10
+
11
+
12
+ class Context(TypedDict):
13
+ """Base class for context dicts passed all around the system."""
14
+
15
+ request: HttpRequest
16
+
17
+
18
+ # Log arguments for structured logging
19
+ LogArg = str | int | float | bool
@@ -0,0 +1,31 @@
1
+ """Types for Wagtail.
2
+
3
+ NB: This module split the hpk.typing module into a package in order to avoid
4
+ circular imports during program initialisation, with the `from wagtail` imports.
5
+ """
6
+
7
+ from typing import Any
8
+
9
+ from wagtail.blocks import StructBlock
10
+ from wagtail.models import Page
11
+
12
+ from . import Context
13
+
14
+
15
+ # StructBlock types
16
+ class BlockRenderContextDict(Context):
17
+ """Context dicts passed to render functions for Blocks."""
18
+
19
+ self: StructBlock
20
+ page: Page
21
+
22
+
23
+ BlockRenderContext = BlockRenderContextDict | None
24
+ BlockRenderValue = dict[str, Any]
25
+
26
+
27
+ class PageContext(Context):
28
+ """Base class for Wagtail Page classes."""
29
+
30
+ self: Page
31
+ page: Page
picata/urls.py ADDED
@@ -0,0 +1,48 @@
1
+ """Top-level URL configuration for the site."""
2
+
3
+ from debug_toolbar.toolbar import debug_toolbar_urls
4
+ from django.conf import settings
5
+ from django.contrib import admin
6
+ from django.urls import include, path, re_path
7
+ from wagtail import urls as wagtail_urls
8
+ from wagtail.admin import urls as wagtailadmin_urls
9
+ from wagtail.contrib.sitemaps.views import sitemap
10
+ from wagtail.documents import urls as wagtaildocs_urls
11
+ from wagtail.images.views.serve import ServeView
12
+
13
+ from hpk.views import search
14
+
15
+ urlpatterns = [
16
+ path("django-admin/", admin.site.urls), # Django Admin
17
+ path("admin/", include(wagtailadmin_urls)), # Wagtail Admin
18
+ path("documents/", include(wagtaildocs_urls)), # Wagtail documents
19
+ re_path(
20
+ r"^images/([^/]*)/(\d*)/([^/]*)/[^/]*$", ServeView.as_view(), name="wagtailimages_serve"
21
+ ),
22
+ path("sitemap.xml", sitemap),
23
+ path("search/", search, name="search"),
24
+ ]
25
+
26
+ # Debug-mode-only URLs
27
+ if settings.DEBUG:
28
+ from django.conf.urls.static import static
29
+ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
30
+ from django.views.generic import RedirectView
31
+
32
+ from hpk.views import debug_shell, preview
33
+
34
+ # Serve static and media files from development server
35
+ urlpatterns += staticfiles_urlpatterns()
36
+ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
37
+
38
+ # Enable Django Debug Toolbar
39
+ urlpatterns += debug_toolbar_urls()
40
+
41
+ urlpatterns += [
42
+ path("favicon.ico", RedirectView.as_view(url=settings.STATIC_URL + "favicon.ico")),
43
+ path("shell/", debug_shell), # Just raises an exception (to invoke Werkzeug shell access)
44
+ path("preview/<slug:file>/", preview, name="debug_preview"), # templates/previews/<file>
45
+ ]
46
+
47
+ # Let Wagtail take care of the rest
48
+ urlpatterns += [path("", include(wagtail_urls))]
picata/validators.py ADDED
@@ -0,0 +1,36 @@
1
+ """Custom validators for Django fields."""
2
+
3
+ from django.core.exceptions import ValidationError
4
+ from django.core.validators import URLValidator
5
+
6
+
7
+ class HREFValidator:
8
+ """Custom validator for href attributes in HTML anchor tags.
9
+
10
+ Basically it's `URLValidator` but with 'mailto:', 'tel:' and 'file:' added.
11
+ (Doesn't actually validate email addresses, telephone numbers, or file paths.)
12
+ """
13
+
14
+ def __init__(
15
+ self, extra_schemes: list[str] | None = None, url_schemes: list[str] | None = None
16
+ ) -> None:
17
+ """Store schemes we check for and initialise a basic `URLValidator`."""
18
+ self.schemes: list[str] = extra_schemes or ["mailto", "tel", "file", "sms"]
19
+ self.base_validator = URLValidator(schemes=url_schemes)
20
+
21
+ def __call__(self, value: str) -> None:
22
+ """Try validating a custom scheme (e.g. "mailto:…") if the `URLValidator` fails."""
23
+ try:
24
+ self.base_validator(value)
25
+ except ValidationError as err:
26
+ if ":" in value:
27
+ if not any(value.startswith(f"{scheme}:") for scheme in self.schemes):
28
+ raise ValidationError(
29
+ f"'{value}' is not a valid href.", code="invalid_href"
30
+ ) from err
31
+ elif not value.startswith(("/", "#")): # Allow relative links or fragments
32
+ raise ValidationError(
33
+ f"'{value}' is not a valid href.", code="invalid_href"
34
+ ) from err
35
+ else:
36
+ return
picata/views.py ADDED
@@ -0,0 +1,80 @@
1
+ """Top-level views for the site."""
2
+
3
+ # NB: Django's meta-class shenanigans over-complicate type hinting when QuerySets get involved.
4
+ # pyright: reportAttributeAccessIssue=false, reportArgumentType=false
5
+
6
+ import logging
7
+ from typing import TYPE_CHECKING, NoReturn
8
+
9
+ from django.http import HttpRequest, HttpResponse
10
+ from django.shortcuts import render
11
+ from hpk.helpers.wagtail import (
12
+ filter_pages_by_tags,
13
+ filter_pages_by_type,
14
+ page_preview_data,
15
+ visible_pages_qs,
16
+ )
17
+ from hpk.models import ArticleType
18
+
19
+ if TYPE_CHECKING:
20
+ from wagtail.query import PageQuerySet
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ def debug_shell(request: HttpRequest) -> NoReturn:
26
+ """Just `assert False`, to force an exception and get to the Werkzeug debug console."""
27
+ logger.info(
28
+ "Raising `assert False` in the `debug_shell` view. "
29
+ "Request details: method=%s, path=%s, user=%s",
30
+ request.method,
31
+ request.path,
32
+ request.user if request.user.is_authenticated else "Anonymous",
33
+ )
34
+ assert False # noqa: B011, PT015, S101
35
+
36
+
37
+ def preview(request: HttpRequest, file: str) -> HttpResponse:
38
+ """Render a named template from the "templates/previews/" directory."""
39
+ return render(request, f"picata/previews/{file}.html")
40
+
41
+
42
+ def search(request: HttpRequest) -> HttpResponse:
43
+ """Render search results from the `query` and `tags` GET parameters."""
44
+ results: dict[str, str | list[str] | set[str]] = {}
45
+
46
+ # Base QuerySet for all pages
47
+ pages: PageQuerySet = visible_pages_qs(request)
48
+
49
+ # Perform search by query
50
+ query_string = request.GET.get("query")
51
+ if query_string:
52
+ pages = pages.search(query_string)
53
+ results["query"] = query_string
54
+
55
+ # Resolve specific pages post-search
56
+ specific_pages = [page.specific for page in pages]
57
+
58
+ # Filter by page types
59
+ page_types_string = request.GET.get("page_types")
60
+ if page_types_string:
61
+ page_type_slugs = {slug.strip() for slug in page_types_string.split(",") if slug.strip()}
62
+ matching_page_types = ArticleType.objects.filter(slug__in=page_type_slugs)
63
+ specific_pages = filter_pages_by_type(specific_pages, page_type_slugs)
64
+ results["page_types"] = [page_type.name for page_type in matching_page_types]
65
+
66
+ # Filter by tags
67
+ tags_string = request.GET.get("tags")
68
+ if tags_string:
69
+ tags = {tag.strip() for tag in tags_string.split(",") if tag.strip()}
70
+ specific_pages = filter_pages_by_tags(specific_pages, tags)
71
+ results["tags"] = tags
72
+
73
+ # Handle empty cases
74
+ if not (query_string or tags_string or page_types_string):
75
+ specific_pages = []
76
+
77
+ # Enhance pages with preview and publication data
78
+ page_previews = [page_preview_data(request, page) for page in specific_pages]
79
+
80
+ return render(request, "picata/search_results.html", {**results, "pages": page_previews})
@@ -0,0 +1,43 @@
1
+ """Wagtail hooks, used to customise view-level behaviour of the Wagtail admin and front-end.
2
+
3
+ See: https://docs.wagtail.org/en/stable/reference/hooks.html
4
+ """
5
+
6
+ import logging
7
+ from typing import ClassVar
8
+
9
+ from django.db.models import QuerySet, Value
10
+ from django.db.models.functions import Coalesce
11
+ from django.http import HttpRequest
12
+ from wagtail import hooks
13
+ from wagtail.models import Page
14
+ from wagtail.snippets.views.snippets import SnippetViewSet
15
+
16
+ from hpk.models import PageTag
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @hooks.register("construct_explorer_page_queryset") # type: ignore[reportOptionalCall]
22
+ def order_admin_menu_by_date(parent_page: Page, pages: QuerySet, request: HttpRequest) -> QuerySet: # noqa: ARG001
23
+ """Order admin menus latest-at-top for pages with lots of children (like 'blog')."""
24
+ if parent_page.slug == "blog":
25
+ # Sort directly in order_by with Coalesce
26
+ return pages.order_by(
27
+ Coalesce("first_published_at", "latest_revision_created_at", Value("1970-01-01")).desc()
28
+ )
29
+ return pages
30
+
31
+
32
+ class PageTagViewSet(SnippetViewSet):
33
+ """Viewset for managing `PageTag`s."""
34
+
35
+ icon: str = "tag"
36
+ list_display: ClassVar[list[str]] = ["name"]
37
+ search_fields: ClassVar[list[str]] = ["name"]
38
+
39
+
40
+ @hooks.register("register_admin_viewset") # type: ignore[reportOptionalCall]
41
+ def register_article_tag_viewset() -> SnippetViewSet:
42
+ """Make `PageTag`s editable via the Wagtail admin."""
43
+ return PageTagViewSet(model=PageTag)
picata/wsgi.py ADDED
@@ -0,0 +1,15 @@
1
+ """WSGI config for the hpk project.
2
+
3
+ It exposes the WSGI callable as a module-level variable named ``application``.
4
+
5
+ For more information on this file, see
6
+ https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
7
+ """
8
+
9
+ import os
10
+
11
+ from django.core.wsgi import get_wsgi_application
12
+
13
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hpk.settings.prod")
14
+
15
+ application = get_wsgi_application()
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: picata
3
+ Version: 0.0.1
4
+ Summary: Ada's Wagtail-based CMS & blog
5
+ Project-URL: Documentation, https://github.com/hipikat/picata#readme
6
+ Project-URL: Issues, https://github.com/hipikat/picata/issues
7
+ Project-URL: Source, https://github.com/hipikat/picata
8
+ Author-email: Ada Wright <ada@hpk.io>
9
+ License-Expression: MIT
10
+ License-File: LICENSE.md
11
+ Keywords: blog,cms,django,wagtail
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Framework :: Django CMS
14
+ Classifier: Framework :: Wagtail :: 6
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: Implementation :: CPython
18
+ Requires-Python: >=3.13
19
+ Requires-Dist: gunicorn~=23.0.0
20
+ Requires-Dist: lxml~=5.3.0
21
+ Requires-Dist: psutil~=6.1.0
22
+ Requires-Dist: psycopg~=3.2.3
23
+ Requires-Dist: pygments~=2.18.0
24
+ Requires-Dist: python-slugify~=8.0.4
25
+ Requires-Dist: wagtail-modeladmin~=2.1.0
26
+ Requires-Dist: wagtail~=6.2
27
+ Description-Content-Type: text/markdown
28
+
29
+ # Ada's website
30
+
31
+ Wherein I set up a little website, and learn a bunch of stuff as I go.
32
+
33
+ ## What it's made of
34
+
35
+ ### Inside the box
36
+
37
+ - [Wagtail](https://wagtail.org) (on [Django](https://www.djangoproject.com)) is the web framework
38
+ <!-- - [Tailwind CSS](https://tailwindcss.com) for styling -->
39
+
40
+ ### Holding things together
41
+
42
+ - [UV](https://github.com/astral-sh/uv) for all Python project management
43
+ - [Just](https://just.systems) as a command runner
44
+ - [OpenTofu](https://opentofu.org) for DevOps
45
+ - [Postgres](https://www.postgresql.org) for the database
46
+ - [Docker](https://www.docker.com) for local development
47
+
48
+ ## Quickstart
49
+
50
+ ### Requirements
51
+
52
+ - On a Mac:
53
+
54
+ ```shell
55
+ brew install colima docker
56
+ ```
57
+
58
+ ### Run a development server
59
+
60
+ ```shell
61
+ just tofu workspace select dev
62
+ just tofu apply
63
+ ```
64
+
65
+ This will spin up a box on DigitalOcean using the settings defined in
66
+ [infra/variables.tf](infra/variables.tf), and create a DNS A record at
67
+ (workspace).for.(tld), (i.e. dev.for.hpk.io) pointing to the box. The variables
68
+ `do_token` and `ssh_fingerprint` should be defined in
69
+ [infra/secrets.tfvars](infra/secrets.tfvars). Workspace-specific variables are
70
+ defined in infra/envs/(workspace).tfvars; e.g.
71
+ [infra/envs/dev.tfvars](infra/envs/dev.tfvars) defines the 'tags' list for the
72
+ box as `[development]` and sets `cloud_init_config` to point to the
73
+ [cloud-init](https://cloud-init.io) script
74
+ [config/cloud-init-dev.yml](config/cloud-init-dev.yml).
75
+
76
+ The development cloud-init script will:
77
+
78
+ - Install the system packages [`just`](https://just.systems), [`zsh`](https://www.zsh.org),
79
+ [`gunicorn`](https://gunicorn.org), and `tree`
80
+ - Create a 'wagtail' user, with UID 1500
81
+ - Create the 'ada' user, and:
82
+ - install their SSH public keys,
83
+ - install their dotfiles,
84
+ - add them to the 'sudo' and 'wagtail' groups
85
+ - Install [Node](http://nodejs.org) on the system, from the `TF_VAR_NODE_VERSION`
86
+ defined in [.env](.env)
87
+ - Checkout this repository into `/app`, setting the owner and group to 'wagtail'.
@@ -0,0 +1,94 @@
1
+ LICENSE.md,sha256=Bv8sMyZI5NI6DMrfiAvCwIFRLSfJkimLF2KVcUMteKU,1103
2
+ README.md,sha256=tPe8EjMhr2cMwsf-N-gQcTT-IpyE2kIOnwggeJnSPzM,1990
3
+ entrypoint.tsx,sha256=Tk6L2rCk0KrE5kaSL0GFuL3S19yG-BsUgvNAGe32uy8,8820
4
+ manage.py,sha256=v0zbaNjwEksTx39Z9dgoWh8LxZEH1tuCpjLVVmiXBF4,423
5
+ pygments.sass,sha256=zbDYpWda3EoGmjoC3JshZy-_CECNf6WU9abYPF8EHms,6369
6
+ styles.sass,sha256=4Jb-Gxn9AP09pZzwLlCGGfeacCyrncpJAOCYcy-dyB4,8486
7
+ components/HelloWorld.tsx,sha256=Kp7gvhGehfrX1mw0jgr2_D6AueFgqgfMYGkyQgvWekg,180
8
+ picata/__init__.py,sha256=_kL7fTKu02_hXVnOmF1K7llLgpdOeQyAVliL7I5o-Dg,62
9
+ picata/apps.py,sha256=P1qIVWRACiNUA-TY6aIRvt-MyA-3baG82Z_MEpr2fsw,1241
10
+ picata/blocks.py,sha256=iPJc4eQN7_J-KGMMw3Iln31I1-tBluqgaUF-xCxq2Mc,5279
11
+ picata/log_utils.py,sha256=BRdB3PqpFx1XAhIyAzIOyQKiqrjbT3PBmkhH6-wAWJg,1555
12
+ picata/middleware.py,sha256=ycKEVr2GKGmGFQNqFG4ijBmxFuVK11khtiiAiTsbbsk,2064
13
+ picata/models.py,sha256=dra7x1pbRrMpFydgER_j7zPEnrP9Dqqy1n3rDR1Jbgc,15868
14
+ picata/transformers.py,sha256=8VkJJC0Xm8ZMzKxOp07rSnqJA7b-TiL02e_y07Gh5AI,2209
15
+ picata/urls.py,sha256=kTSLS0-f9YaLmhzgg8mW4Oc9W04eXVf_0TZpEnYdnJo,1828
16
+ picata/validators.py,sha256=X4wdIxbCdmuU-gJv45ptTFB7kHR166jkSQBJiTzP3ZU,1517
17
+ picata/views.py,sha256=L_NXtqZogdwP7X1uBIPOB1qnYSNpCCThuI8O7YeS47E,2874
18
+ picata/wagtail_hooks.py,sha256=Y_50IVpV62TEHtg1h8MN0IDkCWAMTVzv0Hd3eiult9M,1497
19
+ picata/wsgi.py,sha256=XdUhwbLt-MKyr9he5PRphYrvKadC8yF0glx1xxQpCgE,392
20
+ picata/helpers/__init__.py,sha256=acN445qKCuRVfInCEyCtx5W1BggloOSrawzdQ-c9m7s,2427
21
+ picata/helpers/wagtail.py,sha256=p_0qw530UcaIBY3AzeTYY6fOUxmVnC9DaP_0_gByrUw,2108
22
+ picata/migrations/0001_initial.py,sha256=q15Mjii63qa397O7eXyM-BSgTDzf1MqzKAJn1To_huc,9721
23
+ picata/migrations/0002_alter_article_content_alter_basicpage_content.py,sha256=WlmmGgbAaBCZvR904W8gAeyxp30fOfi4a0D5Xpiojsk,4490
24
+ picata/migrations/0003_alter_article_content_alter_basicpage_content.py,sha256=i2KD213JKxzM7Kgxlfufxz405IICBoVFJVeNBZuaRlI,4300
25
+ picata/migrations/0004_alter_article_content_alter_basicpage_content.py,sha256=sZ_ky-xTZREr43y9Zrh1DaqUS5ZXi4r7ilL_EZf9L_E,4204
26
+ picata/migrations/0005_socialsettings.py,sha256=flfEf47418UX972SoL0nta2gKjambGFACXpFD_oeY0s,1541
27
+ picata/migrations/0006_alter_article_content.py,sha256=EVTuWtWf74mpD-YvZEzBEdmwHAixzn4R5PxEABl8n0Q,2690
28
+ picata/migrations/0007_splitviewpage.py,sha256=KK67Kw4kbxVm56BZfKj58mDajZfsCpLwspAFegKQgNA,2675
29
+ picata/migrations/0008_alter_splitviewpage_content.py,sha256=Y5aj5rTgclKxAgpPF7wCOxDpyFe4rrVkxa_YsEAoYCc,3829
30
+ picata/migrations/0009_alter_splitviewpage_content.py,sha256=PPu4Hqtm7PkbQYRB_CzqsS-G3-vkAPncPco8Zrn1IXY,4406
31
+ picata/migrations/0010_alter_splitviewpage_content.py,sha256=Re61nL4y6zHRGMhxADkqHNDkfoWQ8bHGbZK74uJXatg,4265
32
+ picata/migrations/0011_alter_splitviewpage_options_and_more.py,sha256=OPtQipM3COYRVf9RaP9G8ec0x3NlyR8wT1er3m11kg8,4527
33
+ picata/migrations/0012_alter_splitviewpage_content.py,sha256=pPERBPW4uduQ-sGops44p2gavJ2hYh5toZ67hmvjhLo,4357
34
+ picata/migrations/0013_alter_article_content.py,sha256=zVn-YC5jhXiG_c6hkD_uhAgu1BCdsqA1j1xfgJj5n1U,1571
35
+ picata/migrations/0014_alter_article_content_alter_article_summary.py,sha256=5RvNPNyjy0dnyOw9RfcuTB8pFlpmg6p3yK8kuR0zgMk,1186
36
+ picata/migrations/0015_alter_article_options_article_tagline_and_more.py,sha256=8ToGgChYwqSoxo5EgwM8SISbQhFt7yewH-fN3raNE_Y,849
37
+ picata/migrations/0016_alter_article_options_alter_articletag_options_and_more.py,sha256=yxDQhzCMOZCl3NPEyYnM1Yw1E5HAn4wN_BPV5PYrMxE,917
38
+ picata/migrations/0017_articletagrelation_alter_article_tags_and_more.py,sha256=3rPB6p0GxwTCvTVQIDKNFBtrf26q99mdmQwoCqpXyM8,1341
39
+ picata/migrations/0018_rename_articletag_pagetag_and_more.py,sha256=0wFB82uAlJZAA7BD1OVTJIWvY5by8fZss7TIVsVLnnY,485
40
+ picata/migrations/0019_rename_name_plural_articletype__name_plural.py,sha256=K58-B-V2ld2gJ7OuHnrQchC7zZvLP2Bnss3bQB5oS84,391
41
+ picata/migrations/0020_rename__name_plural_articletype__pluralised_name.py,sha256=X9zRPk5G6iMwitrr5BTUB9Nk9VqQQ951HfBrQ8_MXD4,405
42
+ picata/migrations/0021_rename_article_type_article_page_type.py,sha256=DtxWYyke-8RmoFqpW817rtrIzVMSV8wqCpS1e911Nxc,399
43
+ picata/migrations/0022_homepage.py,sha256=SYpqIlquJzLh4YozTcJVjR_0fW_v9GRrY75bnAUk0vE,3591
44
+ picata/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ picata/settings/__init__.py,sha256=5qI40E9aCWsFanUxAnruZi1wXrad3oAwnusglycfPsk,47
46
+ picata/settings/base.py,sha256=APK6EyBUu1C3Q8VX8JciKTQX-iZcARm2BMD54LDgAaY,9273
47
+ picata/settings/dev.py,sha256=6SXFuEH3NTq2L3iWcC49Ky3gxJnPflHE3TtjByzuEOg,2796
48
+ picata/settings/mypy.py,sha256=M-_KU9Qi4twjCHwwuhFbGz9hnIU3TXLH0Sg3XionVNY,148
49
+ picata/settings/prod.py,sha256=iPsqLOdinblT_ayqMW2_GqpNccsXJlWA9-kA015X7Vo,474
50
+ picata/settings/test.py,sha256=H_Wkn_gjsIV0r5HsU-s5HLhW_Oi63VQp4Afj2TIgRhI,244
51
+ picata/static/picata/ada-profile.jpg,sha256=HlewC8MPH_zSr--pUXV5JCEE0emOrn8BIKCQv41WidA,209953
52
+ picata/static/picata/ada-social-bear.jpg,sha256=3jH2kf57boRLS5AD7M-qW-xsBP84didfeM1KN5Xp4tc,128453
53
+ picata/static/picata/favicon.ico,sha256=MJLjMSsDpx9Mjb1v7y8V5oPMX3gLtD4cIDmNAdOgHC8,15406
54
+ picata/static/picata/icons.svg,sha256=LRLgy8bHyZKorDyPxkO2mMdbevKs40sCnhdWoO29pdY,11320
55
+ picata/static/picata/fonts/Bitter-Light.ttf,sha256=JCgJXY06RiEONk2htx2bitpL3zqeGGJ01Z81fwRTwAo,182212
56
+ picata/static/picata/fonts/Bitter-LightItalic.ttf,sha256=A6oI_l_kGd2F9-V0eOYMoydigDPRdahO6aUKMvQXddY,181412
57
+ picata/static/picata/fonts/FiraCode-Light.ttf,sha256=bKCGEsYc36CaTQ_0-STZkfU7PDJXZpyQQDfQD7oJyTQ,188708
58
+ picata/static/picata/fonts/FiraCode-SemiBold.ttf,sha256=BsEuLjCqZkqwFH0_iBxrWH1hrdhDZa9cNM61DkA5hiE,188848
59
+ picata/static/picata/fonts/Sacramento-Regular.ttf,sha256=pbneZ75FSoJrRthYUS4y7sjDAxK-tMT4ZK7iOQQU6cU,64808
60
+ picata/static/picata/fonts/ZillaSlab-Bold.ttf,sha256=7Fo-wbzMoTThzw3ivb2PiLNcB1atOZdGClX22mwHu_Q,248052
61
+ picata/static/picata/fonts/ZillaSlab-BoldItalic.ttf,sha256=xra8p0e0zYZ5gyu5w6BeR8fnOJbZkeoIRFZuRm-FpEI,255272
62
+ picata/static/picata/fonts/ZillaSlab-Light.ttf,sha256=x9c6KiQ-iPpyqCDb2yYgDqi0GW-DNM8YIyTXqehumJ8,239836
63
+ picata/static/picata/fonts/ZillaSlab-LightItalic.ttf,sha256=8pgf5nlQb5DBqfaNKDj2P7iDMRwaW80YjaC3hXb72PA,245200
64
+ picata/static/picata/fonts/ZillaSlabHighlight-Bold.ttf,sha256=MbNNCVxe1Kt-j8rJpognUmTZrh9R9je-35MgwoeL7eU,245180
65
+ picata/templates/picata/3_column.html,sha256=4SYfqTbmAtYICEulpx1RWocBCQUUn32EnZJrcxfVWwA,790
66
+ picata/templates/picata/404.html,sha256=4q8kKGGHWDk9Z8ThW2rP70T3SQrGNGRf153pvYcV7VE,230
67
+ picata/templates/picata/500.html,sha256=1xvvK2uoiZKkc2EuVVnbfg69KmrCJUdplR0vvFtWvKo,369
68
+ picata/templates/picata/_post_list.html,sha256=JpvNAOGmupLQIC6lTyjoyNOyRGMUQwOqEvEaZgSPrsM,915
69
+ picata/templates/picata/article.html,sha256=NBwXpicb_oL2xy3FN8_6KJNbrrQD2rTrNIu1ngOietk,794
70
+ picata/templates/picata/base.html,sha256=gE8pChABBlXUYfyQCkUdVZx9tFHS-cnMEWGNeaHGziI,8140
71
+ picata/templates/picata/basic_page.html,sha256=1FS_xdL6erskk9T-_TP3JWARczVstOLzs2ttvkbPbdk,173
72
+ picata/templates/picata/dl_view.html,sha256=epAV72HR2f0I3GWBEngUtYOQnHSsXs_SsNlhH7u-JbU,494
73
+ picata/templates/picata/home_page.html,sha256=nVDZwlsXfKtdSwQR80e0cHtiX7hf91ws5tYhu_ug_gU,635
74
+ picata/templates/picata/post_listing.html,sha256=3aSWYdPfwvYblE4s7b2P_dOLiiCWcrT1uvXRuDBak5Y,428
75
+ picata/templates/picata/search_results.html,sha256=P5HwdkLX2iQjZFEtD4YOp4Mun17btshjKBw__z6q8Hs,957
76
+ picata/templates/picata/split_view.html,sha256=DqRUKT5wc_-ByibQRZoyDU91omK6TgK7wC3Rp72bbgM,402
77
+ picata/templates/picata/blocks/icon_link_item.html,sha256=t-9LoA00Nv-H031yIL8es89zevbn315jlr5LTiAyM_o,301
78
+ picata/templates/picata/blocks/icon_link_list.html,sha256=7KU-hLOhAdKnoecLcugqWNzO5SgPnN9XfTDs1y60f0c,261
79
+ picata/templates/picata/blocks/icon_link_list_stream.html,sha256=B7yz5Ss_dT_5NIMsVwggnGFGmRgawNQrvnowaJUSUnw,69
80
+ picata/templates/picata/previews/3col.html,sha256=CwnWJpK5dvmVxqhBuu0QSFHWKhZlnc3xEowMQk3ltBo,4473
81
+ picata/templates/picata/previews/dl.html,sha256=ANOqlD3nlj5NF-4sPmya3eo0CNwmxgmUXswmz22Bh30,2095
82
+ picata/templates/picata/previews/split.html,sha256=hqv27u4wKTX8jJiNMazXioyRU9Uajpys_7LVQeI3NtE,2106
83
+ picata/templates/picata/previews/theme_gallery.html,sha256=f10610quPimz6xzpozvpZtdRrTpSP5KFIppuGeOZ308,8007
84
+ picata/templates/picata/tags/site_menu.html,sha256=Tb_BjV88ZH-nRb76alzSXPVUokPC9O2mVByKmeAgQWA,223
85
+ picata/templatetags/__init__.py,sha256=YNGfxmI00gewcJkkUlH219BHimHD_4p5Lz-zXPvgO-U,47
86
+ picata/templatetags/absolute_static.py,sha256=asY9uNFShD5iQCaU-ZjsgXQOJNlmLmkoOvRs2WWhEYE,454
87
+ picata/templatetags/menu_tags.py,sha256=WvsyNHyuD4oiueedWjqnej2PrAQW0FdlGeEYrYd_xbs,1267
88
+ picata/templatetags/stringify.py,sha256=QxStfcCgn29IGinH_bdsZoaiTLL7pz30ObDitlagecs,850
89
+ picata/typing/__init__.py,sha256=Nu2HZtspAQTzxMx6gmRKdDp9DfqmFc5urxfokXp2k-Y,402
90
+ picata/typing/wagtail.py,sha256=r84cf-8AzaWCMULF4HRjl5wmTFKIxw2DwvhxmIDurjA,661
91
+ picata-0.0.1.dist-info/METADATA,sha256=CzIkWSGSTfq45DELALkcS2ReZ-sxZ3sJ-vMpyfRWq7M,2996
92
+ picata-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
+ picata-0.0.1.dist-info/licenses/LICENSE.md,sha256=Bv8sMyZI5NI6DMrfiAvCwIFRLSfJkimLF2KVcUMteKU,1103
94
+ picata-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,24 @@
1
+ # The MIT License (MIT)
2
+
3
+ Copyright © `2024` `Ada Wright <ada@hpk.io>`
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation
7
+ files (the “Software”), to deal in the Software without
8
+ restriction, including without limitation the rights to use,
9
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the
11
+ Software is furnished to do so, subject to the following
12
+ conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ OTHER DEALINGS IN THE SOFTWARE.