├── .editorconfig ├── .env.dist ├── .gitignore ├── Makefile ├── README.md ├── cms ├── Dockerfile ├── __init__.py ├── api │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── schema.py │ ├── tests.py │ └── views.py ├── cards │ ├── __init__.py │ ├── apps.py │ ├── management │ │ ├── __init__.py │ │ └── commands │ │ │ ├── __init__.py │ │ │ ├── create_superuser.py │ │ │ └── delete_all_wagtail_images.py │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ ├── models.py │ ├── static │ │ └── css │ │ │ └── welcome_page.css │ └── wagtail_hooks.py ├── cms │ ├── __init__.py │ ├── settings.py │ ├── static │ │ └── .gitkeep │ ├── templates │ │ ├── 404.html │ │ ├── 500.html │ │ └── base.html │ ├── urls.py │ └── wsgi.py ├── entrypoint.sh ├── manage.py ├── requirements.txt ├── search │ ├── __init__.py │ └── views.py └── wait_for_postgres.py ├── docker-compose.yml └── web_frontend ├── .dockerignore ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── Dockerfile ├── README.md ├── assets ├── README.md └── css │ └── tailwind.css ├── components ├── InfoCard │ └── index.vue └── README.md ├── jsconfig.json ├── layouts ├── README.md └── default.vue ├── middleware └── README.md ├── nuxt.config.js ├── package.json ├── pages ├── README.md ├── entry │ └── _id.vue └── index.vue ├── plugins ├── README.md ├── apollo-error-handler.js ├── apollo-watch-loading-handler.js ├── default-apollo-config.js └── v-body-scroll-lock.js ├── static └── favicon │ ├── android-icon-144x144.png │ ├── android-icon-192x192.png │ ├── android-icon-36x36.png │ ├── android-icon-48x48.png │ ├── android-icon-72x72.png │ ├── android-icon-96x96.png │ ├── apple-icon-114x114.png │ ├── apple-icon-120x120.png │ ├── apple-icon-144x144.png │ ├── apple-icon-152x152.png │ ├── apple-icon-180x180.png │ ├── apple-icon-57x57.png │ ├── apple-icon-60x60.png │ ├── apple-icon-72x72.png │ ├── apple-icon-76x76.png │ ├── apple-icon-precomposed.png │ ├── apple-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── favicon.ico │ ├── manifest.json │ ├── ms-icon-144x144.png │ ├── ms-icon-150x150.png │ ├── ms-icon-310x310.png │ └── ms-icon-70x70.png ├── tailwind.config.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.{ts,js,py}] 13 | quote_type = single 14 | 15 | [*.py] 16 | indent_style = space 17 | indent_size = 4 18 | max_line_length = 120 19 | 20 | [pep8] 21 | # ignore = E226,E302,E41 22 | max-line-length = 120 23 | indent-size = 2 24 | 25 | [*.md] 26 | max_line_length = off 27 | trim_trailing_whitespace = false 28 | 29 | [Makefile] 30 | indent_style = tab 31 | 32 | [{package.json,.gitlab-ci.yml, docker-compose*.yml}] 33 | indent_style = space 34 | indent_size = 2 35 | -------------------------------------------------------------------------------- /.env.dist: -------------------------------------------------------------------------------- 1 | DJANGO_SECRET_KEY=local 2 | POSTGRES_USER=root 3 | POSTGRES_PASSWORD=root 4 | POSTGRES_DB=cms 5 | DJANGO_SETTINGS_MODULE=cms.settings 6 | WAGTAIL_ADMIN_USER=root 7 | WAGTAIL_ADMIN_PASSWORD=root 8 | MINIO_ACCESS_KEY=root 9 | MINIO_SECRET_KEY=rootroot 10 | MINIO_BROWSER=on 11 | MINIO_ENDPOINT=127.0.0.1:9000 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/**/node_modules 2 | **/**/__pycache__ 3 | misc/ 4 | cms/media/ 5 | **/**/.DS_Store 6 | .env 7 | .vscode/ 8 | .idea/ 9 | **/**/.mypy_cache/ 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | docker-compose exec cms bash -c 'pip install -r requirements.txt' 3 | 4 | install_web_frontend: 5 | docker-compose run --rm web_frontend bash -c 'rm -fr node_modules && yarn install --force' 6 | 7 | migrate: 8 | docker-compose exec cms bash -c 'python manage.py makemigrations' 9 | docker-compose exec cms bash -c 'python manage.py migrate' 10 | 11 | createsuperuser: 12 | docker-compose exec cms bash -c "python manage.py createsuperuser" 13 | 14 | backup: 15 | docker-compose exec cms bash -c 'python manage.py dumpdata --natural-foreign --indent 2 \ 16 | -e contenttypes -e auth.permission \ 17 | -e wagtailcore.groupcollectionpermission \ 18 | -e wagtailcore.grouppagepermission -e wagtailimages.rendition \ 19 | -e sessions -e wagtailcore.site > fixtures.json' 20 | 21 | load: 22 | docker-compose exec cms bash -c 'python manage.py loaddata fixtures.json' 23 | 24 | 25 | deletewagtailimages: 26 | docker-compose exec cms bash -c 'python manage.py delete_all_wagtail_images' 27 | 28 | 29 | initial: migrate createsuperuser 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Table of Contents 3 | 4 | 1. [Requirements](#org98at330) 5 | 2. [Local Setup](#org57856e7) 6 | 1. [Endpoints](#org809e937) 7 | 1. [Frontend - Nuxt](#orgc37a804) 8 | 2. [Backend - Admin](#org211c10f) 9 | 3. [GraphQL - GraphiQL](#orgc70d5b5) 10 | 4. [Static Files - MinIO](#org8110bc6) 11 | 2. [Credentials](#org749259c) 12 | 1. [DB - Postgre](#orgc6c10a9) 13 | 2. [Backend - Admin](#orge1ac287) 14 | 3. [Static Files - MinIO](#orgc1fcbcb) 15 | 3. [Branding](#org13fa485) 16 | 4. [Frontend](#orgc473881) 17 | 5. [Administration](#orgbf9c4d0) 18 | 1. [Delete all Wagtail Images](#orgf36cc02) 19 | 2. [Migrate Changes](#org2525778) 20 | 3. [Persist Data](#org0ac7a34) 21 | 22 | 23 | 24 | 25 | 26 | 27 | # Requirements 28 | 29 | You need to have [docker](https://docs.docker.com/get-docker/) and preferely docker-compose installed on your system. 30 | 31 | 32 | 33 | 34 | # Local Setup 35 | 36 | Follow these steps to set everything up locally on your machine 37 | 38 | 1. Clone repo 39 | 40 | git clone https://gitlab.com/devs-group/base-wagtail.git && cd base-wagtail 41 | 42 | 2. Copy [.env.dist](.env.dist) to .env 43 | 44 | cp .env.dist .env 45 | 46 | 3. Install node modules 47 | 48 | cd web_frontend 49 | yarn install 50 | 51 | 4. Start Containers with docker-compose 52 | 53 | docker-compose up -d 54 | 55 | 56 | 57 | 58 | ## Endpoints 59 | 60 | As soon as everything is up and running visit these addresses to interact with 61 | the provided APIs, where necessary use [Credentials](#org749259c). 62 | 63 | 64 | 65 | 66 | ### Frontend - Nuxt 67 | 68 | 69 | 70 | 71 | 72 | 73 | ### Backend - Admin 74 | 75 | 76 | 77 | 78 | 79 | 80 | ### GraphQL - GraphiQL 81 | 82 | 83 | 84 | 85 | 86 | ### Static Files - MinIO 87 | 88 | 89 | 90 | 91 | 92 | 93 | ## Credentials 94 | 95 | Default Credentials for the dev setup containing only insensitive test data. 96 | It is advised to change these in the .env.dist and .env files. 97 | 98 | 99 | 100 | 101 | ### DB - Postgre 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
databasecms
userroot
passwordroot
130 | 131 | 132 | 133 | 134 | ### Backend - Admin 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 |
userroot
passwordroot
157 | 158 | 159 | 160 | 161 | ### Static Files - MinIO 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 |
access-keyroot
secret-keyrootroot
184 | 185 | 186 | 187 | 188 | # Branding 189 | 190 | Search the project for strings starting with "PLACEHOLDER_" and exchange to enable custom branding of the admin panel and more. 191 | 192 | 193 | 194 | 195 | # Frontend 196 | 197 | Details concerning the nuxt instance serving the frontend can be found in its own [README](web_frontend/README.md) 198 | 199 | 200 | 201 | 202 | # Administration 203 | 204 | To interface with the containers, a Makefile is provided which provides additional 205 | management commands to the [default django-admin commands](https://docs.djangoproject.com/en/3.0/ref/django-admin/). 206 | 207 | 208 | 209 | 210 | ## Delete all Wagtail Images 211 | 212 | If there is a `key not found` error due to a dead reference, wagtail images might be the problem. 213 | It usually helps to delete all instances of the `wagtail.images.Image` class. 214 | This make command shortens the procedure: 215 | 216 | make deletewagtailimages 217 | 218 | 219 | 220 | 221 | ## Migrate Changes 222 | 223 | To shorten the migration process after a database relevant change was made use: 224 | 225 | make migrate 226 | 227 | This will execute inside the container the commands `./manage.py makemigrations` and `./manage.py migrate` 228 | 229 | 230 | 231 | 232 | ## Persist Data 233 | 234 | To be able to work with data from a different docker volume, fixtures can be created with: 235 | 236 | make backup 237 | 238 | To load the fixtures us: 239 | 240 | make load 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /cms/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | # LABEL maintainer="PLACEHOLDER@E.MAIL" 3 | LABEL maintainer="vincent@devs-group.com" 4 | 5 | ENV PYTHONUNBUFFERED 1 6 | ENV DJANGO_ENV dev 7 | 8 | COPY ./entrypoint.sh /usr/local/bin 9 | 10 | WORKDIR /app 11 | COPY ./ /app 12 | 13 | # Install any needed packages specified in requirements.txt 14 | COPY ./requirements.txt ./requirements.txt 15 | RUN pip install --upgrade pip 16 | RUN pip install -r requirements.txt 17 | 18 | CMD ["/usr/local/bin/entrypoint.sh"] 19 | -------------------------------------------------------------------------------- /cms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/__init__.py -------------------------------------------------------------------------------- /cms/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/api/__init__.py -------------------------------------------------------------------------------- /cms/api/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /cms/api/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApiConfig(AppConfig): 5 | name = 'api' 6 | -------------------------------------------------------------------------------- /cms/api/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /cms/api/schema.py: -------------------------------------------------------------------------------- 1 | import graphene 2 | from cards.models import InfoCard 3 | from graphene_django import DjangoObjectType 4 | 5 | 6 | class InfoCardNode(DjangoObjectType): 7 | image = graphene.String(width=graphene.Int()) 8 | 9 | def resolve_image(self, info, width=860): 10 | if not self.image: 11 | return "" 12 | 13 | return self.image.get_rendition('width-%s' % width).url 14 | 15 | class Meta: 16 | model = InfoCard 17 | 18 | 19 | class Query(graphene.ObjectType): 20 | info_card = graphene.Field(InfoCardNode, id=graphene.Int()) 21 | info_cards = graphene.List(InfoCardNode) 22 | 23 | def resolve_info_card(self, info, id): 24 | return InfoCard.objects.get(pk=id) 25 | 26 | def resolve_info_cards(self, info): 27 | return InfoCard.objects.all() 28 | 29 | 30 | schema = graphene.Schema(query=Query) 31 | -------------------------------------------------------------------------------- /cms/api/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /cms/api/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /cms/cards/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/cards/__init__.py -------------------------------------------------------------------------------- /cms/cards/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CardsConfig(AppConfig): 5 | name = 'cards' 6 | -------------------------------------------------------------------------------- /cms/cards/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/cards/management/__init__.py -------------------------------------------------------------------------------- /cms/cards/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/cards/management/commands/__init__.py -------------------------------------------------------------------------------- /cms/cards/management/commands/create_superuser.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import get_user_model 2 | from django.core.management.base import BaseCommand 3 | 4 | 5 | class Command(BaseCommand): 6 | help = 'Create a test super user with the given password' 7 | 8 | def add_arguments(self, parser): 9 | parser.add_argument('username', type=str) 10 | parser.add_argument('password', type=str) 11 | 12 | def handle(self, *args, **options): 13 | username = options.get('username') 14 | password = options.get('password') 15 | try: 16 | User = get_user_model() 17 | if not User.objects.filter(username=username).exists(): 18 | User.objects.create_superuser(username, 19 | 'admin@example.com', 20 | password) 21 | print('Superuser %s with password %s successfully created!\n' 22 | % (username, password)) 23 | else: 24 | print('Superuser %s with password %s already exists!\n' 25 | % (username, password)) 26 | except Exception as e: 27 | print('ERROR: Can\'t create superuser.\n%s\n' % e) 28 | -------------------------------------------------------------------------------- /cms/cards/management/commands/delete_all_wagtail_images.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from django.core.management.base import BaseCommand 4 | from wagtail.images.models import Image 5 | 6 | 7 | class Command(BaseCommand): 8 | help = 'For local development delete all linked wagtail images to prevent key: message error. You will be prompted.' 9 | 10 | def yes_or_no(self, question): 11 | reply = str(input(question + ' (y/n): ')).lower().strip() 12 | if reply[0] == 'y': 13 | return True 14 | if reply[0] == 'n': 15 | return False 16 | else: 17 | return self.yes_or_no("Invalid input: %s" % (question)) 18 | 19 | def handle(self, *args, **options): 20 | images = Image.objects.all() 21 | if not images: 22 | print("No wagtail images found to delete.") 23 | return 24 | 25 | if self.yes_or_no('Are you sure you want to delete %d wagtail images?' % (len(images))): 26 | try: 27 | Image.objects.all().delete() 28 | except Exception as e: 29 | print('ERROR: Can\'t delete wagtail images.\n%s\n' % e) 30 | -------------------------------------------------------------------------------- /cms/cards/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.12 on 2020-05-12 10:11 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | import wagtail.core.fields 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ('wagtailimages', '0022_uploadedimage'), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='InfoCard', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('title', models.CharField(max_length=254)), 22 | ('info', wagtail.core.fields.RichTextField(blank=True)), 23 | ('image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.Image', verbose_name='Image')), 24 | ], 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /cms/cards/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/cards/migrations/__init__.py -------------------------------------------------------------------------------- /cms/cards/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from wagtail.admin.edit_handlers import FieldPanel 3 | from wagtail.core.fields import RichTextField 4 | from wagtail.core.models import Page 5 | from wagtail.images.edit_handlers import ImageChooserPanel 6 | 7 | 8 | class InfoCard(models.Model): 9 | title = models.CharField(max_length=254) 10 | info = RichTextField(blank=True) 11 | image = models.ForeignKey('wagtailimages.Image', on_delete=models.SET_NULL, 12 | verbose_name='Image', related_name='+', 13 | null=True, blank=True) 14 | 15 | panels = [ 16 | FieldPanel('title'), 17 | FieldPanel('info', classname='full'), 18 | ImageChooserPanel('image') 19 | ] 20 | 21 | def __str__(self): 22 | return self.title 23 | -------------------------------------------------------------------------------- /cms/cards/static/css/welcome_page.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | *, 6 | *:before, 7 | *:after { 8 | box-sizing: inherit; 9 | } 10 | 11 | body { 12 | max-width: 960px; 13 | min-height: 100vh; 14 | margin: 0 auto; 15 | padding: 0 15px; 16 | color: #231f20; 17 | font-family: 'Helvetica Neue', 'Segoe UI', Arial, sans-serif; 18 | line-height: 1.25; 19 | } 20 | 21 | a { 22 | background-color: transparent; 23 | color: #308282; 24 | text-decoration: underline; 25 | } 26 | 27 | a:hover { 28 | color: #ea1b10; 29 | } 30 | 31 | h1, 32 | h2, 33 | h3, 34 | h4, 35 | h5, 36 | p, 37 | ul { 38 | padding: 0; 39 | margin: 0; 40 | font-weight: 400; 41 | } 42 | 43 | main { 44 | display: block; /* For IE11 support */ 45 | } 46 | 47 | svg:not(:root) { 48 | overflow: hidden; 49 | } 50 | 51 | .header { 52 | display: flex; 53 | justify-content: space-between; 54 | align-items: center; 55 | padding-top: 20px; 56 | padding-bottom: 10px; 57 | border-bottom: 1px solid #e6e6e6; 58 | } 59 | 60 | .logo { 61 | width: 150px; 62 | margin-right: 20px; 63 | } 64 | 65 | .logo a { 66 | display: block; 67 | } 68 | 69 | .figure-logo { 70 | max-width: 150px; 71 | max-height: 55.1px; 72 | } 73 | 74 | .release-notes { 75 | font-size: 14px; 76 | } 77 | 78 | .main { 79 | padding: 40px 0; 80 | margin: 0 auto; 81 | text-align: center; 82 | } 83 | 84 | .figure-space { 85 | max-width: 265px; 86 | } 87 | 88 | @-webkit-keyframes pos { 89 | 0%, 100% { 90 | -webkit-transform: rotate(-6deg); 91 | transform: rotate(-6deg); 92 | } 93 | 50% { 94 | -webkit-transform: rotate(6deg); 95 | transform: rotate(6deg); 96 | } 97 | } 98 | 99 | @keyframes pos { 100 | 0%, 100% { 101 | -webkit-transform: rotate(-6deg); 102 | transform: rotate(-6deg); 103 | } 104 | 50% { 105 | -webkit-transform: rotate(6deg); 106 | transform: rotate(6deg); 107 | } 108 | } 109 | 110 | .egg { 111 | fill: #43b1b0; 112 | -webkit-animation: pos 3s ease infinite; 113 | animation: pos 3s ease infinite; 114 | -webkit-transform: translateY(50px); 115 | transform: translateY(50px); 116 | -webkit-transform-origin: 50% 80%; 117 | transform-origin: 50% 80%; 118 | } 119 | 120 | .main-text { 121 | max-width: 400px; 122 | margin: 5px auto; 123 | } 124 | 125 | .main-text h1 { 126 | font-size: 22px; 127 | } 128 | 129 | .main-text p { 130 | margin: 15px auto 0; 131 | } 132 | 133 | .footer { 134 | display: flex; 135 | flex-wrap: wrap; 136 | justify-content: space-between; 137 | border-top: 1px solid #e6e6e6; 138 | padding: 10px; 139 | } 140 | 141 | .option { 142 | display: block; 143 | padding: 10px 10px 10px 34px; 144 | position: relative; 145 | text-decoration: none; 146 | } 147 | 148 | .option svg { 149 | width: 24px; 150 | height: 24px; 151 | fill: gray; 152 | border: 1px solid #d9d9d9; 153 | padding: 5px; 154 | border-radius: 100%; 155 | top: 10px; 156 | left: 0; 157 | position: absolute; 158 | } 159 | 160 | .option h4 { 161 | font-size: 19px; 162 | text-decoration: underline; 163 | } 164 | 165 | .option p { 166 | padding-top: 3px; 167 | color: #231f20; 168 | font-size: 15px; 169 | font-weight: 300; 170 | } 171 | 172 | @media (max-width: 996px) { 173 | body { 174 | max-width: 780px; 175 | } 176 | } 177 | 178 | @media (max-width: 767px) { 179 | .option { 180 | flex: 0 0 50%; 181 | } 182 | } 183 | 184 | @media (max-width: 599px) { 185 | .main { 186 | padding: 20px 0; 187 | } 188 | 189 | .figure-space { 190 | max-width: 200px; 191 | } 192 | 193 | .footer { 194 | display: block; 195 | width: 300px; 196 | margin: 0 auto; 197 | } 198 | } 199 | 200 | @media (max-width: 360px) { 201 | .header-link { 202 | max-width: 100px; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /cms/cards/wagtail_hooks.py: -------------------------------------------------------------------------------- 1 | from cards.models import InfoCard 2 | from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register 3 | 4 | 5 | class InfoCardAdminMenu(ModelAdmin): 6 | model = InfoCard 7 | menu_icon = 'form' 8 | menu_label = 'Info Card' 9 | search_fields = ('title',) 10 | 11 | 12 | # -------------------- Register Buttons in admin panel -------------------- 13 | modeladmin_register(InfoCardAdminMenu) 14 | -------------------------------------------------------------------------------- /cms/cms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/cms/__init__.py -------------------------------------------------------------------------------- /cms/cms/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for COOKIECUTTER_PLACEHOLDER_PROJECTNAME project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.2.8. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.2/ref/settings/ 11 | """ 12 | 13 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 14 | import os 15 | 16 | PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) 17 | BASE_DIR = os.path.dirname(PROJECT_DIR) 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ 21 | 22 | 23 | # Application definition 24 | 25 | INSTALLED_APPS = [ 26 | 27 | 'cards', 28 | 'search', 29 | 'api', 30 | 31 | 'corsheaders', 32 | 33 | 'wagtail.api.v2', 34 | 'wagtail.contrib.forms', 35 | 'wagtail.contrib.modeladmin', 36 | 'wagtail.contrib.redirects', 37 | 'wagtail.contrib.styleguide', 38 | 'wagtail.embeds', 39 | 'wagtail.sites', 40 | 'wagtail.users', 41 | 'wagtail.snippets', 42 | 'wagtail.documents', 43 | 'wagtail.images', 44 | 'wagtail.search', 45 | 'wagtail.admin', 46 | 'wagtail.core', 47 | 48 | 'modelcluster', 49 | 'taggit', 50 | 'wagtailmenus', 51 | 52 | 'wagtail_graphql', 53 | 'graphene_django', 54 | 55 | 'django.contrib.admin', 56 | 'django.contrib.auth', 57 | 'django.contrib.contenttypes', 58 | 'django.contrib.sessions', 59 | 'django.contrib.messages', 60 | 'django.contrib.staticfiles', 61 | ] 62 | 63 | MIDDLEWARE = [ 64 | 'django.contrib.sessions.middleware.SessionMiddleware', 65 | 66 | 'corsheaders.middleware.CorsMiddleware', 67 | 'django.middleware.common.CommonMiddleware', 68 | 'django.middleware.csrf.CsrfViewMiddleware', 69 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 70 | 'django.contrib.messages.middleware.MessageMiddleware', 71 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 72 | 'django.middleware.security.SecurityMiddleware', 73 | 74 | 'wagtail.core.middleware.SiteMiddleware', 75 | 'wagtail.contrib.redirects.middleware.RedirectMiddleware', 76 | ] 77 | 78 | ROOT_URLCONF = 'cms.urls' 79 | 80 | TEMPLATES = [ 81 | { 82 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 83 | 'DIRS': [ 84 | os.path.join(PROJECT_DIR, 'templates'), 85 | ], 86 | 'APP_DIRS': True, 87 | 'OPTIONS': { 88 | 'context_processors': [ 89 | 'django.template.context_processors.debug', 90 | 'django.template.context_processors.request', 91 | 'django.contrib.auth.context_processors.auth', 92 | 'django.contrib.messages.context_processors.messages', 93 | 'wagtailmenus.context_processors.wagtailmenus', 94 | ], 95 | }, 96 | }, 97 | ] 98 | 99 | GRAPHENE = { 100 | 'SCHEMA': 'api.schema.schema', 101 | } 102 | 103 | GRAPHQL_API = { 104 | 'APPS': [ 105 | 'cards', 106 | ] 107 | } 108 | 109 | WSGI_APPLICATION = 'cms.wsgi.application' 110 | 111 | # Password validation 112 | # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators 113 | 114 | AUTH_PASSWORD_VALIDATORS = [ 115 | { 116 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 117 | }, 118 | { 119 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 120 | }, 121 | { 122 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 123 | }, 124 | { 125 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 126 | }, 127 | ] 128 | 129 | # Static files (CSS, JavaScript, Images) 130 | # https://docs.djangoproject.com/en/2.2/howto/static-files/ 131 | TIME_ZONE = 'UTC' 132 | 133 | STATIC_URL = '/static/' 134 | STATIC_ROOT = './static_files/' 135 | 136 | STATICFILES_DIRS = [ 137 | os.path.join(PROJECT_DIR, 'static'), 138 | ] 139 | 140 | STATICFILES_FINDERS = [ 141 | 'django.contrib.staticfiles.finders.FileSystemFinder', 142 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 143 | ] 144 | 145 | DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage" 146 | STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage" 147 | MINIO_STORAGE_ENDPOINT = 'minio:9000' 148 | MINIO_STORAGE_STATIC_URL = '//%s/local-static/' % ( 149 | os.environ.get('MINIO_ENDPOINT')) 150 | MINIO_STORAGE_MEDIA_URL = '//%s/local-media/' % ( 151 | os.environ.get('MINIO_ENDPOINT')) 152 | MINIO_STORAGE_ACCESS_KEY = os.environ.get('MINIO_ACCESS_KEY') 153 | MINIO_STORAGE_SECRET_KEY = os.environ.get('MINIO_SECRET_KEY') 154 | MINIO_STORAGE_USE_HTTPS = False 155 | MINIO_STORAGE_MEDIA_BUCKET_NAME = 'local-media' 156 | MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True 157 | MINIO_STORAGE_STATIC_BUCKET_NAME = 'local-static' 158 | MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True 159 | 160 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 161 | MEDIA_URL = '/media/' 162 | 163 | # Wagtail settings 164 | 165 | WAGTAIL_SITE_NAME = "cms" 166 | 167 | # Base URL to use when referring to full URLs within the Wagtail admin backend - 168 | # e.g. in notification emails. Don't include '/admin' or a trailing slash 169 | BASE_URL = 'http://example.com' 170 | 171 | CORS_ORIGIN_ALLOW_ALL = True 172 | CORS_ALLOW_CREDENTIALS = True 173 | 174 | # SECURITY WARNING: don't run with debug turned on in production! 175 | DEBUG = True 176 | ENABLE_DEBUG_BAR = False 177 | WAGTAIL_CACHE = True 178 | 179 | # SECURITY WARNING: keep the secret key used in production secret! 180 | SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY') 181 | 182 | # SECURITY WARNING: define the correct hosts in production! 183 | ALLOWED_HOSTS = ['*'] 184 | 185 | EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' 186 | 187 | # Database 188 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases 189 | 190 | 191 | if ENABLE_DEBUG_BAR is True and DEBUG is True: 192 | 193 | INSTALLED_APPS = INSTALLED_APPS + [ 194 | 'debug_toolbar', 195 | ] 196 | 197 | MIDDLEWARE = MIDDLEWARE + [ 198 | 'debug_toolbar.middleware.DebugToolbarMiddleware', 199 | ] 200 | 201 | # Postgres 202 | DATABASES = { 203 | 'default': { 204 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 205 | 'NAME': os.environ.get('POSTGRES_DB'), 206 | 'USER': os.environ.get('POSTGRES_USER'), 207 | 'PASSWORD': os.environ.get('POSTGRES_PASSWORD'), 208 | 'HOST': 'postgres', 209 | 'PORT': '5432', 210 | } 211 | } 212 | 213 | INTERNAL_IPS = ("127.0.0.1", "172.17.0.1", "172.28.0.1") 214 | 215 | try: 216 | from .local import * 217 | except ImportError: 218 | pass 219 | -------------------------------------------------------------------------------- /cms/cms/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/cms/static/.gitkeep -------------------------------------------------------------------------------- /cms/cms/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block body_class %}template-404{% endblock %} 4 | 5 | {% block content %} 6 |

