Skip to content

Commit

Permalink
core: create image carousel on front page
Browse files Browse the repository at this point in the history
  • Loading branch information
japsu committed Jul 22, 2017
1 parent 1692672 commit 745c5df
Show file tree
Hide file tree
Showing 16 changed files with 182 additions and 33 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -18,3 +18,4 @@ rev-manifest.json
tmp/
virtualenv/
.DS_Store
media/
2 changes: 1 addition & 1 deletion Dockerfile
@@ -1,7 +1,7 @@
FROM python:3.6
WORKDIR /usr/src/app
COPY requirements.txt requirements-production.txt /usr/src/app/
RUN groupadd -r kompassi && useradd -r -g kompassi kompassi && \
RUN groupadd -g 998 -r kompassi && useradd -r -g kompassi -u 998 kompassi && \
pip install -U pip setuptools wheel && \
pip install --no-cache-dir -r requirements.txt -r requirements-production.txt
COPY . /usr/src/app
Expand Down
3 changes: 2 additions & 1 deletion core/admin.py
Expand Up @@ -6,7 +6,7 @@
from django.contrib.auth.admin import GroupAdmin
from django.contrib.auth.models import User, Group

from .models import Organization, Event, Person, Venue
from .models import Organization, Event, Person, Venue, CarouselSlide


organization_admin_inlines = []
Expand Down Expand Up @@ -154,6 +154,7 @@ def get_form(self, request, obj=None, **kwargs):
admin.site.register(Event, EventAdmin)
admin.site.register(Person, PersonAdmin)
admin.site.register(Venue)
admin.site.register(CarouselSlide)


# override GroupAdmin for users of group support in admin
Expand Down
4 changes: 4 additions & 0 deletions core/locale/fi/LC_MESSAGES/django.po
Expand Up @@ -306,3 +306,7 @@ msgstr "Kyllä"
#: templates/core_contact_information_panel.jade
msgid "Please check your contact information and update your profile if necessary. By submitting this form you agree that this contact information will be shared with the organizer of the event."
msgstr "Ole hyvä ja tarkista yhteystietosi ja korjaa ne tarvittaessa profiiliisi. Täyttämällä tämän lomakkeen annat luvan luovuttaa nämä yhteystiedot tapahtuman järjestäjille."

#:
msgid "Picture:"
msgstr "Kuva:"
28 changes: 28 additions & 0 deletions core/migrations/0024_carouselslide.py
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-07-22 16:13
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0023_auto_20160704_2155'),
]

operations = [
migrations.CreateModel(
name='CarouselSlide',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('active_from', models.DateTimeField(blank=True, null=True)),
('active_until', models.DateTimeField(blank=True, null=True)),
('href', models.CharField(blank=True, default='', max_length=512)),
('title', models.CharField(blank=True, default='', max_length=512)),
('image_file', models.FileField(blank=True, upload_to='carousel_slides')),
('image_credit', models.CharField(blank=True, default='', max_length=512)),
('target', models.CharField(choices=[('', 'Same window'), ('_blank', 'New window')], default='', max_length=6)),
],
),
]
15 changes: 9 additions & 6 deletions core/models/__init__.py
@@ -1,4 +1,5 @@
# encoding: utf-8
# flake8: noqa

from .constants import (
EMAIL_LENGTH,
Expand All @@ -7,13 +8,15 @@
NAME_DISPLAY_STYLE_CHOICES,
NAME_DISPLAY_STYLE_FORMATS,
)
from .organization import Organization
from .venue import Venue

from .carousel_slide import CarouselSlide
from .contact_email_mixin import contact_email_validator, ContactEmailMixin
from .email_verification_token import EmailVerificationToken, EmailVerificationError
from .event import Event
from .group_management_mixin import GroupManagementMixin
from .event_meta_base import EventMetaBase
from .person import Person, birth_date_validator
from .group_management_mixin import GroupManagementMixin
from .one_time_code import OneTimeCodeMixin, OneTimeCode, OneTimeCodeLite
from .organization import Organization
from .password_reset_token import PasswordResetToken, PasswordResetError
from .email_verification_token import EmailVerificationToken, EmailVerificationError
from .contact_email_mixin import contact_email_validator, ContactEmailMixin
from .person import Person, birth_date_validator
from .venue import Venue
31 changes: 31 additions & 0 deletions core/models/carousel_slide.py
@@ -0,0 +1,31 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _

