
29 changed files with 923 additions and 0 deletions
@ -0,0 +1,39 @@ |
|||||
|
# Django project |
||||
|
/media/ |
||||
|
/static/ |
||||
|
*.sqlite3 |
||||
|
|
||||
|
# Python and others |
||||
|
__pycache__ |
||||
|
*.pyc |
||||
|
.DS_Store |
||||
|
*.swp |
||||
|
/venv/ |
||||
|
/tmp/ |
||||
|
/.vagrant/ |
||||
|
/Vagrantfile.local |
||||
|
node_modules/ |
||||
|
/npm-debug.log |
||||
|
/.idea/ |
||||
|
.vscode |
||||
|
coverage |
||||
|
.python-version |
||||
|
|
||||
|
# Distribution / packaging |
||||
|
.Python |
||||
|
env/ |
||||
|
build/ |
||||
|
develop-eggs/ |
||||
|
dist/ |
||||
|
downloads/ |
||||
|
eggs/ |
||||
|
.eggs/ |
||||
|
lib/ |
||||
|
lib64/ |
||||
|
parts/ |
||||
|
sdist/ |
||||
|
var/ |
||||
|
wheels/ |
||||
|
*.egg-info/ |
||||
|
.installed.cfg |
||||
|
*.egg |
@ -0,0 +1,60 @@ |
|||||
|
# Use an official Python runtime based on Debian 10 "buster" as a parent image. |
||||
|
FROM python:3.8.1-slim-buster |
||||
|
|
||||
|
# Add user that will be used in the container. |
||||
|
RUN useradd wagtail |
||||
|
|
||||
|
# Port used by this container to serve HTTP. |
||||
|
EXPOSE 8000 |
||||
|
|
||||
|
# Set environment variables. |
||||
|
# 1. Force Python stdout and stderr streams to be unbuffered. |
||||
|
# 2. Set PORT variable that is used by Gunicorn. This should match "EXPOSE" |
||||
|
# command. |
||||
|
ENV PYTHONUNBUFFERED=1 \ |
||||
|
PORT=8000 |
||||
|
|
||||
|
# Install system packages required by Wagtail and Django. |
||||
|
RUN apt-get update --yes --quiet && apt-get install --yes --quiet --no-install-recommends \ |
||||
|
build-essential \ |
||||
|
libpq-dev \ |
||||
|
libmariadbclient-dev \ |
||||
|
libjpeg62-turbo-dev \ |
||||
|
zlib1g-dev \ |
||||
|
libwebp-dev \ |
||||
|
&& rm -rf /var/lib/apt/lists/* |
||||
|
|
||||
|
# Install the application server. |
||||
|
RUN pip install "gunicorn==20.0.4" |
||||
|
|
||||
|
# Install the project requirements. |
||||
|
COPY requirements.txt / |
||||
|
RUN pip install -r /requirements.txt |
||||
|
|
||||
|
# Use /app folder as a directory where the source code is stored. |
||||
|
WORKDIR /app |
||||
|
|
||||
|
# Set this directory to be owned by the "wagtail" user. This Wagtail project |
||||
|
# uses SQLite, the folder needs to be owned by the user that |
||||
|
# will be writing to the database file. |
||||
|
RUN chown wagtail:wagtail /app |
||||
|
|
||||
|
# Copy the source code of the project into the container. |
||||
|
COPY --chown=wagtail:wagtail . . |
||||
|
|
||||
|
# Use user "wagtail" to run the build commands below and the server itself. |
||||
|
USER wagtail |
||||
|
|
||||
|
# Collect static files. |
||||
|
RUN python manage.py collectstatic --noinput --clear |
||||
|
|
||||
|
# Runtime command that executes when "docker run" is called, it does the |
||||
|
# following: |
||||
|
# 1. Migrate the database. |
||||
|
# 2. Start the application server. |
||||
|
# WARNING: |
||||
|
# Migrating database at the same time as starting the server IS NOT THE BEST |
||||
|
# PRACTICE. The database should be migrated manually or using the release |
||||
|
# phase facilities of your hosting platform. This is used only so the |
||||
|
# Wagtail instance can be started with a simple "docker run" command. |
||||
|
CMD set -xe; python manage.py migrate --noinput; gunicorn hvezdarna.wsgi:application |
@ -0,0 +1,11 @@ |
|||||
|
[[source]] |
||||
|
name = "pypi" |
||||
|
url = "https://pypi.org/simple" |
||||
|
verify_ssl = true |
||||
|
|
||||
|
[dev-packages] |
||||
|
|
||||
|
[packages] |
||||
|
|
||||
|
[requires] |
||||
|
python_version = "3.8" |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('wagtailcore', '0040_page_draft_title'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name='HomePage', |
||||
|
fields=[ |
||||
|
('page_ptr', models.OneToOneField(on_delete=models.CASCADE, parent_link=True, auto_created=True, primary_key=True, serialize=False, to='wagtailcore.Page')), |
||||
|
], |
||||
|
options={ |
||||
|
'abstract': False, |
||||
|
}, |
||||
|
bases=('wagtailcore.page',), |
||||
|
), |
||||
|
] |
@ -0,0 +1,62 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
def create_homepage(apps, schema_editor): |
||||
|
# Get models |
||||
|
ContentType = apps.get_model('contenttypes.ContentType') |
||||
|
Page = apps.get_model('wagtailcore.Page') |
||||
|
Site = apps.get_model('wagtailcore.Site') |
||||
|
HomePage = apps.get_model('home.HomePage') |
||||
|
|
||||
|
# Delete the default homepage |
||||
|
# If migration is run multiple times, it may have already been deleted |
||||
|
Page.objects.filter(id=2).delete() |
||||
|
|
||||
|
# Create content type for homepage model |
||||
|
homepage_content_type, __ = ContentType.objects.get_or_create( |
||||
|
model='homepage', app_label='home') |
||||
|
|
||||
|
# Create a new homepage |
||||
|
homepage = HomePage.objects.create( |
||||
|
title="Home", |
||||
|
draft_title="Home", |
||||
|
slug='home', |
||||
|
content_type=homepage_content_type, |
||||
|
path='00010001', |
||||
|
depth=2, |
||||
|
numchild=0, |
||||
|
url_path='/home/', |
||||
|
) |
||||
|
|
||||
|
# Create a site with the new homepage set as the root |
||||
|
Site.objects.create( |
||||
|
hostname='localhost', root_page=homepage, is_default_site=True) |
||||
|
|
||||
|
|
||||
|
def remove_homepage(apps, schema_editor): |
||||
|
# Get models |
||||
|
ContentType = apps.get_model('contenttypes.ContentType') |
||||
|
HomePage = apps.get_model('home.HomePage') |
||||
|
|
||||
|
# Delete the default homepage |
||||
|
# Page and Site objects CASCADE |
||||
|
HomePage.objects.filter(slug='home', depth=2).delete() |
||||
|
|
||||
|
# Delete content type for homepage model |
||||
|
ContentType.objects.filter(model='homepage', app_label='home').delete() |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
run_before = [ |
||||
|
('wagtailcore', '0053_locale_model'), |
||||
|
] |
||||
|
|
||||
|
dependencies = [ |
||||
|
('home', '0001_initial'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RunPython(create_homepage, remove_homepage), |
||||
|
] |
@ -0,0 +1,56 @@ |
|||||
|
# Generated by Django 3.1.7 on 2021-03-17 05:55 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
import modelcluster.fields |
||||
|
import wagtail.core.fields |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('wagtailimages', '0023_add_choose_permissions'), |
||||
|
('home', '0002_create_homepage'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='homepage', |
||||
|
name='address', |
||||
|
field=models.CharField(blank=True, default='', max_length=255, verbose_name='Adresa'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='homepage', |
||||
|
name='body', |
||||
|
field=wagtail.core.fields.RichTextField(blank=True), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='homepage', |
||||
|
name='email', |
||||
|
field=models.EmailField(blank=True, max_length=64, null=True, verbose_name='E-mail'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='homepage', |
||||
|
name='map_link', |
||||
|
field=models.URLField(blank=True, default='', max_length=128, verbose_name='Odkaz na mapu'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='homepage', |
||||
|
name='mobile', |
||||
|
field=models.CharField(blank=True, default='', max_length=24, verbose_name='Mobil'), |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name='CarouselImage', |
||||
|
fields=[ |
||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('sort_order', models.IntegerField(blank=True, editable=False, null=True)), |
||||
|
('caption', models.CharField(blank=True, max_length=250)), |
||||
|
('image', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailimages.image')), |
||||
|
('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='carousel_images', to='home.homepage')), |
||||
|
], |
||||
|
options={ |
||||
|
'ordering': ['sort_order'], |
||||
|
'abstract': False, |
||||
|
}, |
||||
|
), |
||||
|
] |
@ -0,0 +1,41 @@ |
|||||
|
from django.db import models |
||||
|
|
||||
|
from modelcluster.fields import ParentalKey |
||||
|
|
||||
|
from wagtail.core.models import Page, Orderable |
||||
|
from wagtail.core.fields import RichTextField |
||||
|
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel |
||||
|
from wagtail.images.edit_handlers import ImageChooserPanel |
||||
|
from wagtail.search import index |
||||
|
|
||||
|
|
||||
|
class HomePage(Page): |
||||
|
body = RichTextField(blank=True) |
||||
|
address = models.CharField(max_length=255, verbose_name="Adresa", blank=True, default='') |
||||
|
mobile = models.CharField(max_length=24, verbose_name="Mobil", blank=True, default='') |
||||
|
email = models.EmailField(max_length=64, verbose_name="E-mail", blank=True, null=True) |
||||
|
map_link = models.URLField(max_length=128, verbose_name="Odkaz na mapu", blank=True, default='') |
||||
|
|
||||
|
content_panels = Page.content_panels + [ |
||||
|
FieldPanel('body', classname="full"), |
||||
|
FieldPanel('address'), |
||||
|
FieldPanel('mobile'), |
||||
|
FieldPanel('email'), |
||||
|
FieldPanel('map_link'), |
||||
|
InlinePanel('carousel_images', label="Obrázky"), |
||||
|
] |
||||
|
|
||||
|
search_fields = Page.search_fields + [ |
||||
|
index.SearchField('body'), |
||||
|
] |
||||
|
|
||||
|
|
||||
|
class CarouselImage(Orderable): |
||||
|
page = ParentalKey(HomePage, on_delete=models.CASCADE, related_name='carousel_images') |
||||
|
image = models.ForeignKey('wagtailimages.Image', on_delete=models.CASCADE, related_name='+') |
||||
|
caption = models.CharField(blank=True, max_length=250) |
||||
|
|
||||
|
panels = [ |
||||
|
ImageChooserPanel('image'), |
||||
|
FieldPanel('caption'), |
||||
|
] |
@ -0,0 +1,204 @@ |
|||||
|
html { |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
*, |
||||
|
*:before, |
||||
|
*:after { |
||||
|
box-sizing: inherit; |
||||
|
} |
||||
|
|
||||
|
body { |
||||
|
max-width: 960px; |
||||
|
min-height: 100vh; |
||||
|
margin: 0 auto; |
||||
|
padding: 0 15px; |
||||
|
color: #231f20; |
||||
|
font-family: 'Helvetica Neue', 'Segoe UI', Arial, sans-serif; |
||||
|
line-height: 1.25; |
||||
|
} |
||||
|
|
||||
|
a { |
||||
|
background-color: transparent; |
||||
|
color: #308282; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
|
||||
|
a:hover { |
||||
|
color: #ea1b10; |
||||
|
} |
||||
|
|
||||
|
h1, |
||||
|
h2, |
||||
|
h3, |
||||
|
h4, |
||||
|
h5, |
||||
|
p, |
||||
|
ul { |
||||
|
padding: 0; |
||||
|
margin: 0; |
||||
|
font-weight: 400; |
||||
|
} |
||||
|
|
||||
|
main { |
||||
|
display: block; /* For IE11 support */ |
||||
|
} |
||||
|
|
||||
|
svg:not(:root) { |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding-top: 20px; |
||||
|
padding-bottom: 10px; |
||||
|
border-bottom: 1px solid #e6e6e6; |
||||
|
} |
||||
|
|
||||
|
.logo { |
||||
|
width: 150px; |
||||
|
margin-right: 20px; |
||||
|
} |
||||
|
|
||||
|
.logo a { |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
.figure-logo { |
||||
|
max-width: 150px; |
||||
|
max-height: 55.1px; |
||||
|
} |
||||
|
|
||||
|
.release-notes { |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
.main { |
||||
|
padding: 40px 0; |
||||
|
margin: 0 auto; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.figure-space { |
||||
|
max-width: 265px; |
||||
|
} |
||||
|
|
||||
|
@-webkit-keyframes pos { |
||||
|
0%, 100% { |
||||
|
-webkit-transform: rotate(-6deg); |
||||
|
transform: rotate(-6deg); |
||||
|
} |
||||
|
50% { |
||||
|
-webkit-transform: rotate(6deg); |
||||
|
transform: rotate(6deg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@keyframes pos { |
||||
|
0%, 100% { |
||||
|
-webkit-transform: rotate(-6deg); |
||||
|
transform: rotate(-6deg); |
||||
|
} |
||||
|
50% { |
||||
|
-webkit-transform: rotate(6deg); |
||||
|
transform: rotate(6deg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.egg { |
||||
|
fill: #43b1b0; |
||||
|
-webkit-animation: pos 3s ease infinite; |
||||
|
animation: pos 3s ease infinite; |
||||
|
-webkit-transform: translateY(50px); |
||||
|
transform: translateY(50px); |
||||
|
-webkit-transform-origin: 50% 80%; |
||||
|
transform-origin: 50% 80%; |
||||
|
} |
||||
|
|
||||
|
.main-text { |
||||
|
max-width: 400px; |
||||
|
margin: 5px auto; |
||||
|
} |
||||
|
|
||||
|
.main-text h1 { |
||||
|
font-size: 22px; |
||||
|
} |
||||
|
|
||||
|
.main-text p { |
||||
|
margin: 15px auto 0; |
||||
|
} |
||||
|
|
||||
|
.footer { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
justify-content: space-between; |
||||
|
border-top: 1px solid #e6e6e6; |
||||
|
padding: 10px; |
||||
|
} |
||||
|
|
||||
|
.option { |
||||
|
display: block; |
||||
|
padding: 10px 10px 10px 34px; |
||||
|
position: relative; |
||||
|
text-decoration: none; |
||||
|
} |
||||
|
|
||||
|
.option svg { |
||||
|
width: 24px; |
||||
|
height: 24px; |
||||
|
fill: gray; |
||||
|
border: 1px solid #d9d9d9; |
||||
|
padding: 5px; |
||||
|
border-radius: 100%; |
||||
|
top: 10px; |
||||
|
left: 0; |
||||
|
position: absolute; |
||||
|
} |
||||
|
|
||||
|
.option h4 { |
||||
|
font-size: 19px; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
|
||||
|
.option p { |
||||
|
padding-top: 3px; |
||||
|
color: #231f20; |
||||
|
font-size: 15px; |
||||
|
font-weight: 300; |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 996px) { |
||||
|
body { |
||||
|
max-width: 780px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 767px) { |
||||
|
.option { |
||||
|
flex: 0 0 50%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 599px) { |
||||
|
.main { |
||||
|
padding: 20px 0; |
||||
|
} |
||||
|
|
||||
|
.figure-space { |
||||
|
max-width: 200px; |
||||
|
} |
||||
|
|
||||
|
.footer { |
||||
|
display: block; |
||||
|
width: 300px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 360px) { |
||||
|
.header-link { |
||||
|
max-width: 100px; |
||||
|
} |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load static %} |
||||
|
|
||||
|
{% block body_class %}template-homepage{% endblock %} |
||||
|
|
||||
|
{% block extra_css %} |
||||
|
|
||||
|
{% endblock extra_css %} |
||||
|
|
||||
|
{% block content %} |
||||
|
|
||||
|
|
||||
|
|
||||
|
{% endblock content %} |
@ -0,0 +1,162 @@ |
|||||
|
""" |
||||
|
Django settings for hvezdarna project. |
||||
|
|
||||
|
Generated by 'django-admin startproject' using Django 3.1.7. |
||||
|
|
||||
|
For more information on this file, see |
||||
|
https://docs.djangoproject.com/en/3.1/topics/settings/ |
||||
|
|
||||
|
For the full list of settings and their values, see |
||||
|
https://docs.djangoproject.com/en/3.1/ref/settings/ |
||||
|
""" |
||||
|
|
||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) |
||||
|
import os |
||||
|
|
||||
|
PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
||||
|
BASE_DIR = os.path.dirname(PROJECT_DIR) |
||||
|
|
||||
|
|
||||
|
# Quick-start development settings - unsuitable for production |
||||
|
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ |
||||
|
|
||||
|
|
||||
|
# Application definition |
||||
|
|
||||
|
INSTALLED_APPS = [ |
||||
|
'home', |
||||
|
'search', |
||||
|
|
||||
|
'wagtail.contrib.forms', |
||||
|
'wagtail.contrib.redirects', |
||||
|
'wagtail.embeds', |
||||
|
'wagtail.sites', |
||||
|
'wagtail.users', |
||||
|
'wagtail.snippets', |
||||
|
'wagtail.documents', |
||||
|
'wagtail.images', |
||||
|
'wagtail.search', |
||||
|
'wagtail.admin', |
||||
|
'wagtail.core', |
||||
|
|
||||
|
'modelcluster', |
||||
|
'taggit', |
||||
|
|
||||
|
'django.contrib.admin', |
||||
|
'django.contrib.auth', |
||||
|
'django.contrib.contenttypes', |
||||
|
'django.contrib.sessions', |
||||
|
'django.contrib.messages', |
||||
|
'django.contrib.staticfiles', |
||||
|
] |
||||
|
|
||||
|
MIDDLEWARE = [ |
||||
|
'django.contrib.sessions.middleware.SessionMiddleware', |
||||
|
'django.middleware.common.CommonMiddleware', |
||||
|
'django.middleware.csrf.CsrfViewMiddleware', |
||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware', |
||||
|
'django.contrib.messages.middleware.MessageMiddleware', |
||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware', |
||||
|
'django.middleware.security.SecurityMiddleware', |
||||
|
|
||||
|
'wagtail.contrib.redirects.middleware.RedirectMiddleware', |
||||
|
] |
||||
|
|
||||
|
ROOT_URLCONF = 'hvezdarna.urls' |
||||
|
|
||||
|
TEMPLATES = [ |
||||
|
{ |
||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates', |
||||
|
'DIRS': [ |
||||
|
os.path.join(PROJECT_DIR, 'templates'), |
||||
|
], |
||||
|
'APP_DIRS': True, |
||||
|
'OPTIONS': { |
||||
|
'context_processors': [ |
||||
|
'django.template.context_processors.debug', |
||||
|
'django.template.context_processors.request', |
||||
|
'django.contrib.auth.context_processors.auth', |
||||
|
'django.contrib.messages.context_processors.messages', |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
WSGI_APPLICATION = 'hvezdarna.wsgi.application' |
||||
|
|
||||
|
|
||||
|
# Database |
||||
|
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases |
||||
|
|
||||
|
DATABASES = { |
||||
|
'default': { |
||||
|
'ENGINE': 'django.db.backends.sqlite3', |
||||
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
# Password validation |
||||
|
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators |
||||
|
|
||||
|
AUTH_PASSWORD_VALIDATORS = [ |
||||
|
{ |
||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', |
||||
|
}, |
||||
|
{ |
||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', |
||||
|
}, |
||||
|
{ |
||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', |
||||
|
}, |
||||
|
{ |
||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
|
||||
|
# Internationalization |
||||
|
# https://docs.djangoproject.com/en/3.1/topics/i18n/ |
||||
|
|
||||
|
LANGUAGE_CODE = 'en-us' |
||||
|
|
||||
|
TIME_ZONE = 'UTC' |
||||
|
|
||||
|
USE_I18N = True |
||||
|
|
||||
|
USE_L10N = True |
||||
|
|
||||
|
USE_TZ = True |
||||
|
|
||||
|
|
||||
|
# Static files (CSS, JavaScript, Images) |
||||
|
# https://docs.djangoproject.com/en/3.1/howto/static-files/ |
||||
|
|
||||
|
STATICFILES_FINDERS = [ |
||||
|
'django.contrib.staticfiles.finders.FileSystemFinder', |
||||
|
'django.contrib.staticfiles.finders.AppDirectoriesFinder', |
||||
|
] |
||||
|
|
||||
|
STATICFILES_DIRS = [ |
||||
|
os.path.join(PROJECT_DIR, 'static'), |
||||
|
] |
||||
|
|
||||
|
# ManifestStaticFilesStorage is recommended in production, to prevent outdated |
||||
|
# JavaScript / CSS assets being served from cache (e.g. after a Wagtail upgrade). |
||||
|
# See https://docs.djangoproject.com/en/3.1/ref/contrib/staticfiles/#manifeststaticfilesstorage |
||||
|
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' |
||||
|
|
||||
|
STATIC_ROOT = os.path.join(BASE_DIR, 'static') |
||||
|
STATIC_URL = '/static/' |
||||
|
|
||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') |
||||
|
MEDIA_URL = '/media/' |
||||
|
|
||||
|
|
||||
|
# Wagtail settings |
||||
|
|
||||
|
WAGTAIL_SITE_NAME = "hvezdarna" |
||||
|
|
||||
|
# Base URL to use when referring to full URLs within the Wagtail admin backend - |
||||
|
# e.g. in notification emails. Don't include '/admin' or a trailing slash |
||||
|
BASE_URL = 'http://example.com' |
@ -0,0 +1,18 @@ |
|||||
|
from .base import * |
||||
|
|
||||
|
# SECURITY WARNING: don't run with debug turned on in production! |
||||
|
DEBUG = True |
||||
|
|
||||
|
# SECURITY WARNING: keep the secret key used in production secret! |
||||
|
SECRET_KEY = 'ec1zzak-x$@r3(03&$#+up6u7pg-e0ybp%dl*j3il%s_c_x_ql' |
||||
|
|
||||
|
# SECURITY WARNING: define the correct hosts in production! |
||||
|
ALLOWED_HOSTS = ['*'] |
||||
|
|
||||
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' |
||||
|
|
||||
|
|
||||
|
try: |
||||
|
from .local import * |
||||
|
except ImportError: |
||||
|
pass |
@ -0,0 +1,8 @@ |
|||||
|
from .base import * |
||||
|
|
||||
|
DEBUG = False |
||||
|
|
||||
|
try: |
||||
|
from .local import * |
||||
|
except ImportError: |
||||
|
pass |
@ -0,0 +1,9 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
|
||||
|
{% block body_class %}template-404{% endblock %} |
||||
|
|
||||
|
{% block content %} |
||||
|
<h1>Page not found</h1> |
||||
|
|
||||
|
<h2>Sorry, this page could not be found.</h2> |
||||
|
{% endblock %} |
@ -0,0 +1,13 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html class="no-js"> |
||||
|
<head> |
||||
|
<meta charset="utf-8" /> |
||||
|
<title>Internal server error</title> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
||||
|
</head> |
||||
|
<body> |
||||
|
<h1>Internal server error</h1> |
||||
|
|
||||
|
<h2>Sorry, there seems to be an error. Please try again soon.</h2> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,65 @@ |
|||||
|
{% load static wagtailuserbar %} |
||||
|
|
||||
|
<!DOCTYPE html> |
||||
|
<html class="no-js" lang="en"> |
||||
|
<head> |
||||
|
<meta charset="utf-8" /> |
||||
|
<title> |
||||
|
{% block title %} |
||||
|
{% if self.seo_title %}{{ self.seo_title }}{% else %}{{ self.title }}{% endif %} |
||||
|
{% endblock %} |
||||
|
{% block title_suffix %} |
||||
|
{% with self.get_site.site_name as site_name %} |
||||
|
{% if site_name %}- {{ site_name }}{% endif %} |
||||
|
{% endwith %} |
||||
|
{% endblock %} |
||||
|
</title> |
||||
|
<meta name="description" content="" /> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
||||
|
|
||||
|
{# Global stylesheets #} |
||||
|
{#<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">#} |
||||
|
<link rel="stylesheet" type="text/css" href="{% static 'css/hvezdarna.css' %}"> |
||||
|
|
||||
|
{% block extra_css %} |
||||
|
{# Override this in templates to add extra stylesheets #} |
||||
|
{% endblock %} |
||||
|
</head> |
||||
|
|
||||
|
<body class="{% block body_class %}{% endblock %}"> |
||||
|
{% wagtailuserbar %} |
||||
|
|
||||
|
<div class="container-fluid"> |
||||
|
<nav class="navbar navbar-expand-lg p-4 d-block d-md-flex"> |
||||
|
<a href="/" class="navbar-brand d-block text-center d-md-inline"> |
||||
|
LOGO |
||||
|
</a> |
||||
|
|
||||
|
<ul class="navbar-nav nav-info-text"> |
||||
|
<li class="nav-item"> |
||||
|
<a href="mailto:{{ page.email }}">{{ page.email }}</a> |
||||
|
</li> |
||||
|
<li class="nav-item">|</li> |
||||
|
<li class="nav-item"> |
||||
|
<a href="mailto:{{ page.address }}">{{ page.address }}</a> |
||||
|
</li> |
||||
|
<li class="nav-item">|</li> |
||||
|
<li class="nav-item"> |
||||
|
<a href="mailto:{{ page.mobile }}">{{ page.mobile }}</a> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</nav> |
||||
|
<hr> |
||||
|
</div> |
||||
|
|
||||
|
{% block content %}{% endblock %} |
||||
|
|
||||
|
{# Global javascript #} |
||||
|
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> |
||||
|
<script type="text/javascript" src="{% static 'js/hvezdarna.js' %}"></script> |
||||
|
|
||||
|
{% block extra_js %} |
||||
|
{# Override this in templates to add extra javascript #} |
||||
|
{% endblock %} |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,39 @@ |
|||||
|
from django.conf import settings |
||||
|
from django.urls import include, path |
||||
|
from django.contrib import admin |
||||
|
|
||||
|
from wagtail.admin import urls as wagtailadmin_urls |
||||
|
from wagtail.core import urls as wagtail_urls |
||||
|
from wagtail.documents import urls as wagtaildocs_urls |
||||
|
|
||||
|
from search import views as search_views |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
path('django-admin/', admin.site.urls), |
||||
|
|
||||
|
path('admin/', include(wagtailadmin_urls)), |
||||
|
path('documents/', include(wagtaildocs_urls)), |
||||
|
|
||||
|
path('search/', search_views.search, name='search'), |
||||
|
|
||||
|
] |
||||
|
|
||||
|
|
||||
|
if settings.DEBUG: |
||||
|
from django.conf.urls.static import static |
||||
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns |
||||
|
|
||||
|
# Serve static and media files from development server |
||||
|
urlpatterns += staticfiles_urlpatterns() |
||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) |
||||
|
|
||||
|
urlpatterns = urlpatterns + [ |
||||
|
# For anything not caught by a more specific rule above, hand over to |
||||
|
# Wagtail's page serving mechanism. This should be the last pattern in |
||||
|
# the list: |
||||
|
path("", include(wagtail_urls)), |
||||
|
|
||||
|
# Alternatively, if you want Wagtail pages to be served from a subpath |
||||
|
# of your site, rather than the site root: |
||||
|
# path("pages/", include(wagtail_urls)), |
||||
|
] |
@ -0,0 +1,16 @@ |
|||||
|
""" |
||||
|
WSGI config for hvezdarna project. |
||||
|
|
||||
|
It exposes the WSGI callable as a module-level variable named ``application``. |
||||
|
|
||||
|
For more information on this file, see |
||||
|
https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ |
||||
|
""" |
||||
|
|
||||
|
import os |
||||
|
|
||||
|
from django.core.wsgi import get_wsgi_application |
||||
|
|
||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hvezdarna.settings.dev") |
||||
|
|
||||
|
application = get_wsgi_application() |
@ -0,0 +1,10 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
import os |
||||
|
import sys |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hvezdarna.settings.dev") |
||||
|
|
||||
|
from django.core.management import execute_from_command_line |
||||
|
|
||||
|
execute_from_command_line(sys.argv) |
@ -0,0 +1,2 @@ |
|||||
|
Django>=3.1,<3.2 |
||||
|
wagtail>=2.12,<2.13 |
@ -0,0 +1,38 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load static wagtailcore_tags %} |
||||
|
|
||||
|
{% block body_class %}template-searchresults{% endblock %} |
||||
|
|
||||
|
{% block title %}Search{% endblock %} |
||||
|
|
||||
|
{% block content %} |
||||
|
<h1>Search</h1> |
||||
|
|
||||
|
<form action="{% url 'search' %}" method="get"> |
||||
|
<input type="text" name="query"{% if search_query %} value="{{ search_query }}"{% endif %}> |
||||
|
<input type="submit" value="Search" class="button"> |
||||
|
</form> |
||||
|
|
||||
|
{% if search_results %} |
||||
|
<ul> |
||||
|
{% for result in search_results %} |
||||
|
<li> |
||||
|
<h4><a href="{% pageurl result %}">{{ result }}</a></h4> |
||||
|
{% if result.search_description %} |
||||
|
{{ result.search_description }} |
||||
|
{% endif %} |
||||
|
</li> |
||||
|
{% endfor %} |
||||
|
</ul> |
||||
|
|
||||
|
{% if search_results.has_previous %} |
||||
|
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.previous_page_number }}">Previous</a> |
||||
|
{% endif %} |
||||
|
|
||||
|
{% if search_results.has_next %} |
||||
|
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.next_page_number }}">Next</a> |
||||
|
{% endif %} |
||||
|
{% elif search_query %} |
||||
|
No results found |
||||
|
{% endif %} |
||||
|
{% endblock %} |
@ -0,0 +1,34 @@ |
|||||
|
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator |
||||
|
from django.template.response import TemplateResponse |
||||
|
|
||||
|
from wagtail.core.models import Page |
||||
|
from wagtail.search.models import Query |
||||
|
|
||||
|
|
||||
|
def search(request): |
||||
|
search_query = request.GET.get('query', None) |
||||
|
page = request.GET.get('page', 1) |
||||
|
|
||||
|
# Search |
||||
|
if search_query: |
||||
|
search_results = Page.objects.live().search(search_query) |
||||
|
query = Query.get(search_query) |
||||
|
|
||||
|
# Record hit |
||||
|
query.add_hit() |
||||
|
else: |
||||
|
search_results = Page.objects.none() |
||||
|
|
||||
|
# Pagination |
||||
|
paginator = Paginator(search_results, 10) |
||||
|
try: |
||||
|
search_results = paginator.page(page) |
||||
|
except PageNotAnInteger: |
||||
|
search_results = paginator.page(1) |
||||
|
except EmptyPage: |
||||
|
search_results = paginator.page(paginator.num_pages) |
||||
|
|
||||
|
return TemplateResponse(request, 'search/search.html', { |
||||
|
'search_query': search_query, |
||||
|
'search_results': search_results, |
||||
|
}) |
Loading…
Reference in new issue