Page not found

7 | 8 |

Sorry, this page could not be found.

9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /cms/cms/templates/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Internal server error 6 | 7 | 8 | 9 |

Internal server error

10 | 11 |

Sorry, there seems to be an error. Please try again soon.

12 | 13 | 14 | -------------------------------------------------------------------------------- /cms/cms/templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static wagtailuserbar %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% block title %} 9 | {% if self.seo_title %}{{ self.seo_title }}{% else %}{{ self.title }}{% endif %} 10 | {% endblock %} 11 | {% block title_suffix %} 12 | {% with self.get_site.site_name as site_name %} 13 | {% if site_name %}- {{ site_name }}{% endif %} 14 | {% endwith %} 15 | {% endblock %} 16 | 17 | 18 | 19 | 20 | {# Global stylesheets #} 21 | 22 | 23 | {% block extra_css %} 24 | {# Override this in templates to add extra stylesheets #} 25 | {% endblock %} 26 | 27 | 28 | 29 | {% wagtailuserbar %} 30 | 31 | {% block content %}{% endblock %} 32 | 33 | {# Global javascript #} 34 | 35 | 36 | {% block extra_js %} 37 | {# Override this in templates to add extra javascript #} 38 | {% endblock %} 39 | 40 | 41 | -------------------------------------------------------------------------------- /cms/cms/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls import include, url 3 | from django.contrib import admin 4 | from django.urls import path 5 | from django.views.decorators.csrf import csrf_exempt 6 | from graphene_django.views import GraphQLView 7 | from search import views as search_views 8 | from wagtail.admin import urls as wagtailadmin_urls 9 | from wagtail.core import urls as wagtail_urls 10 | from wagtail.documents import urls as wagtaildocs_urls 11 | from wagtail.images.views.serve import ServeView 12 | 13 | urlpatterns = [ 14 | url(r'^django-admin/', admin.site.urls), 15 | url(r'^admin/', include(wagtailadmin_urls)), 16 | url(r'^documents/', include(wagtaildocs_urls)), 17 | url(r'^api/graphql', csrf_exempt(GraphQLView.as_view())), 18 | url(r'^api/graphiql', csrf_exempt(GraphQLView.as_view(graphiql=True, pretty=True))), 19 | url(r'', include(wagtail_urls)), 20 | ] 21 | 22 | if settings.DEBUG: 23 | from django.conf.urls.static import static 24 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns 25 | import debug_toolbar 26 | 27 | # Serve static and media files from development server 28 | urlpatterns += staticfiles_urlpatterns() 29 | urlpatterns += static(settings.MEDIA_URL, 30 | document_root=settings.MEDIA_ROOT) 31 | 32 | urlpatterns = [ 33 | path('__debug__/', include(debug_toolbar.urls)), 34 | ] + urlpatterns 35 | -------------------------------------------------------------------------------- /cms/cms/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for PLACEHOLDER_PROJECTNAME project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cms.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /cms/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function waitForPostgres() { 4 | echo "Waiting for postgres ..." 5 | python wait_for_postgres.py 6 | } 7 | 8 | function migrateTables() { 9 | echo "Migrating tables..." 10 | python manage.py makemigrations && python manage.py migrate --noinput 11 | } 12 | 13 | function loadStatics() { 14 | echo "Loading static files..." 15 | python manage.py collectstatic --noinput 16 | } 17 | 18 | function loadFixtures() { 19 | echo "Loading fixtures..." 20 | if [ -f fixtures.json ]; then 21 | python manage.py loaddata fixtures.json 22 | fi 23 | } 24 | 25 | function createSuperuser () { 26 | echo "Creating superuser..." 27 | local username="$1" 28 | local password="$2" 29 | python manage.py create_superuser $username $password 30 | } 31 | 32 | function syncPageTranslationFields () { 33 | echo "Syncing page translation fields..." 34 | python manage.py sync_page_translation_fields 35 | } 36 | 37 | 38 | waitForPostgres 39 | migrateTables 40 | loadStatics 41 | createSuperuser $WAGTAIL_ADMIN_USER $WAGTAIL_ADMIN_PASSWORD 42 | gunicorn --bind 0.0.0.0:8000 --reload --workers 3 --worker-class gevent --access-logfile - cms.wsgi:application 43 | -------------------------------------------------------------------------------- /cms/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", 7 | "cms.settings") 8 | 9 | from django.core.management import execute_from_command_line 10 | 11 | execute_from_command_line(sys.argv) 12 | -------------------------------------------------------------------------------- /cms/requirements.txt: -------------------------------------------------------------------------------- 1 | Django>=2.2,<2.3 2 | wagtail>=2.9,<3.0 3 | gunicorn==19.9.0 4 | gevent==1.4.0 5 | ipython==7.12.0 6 | django-debug-toolbar 7 | 8 | 9 | # Storage 10 | psycopg2==2.8.3 11 | wagtailmenus>=3.0 12 | django-minio-storage==0.3.5 13 | 14 | # API 15 | wagtail-graphql 16 | graphene-django 17 | django-cors-headers 18 | -------------------------------------------------------------------------------- /cms/search/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/cms/search/__init__.py -------------------------------------------------------------------------------- /cms/search/views.py: -------------------------------------------------------------------------------- 1 | from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator 2 | from django.shortcuts import render 3 | 4 | from wagtail.core.models import Page 5 | from wagtail.search.models import Query 6 | 7 | 8 | def search(request): 9 | search_query = request.GET.get('query', None) 10 | page = request.GET.get('page', 1) 11 | 12 | # Search 13 | if search_query: 14 | search_results = Page.objects.live().search(search_query) 15 | query = Query.get(search_query) 16 | 17 | # Record hit 18 | query.add_hit() 19 | else: 20 | search_results = Page.objects.none() 21 | 22 | # Pagination 23 | paginator = Paginator(search_results, 10) 24 | try: 25 | search_results = paginator.page(page) 26 | except PageNotAnInteger: 27 | search_results = paginator.page(1) 28 | except EmptyPage: 29 | search_results = paginator.page(paginator.num_pages) 30 | 31 | return render(request, 'search/search.html', { 32 | 'search_query': search_query, 33 | 'search_results': search_results, 34 | }) 35 | -------------------------------------------------------------------------------- /cms/wait_for_postgres.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from time import sleep, time 4 | 5 | import psycopg2 6 | 7 | check_timeout = os.getenv("POSTGRES_CHECK_TIMEOUT", 30) 8 | check_interval = os.getenv("POSTGRES_CHECK_INTERVAL", 1) 9 | interval_unit = "second" if check_interval == 1 else "seconds" 10 | config = { 11 | "dbname": os.getenv("POSTGRES_DB", "postgres"), 12 | "user": os.getenv("POSTGRES_USER", "postgres"), 13 | "password": os.getenv("POSTGRES_PASSWORD", ""), 14 | "host": os.getenv("DATABASE_URL", "postgres") 15 | } 16 | 17 | start_time = time() 18 | logger = logging.getLogger() 19 | logger.setLevel(logging.INFO) 20 | logger.addHandler(logging.StreamHandler()) 21 | 22 | 23 | def pg_isready(**kwargs): 24 | while time() - start_time < check_timeout: 25 | try: 26 | conn = psycopg2.connect(**kwargs) 27 | logger.info("Postgres is ready! ✨ 💅") 28 | conn.close() 29 | return True 30 | except psycopg2.OperationalError as e: 31 | logger.info( 32 | f"Postgres isn't ready.\n%s\n Waiting for {check_interval} {interval_unit}..." % e) 33 | sleep(check_interval) 34 | 35 | logger.error( 36 | f"We could not connect to Postgres within {check_timeout} seconds.") 37 | return False 38 | 39 | 40 | pg_isready(**config) 41 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | volumes: 4 | db: 5 | minio-data: 6 | 7 | networks: 8 | default: 9 | driver: bridge 10 | external: false 11 | 12 | services: 13 | web_frontend: 14 | restart: always 15 | env_file: .env 16 | image: node:12.15.0 17 | working_dir: /app 18 | volumes: 19 | - ./web_frontend:/app 20 | command: "yarn dev" 21 | ports: 22 | - 3000:3000 23 | depends_on: 24 | - cms 25 | links: 26 | - cms 27 | 28 | cms: 29 | restart: always 30 | env_file: .env 31 | build: 32 | context: ./cms 33 | dockerfile: Dockerfile 34 | entrypoint: /usr/bin/entrypoint.sh 35 | working_dir: /app 36 | volumes: 37 | - ./cms:/app 38 | - ./cms/entrypoint.sh:/usr/bin/entrypoint.sh 39 | ports: 40 | - 8000:8000 41 | depends_on: 42 | - postgres 43 | - minio 44 | links: 45 | - postgres 46 | - minio 47 | networks: 48 | - default 49 | 50 | postgres: 51 | image: postgres:9.6 52 | volumes: 53 | - db:/var/lib/postgresql/data 54 | networks: 55 | - default 56 | env_file: .env 57 | 58 | minio: 59 | image: minio/minio:RELEASE.2020-02-07T04-56-50Z 60 | env_file: .env 61 | volumes: 62 | - minio-data:/data 63 | ports: 64 | - 9000:9000 65 | command: server /data 66 | -------------------------------------------------------------------------------- /web_frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /web_frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /web_frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | parser: 'babel-eslint' 9 | }, 10 | extends: [ 11 | '@nuxtjs', 12 | 'prettier', 13 | 'prettier/vue', 14 | 'plugin:prettier/recommended', 15 | 'plugin:nuxt/recommended' 16 | ], 17 | plugins: ['prettier'], 18 | // add your custom rules here 19 | rules: { 20 | 'no-console': 'off' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /web_frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | /logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # Nuxt generate 72 | dist 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless 79 | 80 | # IDE / Editor 81 | .idea 82 | 83 | # Service worker 84 | sw.* 85 | 86 | # Mac OSX 87 | .DS_Store 88 | 89 | # Vim swap files 90 | *.swp 91 | -------------------------------------------------------------------------------- /web_frontend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "arrowParens": "always", 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /web_frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.15.0 2 | 3 | WORKDIR /app 4 | ADD . /app/ 5 | 6 | RUN npm i -g yarn --force 7 | 8 | RUN yarn install 9 | RUN yarn build 10 | 11 | CMD [ "yarn", "start" ] 12 | -------------------------------------------------------------------------------- /web_frontend/README.md: -------------------------------------------------------------------------------- 1 | # web frontend 2 | 3 | > Web Frontend for PLACEHOLDER_PROJECTNAME 4 | 5 | ## Build Setup 6 | * 7 | ``` bash 8 | # install dependencies 9 | $ yarn install 10 | 11 | # serve with hot reload at localhost:3000 12 | $ yarn dev 13 | 14 | # build for production and launch server 15 | $ yarn build 16 | $ yarn start 17 | 18 | # generate static project 19 | $ yarn generate 20 | ``` 21 | 22 | For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org). 23 | -------------------------------------------------------------------------------- /web_frontend/assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked). 8 | -------------------------------------------------------------------------------- /web_frontend/assets/css/tailwind.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss/base'; 2 | @import 'tailwindcss/components'; 3 | @import 'tailwindcss/utilities'; 4 | -------------------------------------------------------------------------------- /web_frontend/components/InfoCard/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 44 | -------------------------------------------------------------------------------- /web_frontend/components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | The components directory contains your Vue.js Components. 6 | 7 | _Nuxt.js doesn't supercharge these components._ 8 | -------------------------------------------------------------------------------- /web_frontend/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "~/*": ["./*"], 6 | "@/*": ["./*"], 7 | "~~/*": ["./*"], 8 | "@@/*": ["./*"] 9 | } 10 | }, 11 | "exclude": ["node_modules", ".nuxt", "dist"] 12 | } 13 | -------------------------------------------------------------------------------- /web_frontend/layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Application Layouts. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts). 8 | -------------------------------------------------------------------------------- /web_frontend/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 6 | 15 | -------------------------------------------------------------------------------- /web_frontend/middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your application middleware. 6 | Middleware let you define custom functions that can be run before rendering either a page or a group of pages. 7 | 8 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware). 9 | -------------------------------------------------------------------------------- /web_frontend/nuxt.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mode: 'universal', 3 | server: { 4 | port: 3000, 5 | host: '0.0.0.0' 6 | }, 7 | /* 8 | ** Headers of the page 9 | */ 10 | head() { 11 | return { 12 | title: 'PLACEHOLDER_PROJECTNAME', 13 | meta: [ 14 | { charset: 'utf-8' }, 15 | { 16 | name: 'viewport', 17 | content: 'width=device-width, initial-scale=1, maximum-scale=1' 18 | }, 19 | { 20 | hid: 'description', 21 | name: 'description', 22 | content: 'meta.description' 23 | } 24 | ], 25 | link: [ 26 | { rel: 'icon', type: 'image/x-icon', href: '/favicons/favicon.ico' }, 27 | { 28 | rel: 'shortcut icon', 29 | type: 'image/png', 30 | href: '/favicons/icon-192x192.png' 31 | }, 32 | 33 | { 34 | rel: 'shortcut icon', 35 | sizes: '192x192', 36 | href: '/favicons/android-icon-192x192.png' 37 | }, 38 | { 39 | rel: 'apple-touch-icon', 40 | href: '/favicons/apple-icon-180x180.png' 41 | }, 42 | { 43 | rel: 'stylesheet', 44 | href: 'https://use.typekit.net/oft7xcx.css' 45 | } 46 | ] 47 | } 48 | }, 49 | /* 50 | ** Customize the progress-bar color 51 | */ 52 | loading: { color: '#fff' }, 53 | /* 54 | ** Global CSS 55 | */ 56 | css: [], 57 | /* 58 | ** Plugins to load before mounting the App 59 | */ 60 | plugins: ['~/plugins/v-body-scroll-lock'], 61 | /* 62 | ** Nuxt.js dev-modules 63 | */ 64 | buildModules: [ 65 | // Doc: https://github.com/nuxt-community/eslint-module 66 | '@nuxtjs/eslint-module', 67 | // Doc: https://github.com/nuxt-community/nuxt-tailwindcss 68 | '@nuxtjs/tailwindcss' 69 | ], 70 | /* 71 | ** Nuxt.js modules 72 | */ 73 | modules: [ 74 | // Doc: https://axios.nuxtjs.org/usage 75 | '@nuxtjs/axios', 76 | '@nuxtjs/pwa', 77 | // Doc: https://github.com/nuxt-community/dotenv-module 78 | '@nuxtjs/dotenv', 79 | // Docs: https://github.com/nuxt-community/apollo-module 80 | '@nuxtjs/apollo', 81 | ['vue-scrollto/nuxt', { duration: 300 }] 82 | ], 83 | /* 84 | ** Axios module configuration 85 | ** See https://axios.nuxtjs.org/options 86 | */ 87 | axios: {}, 88 | /* 89 | ** Build configuration 90 | */ 91 | build: { 92 | /* 93 | ** You can extend webpack config here 94 | */ 95 | extend(config, ctx) {}, 96 | transpile: ['v-body-scroll-lock'] 97 | }, 98 | apollo: { 99 | // tokenName: 'yourApolloTokenName', // optional, default: apollo-token 100 | cookieAttributes: { 101 | /** 102 | * Define when the cookie will be removed. Value can be a Number 103 | * which will be interpreted as days from time of creation or a 104 | * Date instance. If omitted, the cookie becomes a session cookie. 105 | */ 106 | expires: 7, // optional, default: 7 (days) 107 | 108 | /** 109 | * Define the path where the cookie is available. Defaults to '/' 110 | */ 111 | // path: '/', // optional 112 | /** 113 | * Define the domain where the cookie is available. Defaults to 114 | * the domain of the page where the cookie was created. 115 | */ 116 | // domain: 'example.com', // optional 117 | 118 | /** 119 | * A Boolean indicating if the cookie transmission requires a 120 | * secure protocol (https). Defaults to false. 121 | */ 122 | secure: false 123 | }, 124 | includeNodeModules: true, // optional, default: false (this includes graphql-tag for node_modules folder) 125 | // authenticationType: 'Basic', // optional, default: 'Bearer' 126 | // (Optional) Default 'apollo' definition 127 | defaultOptions: { 128 | // See 'apollo' definition 129 | // For example: default query options 130 | $query: { 131 | loadingKey: 'loading', 132 | fetchPolicy: 'cache-and-network' 133 | } 134 | }, 135 | // optional 136 | watchLoading: '~/plugins/apollo-watch-loading-handler.js', 137 | // optional 138 | errorHandler: '~/plugins/apollo-error-handler.js', 139 | // required 140 | clientConfigs: { 141 | default: '~/plugins/default-apollo-config.js' 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /web_frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web_frontend", 3 | "version": "1.0.0", 4 | "description": "Web Frontend for PLACEHOLDER_PROJECTNAME", 5 | "author": "PLACEHOLDER_AUTHOR", 6 | "private": true, 7 | "scripts": { 8 | "dev": "nuxt", 9 | "build": "nuxt build", 10 | "start": "nuxt start", 11 | "generate": "nuxt generate", 12 | "lint": "eslint --ext .js,.vue --ignore-path .gitignore ." 13 | }, 14 | "lint-staged": { 15 | "*.{js,vue}": "eslint" 16 | }, 17 | "engines": { 18 | "node": ">=12.15" 19 | }, 20 | "husky": { 21 | "hooks": { 22 | "pre-commit": "lint-staged" 23 | } 24 | }, 25 | "dependencies": { 26 | "@nuxtjs/apollo": "4.0.0-rc19", 27 | "@nuxtjs/axios": "^5.3.6", 28 | "@nuxtjs/dotenv": "^1.4.0", 29 | "@nuxtjs/pwa": "^3.0.0-0", 30 | "graphql-tag": "2.10.1", 31 | "lodash": "4.17.15", 32 | "mobile-detect": "^1.4.4", 33 | "node-sass": "^4.13.1", 34 | "nuxt": "^2.0.0", 35 | "sass-loader": "^8.0.2", 36 | "v-body-scroll-lock": "^1.1.3", 37 | "vue-scrollto": "^2.17.1" 38 | }, 39 | "devDependencies": { 40 | "@nuxtjs/eslint-config": "^1.0.1", 41 | "@nuxtjs/eslint-module": "^1.0.0", 42 | "@nuxtjs/tailwindcss": "^1.0.0", 43 | "babel-eslint": "^10.0.1", 44 | "eslint": "^6.1.0", 45 | "eslint-config-prettier": "^4.1.0", 46 | "eslint-plugin-nuxt": ">=0.4.2", 47 | "eslint-plugin-prettier": "^3.0.1", 48 | "husky": "^2.6.0", 49 | "lint-staged": "^8.2.1", 50 | "prettier": "^1.16.4" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /web_frontend/pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the `*.vue` files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing). 7 | -------------------------------------------------------------------------------- /web_frontend/pages/entry/_id.vue: -------------------------------------------------------------------------------- 1 | 10 | 44 | -------------------------------------------------------------------------------- /web_frontend/pages/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 38 | -------------------------------------------------------------------------------- /web_frontend/plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains Javascript plugins that you want to run before mounting the root Vue.js application. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins). 8 | -------------------------------------------------------------------------------- /web_frontend/plugins/apollo-error-handler.js: -------------------------------------------------------------------------------- 1 | export default (error, nuxtContext) => { 2 | console.log(error) 3 | } 4 | -------------------------------------------------------------------------------- /web_frontend/plugins/apollo-watch-loading-handler.js: -------------------------------------------------------------------------------- 1 | let loading 2 | export default (isLoading, countModifier, nuxtContext) => { 3 | loading += countModifier 4 | console.log(loading) 5 | } 6 | -------------------------------------------------------------------------------- /web_frontend/plugins/default-apollo-config.js: -------------------------------------------------------------------------------- 1 | export default function(context) { 2 | let url = '' 3 | const isServer = process.server 4 | 5 | if (isServer) { 6 | url = 'http://cms:8000/' 7 | } else { 8 | url = 'http://localhost:8000/' 9 | } 10 | 11 | url = url + 'api/graphiql' 12 | return { 13 | httpEndpoint: url 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /web_frontend/plugins/v-body-scroll-lock.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VBodyScrollLock from 'v-body-scroll-lock' 3 | 4 | Vue.use(VBodyScrollLock) 5 | -------------------------------------------------------------------------------- /web_frontend/static/favicon/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/android-icon-144x144.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/android-icon-192x192.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/android-icon-36x36.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/android-icon-48x48.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/android-icon-72x72.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/android-icon-96x96.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-114x114.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-120x120.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-144x144.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-152x152.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-180x180.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-57x57.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-60x60.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-72x72.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-76x76.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon-precomposed.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/apple-icon.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /web_frontend/static/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/favicon.ico -------------------------------------------------------------------------------- /web_frontend/static/favicon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /web_frontend/static/favicon/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/ms-icon-144x144.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/ms-icon-150x150.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/ms-icon-310x310.png -------------------------------------------------------------------------------- /web_frontend/static/favicon/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devs-group/wagtail-nuxt/21966fe77c7b07750c7f0c09cb65fff77d2f05ce/web_frontend/static/favicon/ms-icon-70x70.png -------------------------------------------------------------------------------- /web_frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** TailwindCSS Configuration File 3 | ** 4 | ** Docs: https://tailwindcss.com/docs/configuration 5 | ** Default: https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js 6 | */ 7 | module.exports = { 8 | theme: { 9 | fontFamily: { 10 | monotalic: 'monotalic, sans-serif', 11 | moret: 'moret, serif', 12 | signo: 'signo sans-serif' 13 | }, 14 | extend: { 15 | colors: { 16 | 'custom-brown': '#886562', 17 | 'custom-gold': '#877646', 18 | 'custom-green': '#234F40', 19 | 'custom-green-bright': '#828536', 20 | 'custom-green-brightest': '#818564', 21 | 'custom-turquoise': '#20696b' 22 | }, 23 | letterSpacing: { 24 | '7-5': '7.5px' 25 | }, 26 | fontSize: { 27 | xxxs: '0.625rem', 28 | xxs: '0.6875rem', 29 | '1xl': '1.375rem', 30 | '5xl': '3.5rem' 31 | }, 32 | opacity: { 33 | '35': '.35' 34 | }, 35 | height: { 36 | '38': '9.5rem' 37 | }, 38 | spacing: { 39 | 14: '3.5rem' 40 | }, 41 | maxWidth: { 42 | half: '50%' 43 | } 44 | } 45 | }, 46 | variants: {}, 47 | plugins: [] 48 | } 49 | --------------------------------------------------------------------------------