from core.utils import get_objects_within_period


TARGET_CHOICES = [
('', _('Same window')),
('_blank', _('New window')),
]


class CarouselSlide(models.Model):
active_from = models.DateTimeField(blank=True, null=True)
active_until = models.DateTimeField(blank=True, null=True)
href = models.CharField(max_length=512, blank=True, default='')
title = models.CharField(max_length=512, blank=True, default='')
image_file = models.FileField(upload_to='carousel_slides', blank=True)
image_credit = models.CharField(max_length=512, blank=True, default='')
target = models.CharField(
choices=TARGET_CHOICES,
max_length=max(len(key) for (key, label) in TARGET_CHOICES),
default=TARGET_CHOICES[0][0],
)

@classmethod
def get_active_slides(cls, t=None, **extra_criteria):
return get_objects_within_period(cls, t=t, **extra_criteria)

def __str__(self):
return self.title
2 changes: 1 addition & 1 deletion core/static/kompassi.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/static/kompassi.css.map

Large diffs are not rendered by default.

43 changes: 39 additions & 4 deletions core/static_src/less/kompassi.less
@@ -1,15 +1,30 @@
@inputBorderRadius: 2px;

@import "bootstrap/bootstrap";
@import "frontend";
@import "tracon_categories";
@import "../../../feedback/static_src/less/feedback.less";

.navbar-main {
background: @brand-primary url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaBAMAAABbZFH9AAAAElBMVEX///////////////////////+65XQCAAAABnRSTlMAHyEcGh7LhlI1AAAAf0lEQVR4Xl3OMQrDMBSDYR/hTyG7mhNoyS4o3VV6/7sUb7UFb/p4SOP1Oc77cV3P93l8h8d/nBlLSNqNiqkYDRaTaKCmeHSxCtsEJR1aDJDspK62v1iaqDret1QSzPPexyQqJLPtZKLcAtq22IUQIzGyWEliSqC7ldglUrL2/QBWYh5FPnmMCgAAAABJRU5ErkJggg==);
box-shadow: 0px 0px 15px 7px rgba(0, 0, 0, 0.3);
}

.panel, .list-group {
box-shadow: 2px 3px 15px -1px rgba(0, 0, 0, 0.2);
.navbar-brand {
font-weight: bold;
}

.panel, .panel-group .panel, .btn, .form-control, .label {
border-radius: @inputBorderRadius;
}

.panel-heading {
border-top-left-radius: @inputBorderRadius;
border-top-right-radius: @inputBorderRadius;
}

.panel-footer {
border-bottom-left-radius: @inputBorderRadius;
border-bottom-right-radius: @inputBorderRadius;
}

.label-brand {
Expand Down Expand Up @@ -41,7 +56,7 @@
.programme-host-table input {
width: 100%;
border: 1px solid #CCC;
border-radius: 4px;
border-radius: 1px;
padding: 6px 12px;
}

Expand Down Expand Up @@ -97,3 +112,23 @@
order: 3;
}
}

#core-frontpage-carousel a.item {
display: block;
color: white;
font-weight: bold;
font-size: 25px;
margin-bottom: 13px;
height: 400px;
background-size: cover;
background-position: center;

&:hover {
text-decoration: underline;
}

.slide-image-credit {
font-size: 13px;
font-weight: normal;
}
}
20 changes: 20 additions & 0 deletions core/templates/core_frontpage_carousel.jade
@@ -0,0 +1,20 @@
- load i18n
if carousel_slides.exists
.carousel.slide#core-frontpage-carousel(data-ride='carousel', style='margin-top: -25px')
ol.carousel-indicators
for slide in carousel_slides
if forloop.first
li.active(data-target='#core-frontpage-carousel', data-slide-to='{{ forloop.counter0 }}')
else
li(data-target='#core-frontpage-carousel', data-slide-to='{{ forloop.counter0 }}')

.carousel-inner(role="listbox")
for slide in carousel_slides
a.item(href="{{ slide.href }}"
target="{{ slide.target }}"
class="{% if forloop.first %}active{% endif %}"
style="background-image: url({{ slide.image_file.url }})")
.carousel-caption
if slide.image_credit
.slide-image-credit {% trans "Picture:" %} {{ slide.image_credit }}
.slide-title {{ slide.title }}
11 changes: 6 additions & 5 deletions core/templates/core_frontpage_view.jade
@@ -1,8 +1,9 @@
extends base
block full_title
| {{ settings.KOMPASSI_INSTALLATION_NAME }}
block content
if "branding" in settings.INSTALLED_APPS
include branding_frontpage.jade
include core_event_boxen.jade
include core_organization_boxen.jade
block content_full_width
include core_frontpage_carousel.jade

.container
include core_event_boxen.jade
include core_organization_boxen.jade
5 changes: 4 additions & 1 deletion core/utils/__init__.py
@@ -1,3 +1,5 @@
# flake8: noqa

from .form_utils import (
DateField,
horizontal_form_helper,
Expand Down Expand Up @@ -39,11 +41,12 @@

from .time_utils import (
calculate_age,
format_date,
format_date_range,
format_date,
format_datetime,
format_interval,
full_hours_between,
get_objects_within_period,
is_within_period,
ONE_HOUR,
)
Expand Down
32 changes: 28 additions & 4 deletions core/utils/time_utils.py
@@ -1,10 +1,7 @@
# encoding: utf-8



import sys
from datetime import date, datetime, timedelta

from django.db.models import Q
from django.utils.timezone import now
from django.template import defaultfilters

Expand Down Expand Up @@ -54,6 +51,33 @@ def is_within_period(period_start, period_end, t=None):
not (period_end and period_end <= t)


def get_objects_within_period(
Model,
t=None,
start_field_name='active_from',
end_field_name='active_until',
**extra_criteria
):
"""
Given a Model with an activity period, return only those instances that are within the
activity period and match any given extra criteria.
If the activity period start is not set, the object will never be returned.
If the activity period end is unset, the object will never expire, ie. will always be
returned if its activity period start has passed.
"""

if t is None:
t = now()

q = Q(**{f'{start_field_name}__lte': t})
q &= Q(**{f'{end_field_name}__gt': t}) | Q(**{f'{end_field_name}__isnull': True})
q &= Q(**extra_criteria)

return Model.objects.filter(q)


def format_date_range(start_date, end_date):
# XXX Finnish-specific

Expand Down
11 changes: 4 additions & 7 deletions core/views/core_frontpage_view.py
@@ -1,14 +1,10 @@
# encoding: utf-8



from django.db.models import Q
from django.shortcuts import render
from django.utils.timezone import now

from core.utils import groups_of_n, groupby_strict

from ..models import Event, Organization
from ..models import Event, Organization, CarouselSlide


def get_year(event):
Expand Down Expand Up @@ -39,10 +35,11 @@ def core_frontpage_view(request):
past_events_rows_by_year = [(year, list(groups_of_n(year_events, 4))) for (year, year_events) in groupby_strict(past_events, get_year)]

vars = dict(
future_events_rows=list(groups_of_n(future_events, 4)),
carousel_slides=CarouselSlide.get_active_slides(),
current_events_rows=list(groups_of_n(current_events, 4)),
future_events_rows=list(groups_of_n(future_events, 4)),
organizations_rows=list(groups_of_n(organizations, 4)),
past_events_rows_by_year=past_events_rows_by_year,
organizations_rows = list(groups_of_n(organizations, 4)),
)

return render(request, 'core_frontpage_view.jade', vars)
5 changes: 3 additions & 2 deletions docker-compose.yml
Expand Up @@ -11,6 +11,7 @@ services:
- memcache
volumes:
- .:/usr/src/app
- web-media:/usr/src/app/media
environment:
PYTHONUNBUFFERED: 1
DEBUG: 1
Expand Down Expand Up @@ -49,5 +50,5 @@ services:
memcache:
image: memcached
volumes:
postgres-data:
driver: local
postgres-data: {}
web-media: {}

0 comments on commit 745c5df

Please sign in to comment.