diff --git a/com/admin.py b/com/admin.py
index db60dd05..df553be2 100644
--- a/com/admin.py
+++ b/com/admin.py
@@ -39,4 +39,6 @@ class WeekmailAdmin(SearchModelAdmin):
admin.site.register(Sith)
admin.site.register(News, NewsAdmin)
admin.site.register(Weekmail, WeekmailAdmin)
+admin.site.register(Screen)
+admin.site.register(Poster)
diff --git a/com/models.py b/com/models.py
index 3d2089c5..bd1f7afe 100644
--- a/com/models.py
+++ b/com/models.py
@@ -32,10 +32,14 @@ from django.conf import settings
from django.contrib.staticfiles.templatetags.staticfiles import static
from django.core.mail import EmailMultiAlternatives
-from core.models import User, Preferences, RealGroup, Notification
+from django.utils import timezone
+
+from core.models import User, Preferences, RealGroup, Notification, SithFile
from club.models import Club
+
+
class Sith(models.Model):
"""A one instance class storing all the modifiable infos"""
alert_msg = models.TextField(_("alert message"), default="", blank=True)
@@ -183,3 +187,41 @@ class WeekmailArticle(models.Model):
def __str__(self):
return "%s - %s (%s)" % (self.title, self.author, self.club)
+
+
+class Screen(models.Model):
+ name = models.CharField(_("name"), max_length=128)
+ club = models.ForeignKey(Club, related_name="screens", verbose_name=_("club"), null=False)
+
+ def active_posters(self):
+ now = timezone.now()
+ return self.posters.filter(is_moderated=True, date_begin__lte=now).filter(Q(date_end__isnull=True)|Q(date_end__gte=now))
+
+ def is_owned_by(self, user):
+ return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
+
+ def __str__(self):
+ return "%s: %s" % (self.club, self.name)
+
+class Poster(models.Model):
+ name = models.CharField(_("name"), blank=False, null=False, max_length=128, default="")
+ file = models.ImageField(_("file"), null=False, upload_to="com/posters")
+ screens = models.ManyToManyField(Screen, related_name="posters")
+ date_begin = models.DateTimeField(blank=False, null=False, default=timezone.now)
+ date_end = models.DateTimeField(blank=True, null=True)
+ is_moderated = models.BooleanField(_("is moderated"), default=False)
+ moderator = models.ForeignKey(User, related_name="moderated_posters", verbose_name=_("moderator"), null=True, blank=True)
+
+ def save(self, *args, **kwargs):
+ if self.date_end and self.date_begin > self.date_end:
+ raise ValidationError
+ return super(Poster, self).save(*args, **kwargs)
+
+ def is_owned_by(self, user):
+ return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
+
+ def can_moderate(self, user):
+ return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
+
+ def __str__(self):
+ return self.name
diff --git a/com/templates/com/poster_edit.jinja b/com/templates/com/poster_edit.jinja
new file mode 100644
index 00000000..5b9cca1c
--- /dev/null
+++ b/com/templates/com/poster_edit.jinja
@@ -0,0 +1,35 @@
+{% extends "core/base.jinja" %}
+
+{% block title %}
+{% trans %}Poster{% endtrans %}
+{% endblock %}
+
+{% block content %}
+
+
+
+
+
{% trans %}Posters - edit{% endtrans %}
+
+
+
+
+
+
+{% endblock %}
+
+
+
diff --git a/com/templates/com/poster_list.jinja b/com/templates/com/poster_list.jinja
new file mode 100644
index 00000000..cfb8d223
--- /dev/null
+++ b/com/templates/com/poster_list.jinja
@@ -0,0 +1,52 @@
+{% extends "core/base.jinja" %}
+
+{% block script %}
+{{ super() }}
+
+{% endblock %}
+
+
+{% block title %}
+{% trans %}Poster{% endtrans %}
+{% endblock %}
+
+{% block content %}
+
+
+
+
{% trans %}Posters{% endtrans %}
+
+
+
+
+
+ {% if posters.count() == 0 %}
+
{% trans %}No posters{% endtrans %}
+ {% else %}
+
+ {% for poster in posters %}
+
+
{{ poster.name }}
+
+
+
{{ poster.date_begin | date("d/M/Y H:m") }}
+
{{ poster.date_end | date("d/M/Y H:m") }}
+
+
{% trans %}Edit{% endtrans %}
+
+ {% endfor %}
+
+ {% endif %}
+
+
+
+
+
+
+{% endblock %}
+
+
+
diff --git a/com/templates/com/poster_moderate.jinja b/com/templates/com/poster_moderate.jinja
new file mode 100644
index 00000000..b9cbf988
--- /dev/null
+++ b/com/templates/com/poster_moderate.jinja
@@ -0,0 +1,39 @@
+{% extends "core/base.jinja" %}
+
+{% block script %}
+{{ super() }}
+
+{% endblock %}
+
+{% block content %}
+
+
+
+
+
{% trans %}Posters - moderation{% endtrans %}
+
+
+
+
+ {% if object_list.count == 0 %}
+
{% trans %}No objects{% endtrans %}
+ {% else %}
+
+ {% for poster in object_list %}
+
+
{{ poster.name }}
+
+
Moderate
+
+ {% endfor %}
+
+ {% endif %}
+
+
+
+
+
+
+{% endblock %}
diff --git a/com/templates/com/screen_edit.jinja b/com/templates/com/screen_edit.jinja
new file mode 100644
index 00000000..b18c2e00
--- /dev/null
+++ b/com/templates/com/screen_edit.jinja
@@ -0,0 +1,34 @@
+{% extends "core/base.jinja" %}
+
+{% block title %}
+{% trans %}Screen{% endtrans %}
+{% endblock %}
+
+{% block content %}
+
+
+
+
+
{% trans %}Screen - edit{% endtrans %}
+
+
+
+
+
+
+{% endblock %}
+
+
+
diff --git a/com/templates/com/screen_list.jinja b/com/templates/com/screen_list.jinja
new file mode 100644
index 00000000..83f614be
--- /dev/null
+++ b/com/templates/com/screen_list.jinja
@@ -0,0 +1,40 @@
+{% extends "core/base.jinja" %}
+
+{% block title %}
+{% trans %}Screens{% endtrans %}
+{% endblock %}
+
+{% block content %}
+
+
+
+
{% trans %}Screens{% endtrans %}
+
+
+
+
+
+ {% if screen_list.count() == 0 %}
+
{% trans %}No screens{% endtrans %}
+ {% else %}
+
+ {% for screen in screen_list %}
+
+ {% endfor %}
+
+ {% endif %}
+
+
+
+
+{% endblock %}
+
+
+
diff --git a/com/templates/com/screen_slideshow.jinja b/com/templates/com/screen_slideshow.jinja
new file mode 100644
index 00000000..76ff743c
--- /dev/null
+++ b/com/templates/com/screen_slideshow.jinja
@@ -0,0 +1,30 @@
+
+
+
+ {% trans %}Slideshow{% endtrans %}
+
+
+
+
+
+
+ {% for poster in posters %}
+
+
+
+ {% endfor %}
+
+
+
+ {% for poster in posters %}
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
diff --git a/com/urls.py b/com/urls.py
index 3f172693..9f5b0d97 100644
--- a/com/urls.py
+++ b/com/urls.py
@@ -47,5 +47,16 @@ urlpatterns = [
url(r'^mailings$', MailingListAdminView.as_view(), name='mailing_admin'),
url(r'^mailings/(?P[0-9]+)/moderate$', MailingModerateView.as_view(), name='mailing_moderate'),
url(r'^mailings/(?P[0-9]+)/delete$', MailingDeleteView.as_view(redirect_page='com:mailing_admin'), name='mailing_delete'),
+ url(r'^poster$', PosterListView.as_view(), name='poster_list'),
+ url(r'^poster/create$', PosterCreateView.as_view(), name='poster_create'),
+ url(r'^poster/(?P[0-9]+)/edit$', PosterEditView.as_view(), name='poster_edit'),
+ url(r'^poster/(?P[0-9]+)/delete$', PosterDeleteView.as_view(), name='poster_delete'),
+ url(r'^poster/moderate$', PosterModerateListView.as_view(), name='poster_moderate_list'),
+ url(r'^poster/(?P[0-9]+)/moderate$', PosterModerateView.as_view(), name='poster_moderate'),
+ url(r'^screen$', ScreenListView.as_view(), name='screen_list'),
+ url(r'^screen/create$', ScreenCreateView.as_view(), name='screen_create'),
+ url(r'^screen/(?P[0-9]+)/slideshow$', ScreenSlideshowView.as_view(), name='screen_slideshow'),
+ url(r'^screen/(?P[0-9]+)/edit$', ScreenEditView.as_view(), name='screen_edit'),
+ url(r'^screen/(?P[0-9]+)/delete$', ScreenDeleteView.as_view(), name='screen_delete'),
]
diff --git a/com/views.py b/com/views.py
index 34bd99d0..ab6dd64d 100644
--- a/com/views.py
+++ b/com/views.py
@@ -40,7 +40,7 @@ from django import forms
from datetime import timedelta
-from com.models import Sith, News, NewsDate, Weekmail, WeekmailArticle
+from com.models import Sith, News, NewsDate, Weekmail, WeekmailArticle, Screen, Poster
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, CanCreateMixin, QuickNotifMixin
from core.views.forms import SelectDateTime
from core.models import Notification, RealGroup, User
@@ -88,9 +88,27 @@ class ComTabsMixin(TabedViewMixin):
'slug': 'mailings',
'name': _("Mailing lists administration"),
})
+ tab_list.append({
+ 'url': reverse('com:poster_list'),
+ 'slug': 'posters',
+ 'name': _("Posters list"),
+ })
+ tab_list.append({
+ 'url': reverse('com:screen_list'),
+ 'slug': 'screens',
+ 'name': _("Screens list"),
+ })
return tab_list
+class IsComAdminMixin(View):
+
+ def dispatch(self, request, *args, **kwargs):
+ if not (request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or request.user.is_root):
+ raise PermissionDenied
+ return super(IsComAdminMixin, self).dispatch(request, *args, **kwargs)
+
+
class ComEditView(ComTabsMixin, CanEditPropMixin, UpdateView):
model = Sith
template_name = 'core/edit.jinja'
@@ -117,6 +135,14 @@ class IndexEditView(ComEditView):
success_url = reverse_lazy('com:index_edit')
+class ModerateListView(ListView):
+ """Generic view for moderation pages"""
+
+
+class ModerateView(View):
+ """Generic view for moderation pages"""
+
+
class WeekmailDestinationEditView(ComEditView):
fields = ['weekmail_destinations']
current_tab = "weekmail_destinations"
@@ -465,3 +491,114 @@ class MailingModerateView(View):
return redirect('com:mailing_admin')
raise PermissionDenied
+
+
+class PosterListView(IsComAdminMixin, ComTabsMixin, ListView):
+ """List communication posters"""
+ current_tab = "posters"
+ model = Poster
+ template_name = 'com/poster_list.jinja'
+
+ def get_context_data(self, **kwargs):
+ kwargs = super(PosterListView, self).get_context_data(**kwargs)
+ kwargs['posters'] = Poster.objects.all().order_by('-date_begin')
+ return kwargs
+
+
+class PosterCreateView(IsComAdminMixin, ComTabsMixin, CreateView):
+ """Create communication poster"""
+ current_tab = "posters"
+ model = Poster
+ fields = ['name', 'file', 'screens', 'date_begin', 'date_end']
+ template_name = 'core/create.jinja'
+ success_url = reverse_lazy('com:poster_list')
+
+
+class PosterEditView(IsComAdminMixin, ComTabsMixin, UpdateView):
+ """Edit communication poster"""
+ pk_url_kwarg = "poster_id"
+ current_tab = "posters"
+ model = Poster
+ fields = ['name', 'file', 'screens', 'date_begin', 'date_end']
+ template_name = 'com/poster_edit.jinja'
+ success_url = reverse_lazy('com:poster_list')
+
+
+class PosterDeleteView(IsComAdminMixin, ComTabsMixin, DeleteView):
+ """Delete communication poster"""
+ pk_url_kwarg = "poster_id"
+ current_tab = "posters"
+ model = Poster
+ template_name = 'core/delete_confirm.jinja'
+ success_url = reverse_lazy('com:poster_list')
+
+
+class PosterModerateListView(IsComAdminMixin, ComTabsMixin, ListView):
+ """Moderate list communication poster"""
+ current_tab = "posters"
+ model = Poster
+ template_name = 'com/poster_moderate.jinja'
+ def get_context_data(self, **kwargs):
+ kwargs = super(PosterModerateListView, self).get_context_data(**kwargs)
+ kwargs['moderation_url'] = 'com:poster_moderate'
+ kwargs['object_list'] = Poster.objects.filter(is_moderated=False).all()
+ return kwargs
+
+
+class PosterModerateView(IsComAdminMixin, ComTabsMixin, ModerateView):
+ """Moderate communication poster"""
+ def get(self, request, *args, **kwargs):
+ obj = get_object_or_404(Poster, pk=kwargs['object_id'])
+ if obj.can_moderate(request.user):
+ obj.is_moderated = True
+ obj.moderator = request.user
+ obj.save()
+ return redirect('com:poster_moderate_list')
+ raise PermissionDenied
+
+
+class ScreenListView(IsComAdminMixin, ComTabsMixin, ListView):
+ """List communication screens"""
+ current_tab = "screens"
+ model = Screen
+ template_name = 'com/screen_list.jinja'
+
+
+class ScreenSlideshowView(DetailView):
+ """Slideshow of actives posters"""
+ pk_url_kwarg = "screen_id"
+ model = Screen
+ template_name = 'com/screen_slideshow.jinja'
+
+ def get_context_data(self, **kwargs):
+ kwargs = super(ScreenSlideshowView, self).get_context_data(**kwargs)
+ kwargs['posters'] = self.object.active_posters()
+ return kwargs
+
+
+class ScreenCreateView(IsComAdminMixin, ComTabsMixin, CreateView):
+ """Create communication screen"""
+ current_tab = "screens"
+ model = Screen
+ fields = ['name', 'club']
+ template_name = 'core/create.jinja'
+ success_url = reverse_lazy('com:screen_list')
+
+
+class ScreenEditView(IsComAdminMixin, ComTabsMixin, UpdateView):
+ """Edit communication screen"""
+ pk_url_kwarg = "screen_id"
+ current_tab = "screens"
+ model = Screen
+ fields = ['name', 'club']
+ template_name = 'com/screen_edit.jinja'
+ success_url = reverse_lazy('com:screen_list')
+
+
+class ScreenDeleteView(IsComAdminMixin, ComTabsMixin, DeleteView):
+ """Delete communication screen"""
+ pk_url_kwarg = "screen_id"
+ current_tab = "screens"
+ model = Screen
+ template_name = 'core/delete_confirm.jinja'
+ success_url = reverse_lazy('com:screen_list')
diff --git a/core/admin.py b/core/admin.py
index eec0e90b..6c954aa8 100644
--- a/core/admin.py
+++ b/core/admin.py
@@ -2,6 +2,7 @@
#
# Copyright 2016,2017
# - Skia
+# - Nabos
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
@@ -28,9 +29,12 @@ from core.models import User, Page, RealGroup, SithFile
from django.contrib.auth.models import Group as AuthGroup
from haystack.admin import SearchModelAdmin
+@admin.register(SithFile)
+class SithFileAdmin(admin.ModelAdmin):
+ form = make_ajax_form(SithFile, {
+ 'parent': 'files', # ManyToManyField
+ })
-admin.site.unregister(AuthGroup)
-admin.site.register(RealGroup)
class UserAdmin(SearchModelAdmin):
list_display = ["first_name", "last_name", "username", "email", "nick_name"]
@@ -45,6 +49,11 @@ class UserAdmin(SearchModelAdmin):
admin.site.register(User, UserAdmin)
+ search_fields = ['username', 'first_name', 'last_name']
+ list_display = ('username', 'first_name', 'last_name')
+ list_filter = ['department', 'promo', 'groups']
+ list_per_page = 20
+
@admin.register(Page)
class PageAdmin(admin.ModelAdmin):
form = make_ajax_form(Page, {
@@ -54,8 +63,6 @@ class PageAdmin(admin.ModelAdmin):
'view_groups': 'groups',
})
-@admin.register(SithFile)
-class SithFileAdmin(admin.ModelAdmin):
- form = make_ajax_form(SithFile, {
- 'parent': 'files', # ManyToManyField
- })
+admin.site.register(User, UserAdmin)
+admin.site.unregister(AuthGroup)
+admin.site.register(RealGroup)
diff --git a/core/static/com/js/poster_create.js b/core/static/com/js/poster_create.js
new file mode 100644
index 00000000..5438a2d4
--- /dev/null
+++ b/core/static/com/js/poster_create.js
@@ -0,0 +1,22 @@
+$(document).ready(function(){
+
+ $("#poster_list #view").click(function(e){
+ $("#view").removeClass("active");
+ });
+
+ $("#poster_list .poster").click(function(e){
+
+ el = $(e.target);
+ $("#poster_list #view #placeholder").html(el);
+
+ $("#view").addClass("active");
+ });
+
+ $(document).keyup(function(e) {
+ if (e.keyCode == 27) { // escape key maps to keycode `27`
+ e.preventDefault();
+ $("#view").removeClass("active");
+ }
+ });
+
+});
diff --git a/core/static/com/js/poster_list.js b/core/static/com/js/poster_list.js
new file mode 100644
index 00000000..9d4090e9
--- /dev/null
+++ b/core/static/com/js/poster_list.js
@@ -0,0 +1,24 @@
+$(document).ready(function(){
+
+ $("#poster_list #view").click(function(e){
+ $("#view").removeClass("active");
+ });
+
+ $("#poster_list .poster .image").click(function(e){
+
+ el = $(e.target);
+ if(el.hasClass("image"))
+ el = el.find("img")
+ $("#poster_list #view #placeholder").html(el.clone());
+
+ $("#view").addClass("active");
+ });
+
+ $(document).keyup(function(e) {
+ if (e.keyCode == 27) { // escape key maps to keycode `27`
+ e.preventDefault();
+ $("#view").removeClass("active");
+ }
+ });
+
+});
diff --git a/core/static/com/js/slideshow.js b/core/static/com/js/slideshow.js
new file mode 100644
index 00000000..76882230
--- /dev/null
+++ b/core/static/com/js/slideshow.js
@@ -0,0 +1,115 @@
+$(document).ready(function(){
+
+ wait_time = 40 * 1000;
+ transition_time = 1000;
+
+ i = 0;
+ max = $("#slideshow .slide").length;
+
+ next_trigger = 0
+
+ function enterFullscreen() {
+ element = document.getElementById("slideshow");
+ $(element).addClass("fullscreen");
+ if(element.requestFullscreen) {
+ element.requestFullscreen();
+ } else if(element.mozRequestFullScreen) {
+ element.mozRequestFullScreen();
+ } else if(element.webkitRequestFullscreen) {
+ element.webkitRequestFullscreen();
+ } else if(element.msRequestFullscreen) {
+ element.msRequestFullscreen();
+ }
+ }
+
+ function exitFullscreen() {
+ element = document.getElementById("slideshow");
+ $(element).removeClass("fullscreen");
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen();
+ } else if (document.mozCancelFullScreen) {
+ document.mozCancelFullScreen();
+ } else if (document.msExitFullscreen) {
+ document.msExitFullscreen();
+ }
+ }
+
+ function init_progress_bar()
+ {
+
+ $("#slideshow #progress_bar").removeClass("progress");
+ $("#slideshow #progress_bar").addClass("init");
+
+ }
+
+ function start_progress_bar()
+ {
+
+ $("#slideshow #progress_bar").removeClass("init");
+ $("#slideshow #progress_bar").addClass("progress");
+
+ }
+
+ function next()
+ {
+
+ init_progress_bar();
+ slide = $($("#slideshow .slide").get(i % max));
+ slide.removeClass("center");
+ slide.addClass("left");
+
+ next_slide = $($("#slideshow .slide").get((i + 1) % max));
+ next_slide.removeClass("right");
+ next_slide.addClass("center");
+
+ $("#slideshow .bullet").removeClass("active");
+ bullet = $("#slideshow .bullet")[(i + 1) % max];
+ $(bullet).addClass("active");
+
+ i = (i + 1) % max;
+
+ setTimeout(function(){
+
+ others_left = $("#slideshow .slide.left");
+ others_left.removeClass("left");
+ others_left.addClass("right");
+
+ start_progress_bar();
+ next_trigger = setTimeout(next, wait_time);
+
+ }, transition_time);
+
+ }
+
+
+ init_progress_bar();
+ setTimeout(function(){
+ if(max > 1){
+ start_progress_bar();
+ setTimeout(next, wait_time);
+ }
+ }, 10);
+
+
+ $("#slideshow").click(function(e){
+ if(!$("#slideshow").hasClass("fullscreen"))
+ {
+ console.log("Entering fullscreen ...");
+ enterFullscreen();
+ }else{
+ console.log("Exiting fullscreen ...");
+ exitFullscreen();
+ }
+ });
+
+ $(document).keyup(function(e) {
+ if (e.keyCode == 27) { // escape key maps to keycode `27`
+ e.preventDefault();
+ console.log("Exiting fullscreen ...");
+ exitFullscreen();
+ }
+ });
+
+});
diff --git a/core/static/com/slideshow.scss b/core/static/com/slideshow.scss
new file mode 100644
index 00000000..b2f851d2
--- /dev/null
+++ b/core/static/com/slideshow.scss
@@ -0,0 +1,209 @@
+body{
+
+ position: absolute;
+ width: 100vw;
+ height: 100vh;
+
+ padding: 0;
+ margin: 0;
+
+}
+
+#slideshow
+{
+
+ position: relative;
+ background-color: lightgrey;
+
+ height: 100%;
+
+ *
+ {
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ }
+
+ &:hover{
+
+ &::before
+ {
+
+ position: absolute;
+ width: 100%;
+ height: 100%;
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ z-index: 10;
+
+ content: "Click to expand";
+
+ color: white;
+ background-color: rgba(black, 0.5);
+
+ }
+
+ }
+
+
+ &.fullscreen
+ {
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background: none;
+
+ &:before
+ {
+
+ display:none;
+
+ }
+
+ #slides
+ {
+
+ height: 100vh;
+
+ }
+
+ }
+
+ #slides
+ {
+
+ position: relative;
+
+ height: 100%;
+
+ overflow: hidden;
+
+ .slide
+ {
+
+ position: absolute;
+
+ width: 100%;
+ height: 100%;
+
+ display: inline-flex;
+ justify-content: center;
+
+ top: 0px;
+
+ background-color: grey;
+
+ transition: left 1s ease-out;
+
+ img
+ {
+
+ max-width: 100%;
+ max-height: 100%;
+
+ }
+
+ }
+
+ .slide.left
+ {
+
+ left: -100%;
+
+ }
+
+ .slide.center
+ {
+
+ left: 0px;
+
+ }
+
+ .slide.right
+ {
+
+ left: 100%;
+
+ transition: none;
+
+ }
+
+ }
+
+
+ #progress_bullets
+ {
+
+ position: absolute;
+
+ bottom: 10px;
+
+ width: 100%;
+ height: 10px;
+
+ display: flex;
+ justify-content: center;
+
+ margin-bottom: 10px;
+
+ .bullet
+ {
+
+ height: 10px;
+ width: 10px;
+
+ margin-left: 5px;
+ margin-right: 5px;
+
+ border-radius: 50%;
+
+ background-color: grey;
+
+ &.active
+ {
+
+ background-color: #c99836;
+
+ }
+
+ }
+
+
+ }
+
+ #progress_bar
+ {
+
+ position: absolute;
+ bottom: 0px;
+ height: 10px;
+ background-color: #304c83;
+
+ &.init
+ {
+
+ width: 0px;
+ transition: none;
+
+ }
+
+ &.progress
+ {
+
+ width: 100%;
+ transition: width 40s linear;
+
+ }
+
+ }
+
+}
+
diff --git a/core/static/core/style.scss b/core/static/core/style.scss
index c6964963..8e28ea22 100644
--- a/core/static/core/style.scss
+++ b/core/static/core/style.scss
@@ -642,6 +642,289 @@ header {
display: block;
}
+/*---------------------------POSTERS----------------------------*/
+
+#poster_list, #screen_list, #poster_edit, #screen_edit{
+
+ position: relative;
+
+ #title{
+
+ position: relative;
+
+ padding: 10px;
+ margin: 10px;
+
+ border-bottom: 2px solid black;
+
+ h3{
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ }
+
+ #links{
+
+ position: absolute;
+ display: flex;
+
+ bottom: 5px;
+
+ &.left{
+ left: 0;
+ }
+
+ &.right{
+ right: 0;
+ }
+
+ .link{
+
+ padding: 5px;
+ padding-left: 20px;
+ padding-right: 20px;
+
+ margin-left: 5px;
+
+ border-radius: 20px;
+
+ background-color: #ffaa00;
+
+ color: black;
+
+ &:hover{
+
+ color: black;
+
+ background-color: #c99836;
+
+ }
+
+ &.delete{
+
+ background-color: #cb0000;
+
+ }
+
+ }
+
+ }
+
+
+ }
+
+ #posters, #screens{
+
+ position: relative;
+
+ display: flex;
+ flex-wrap: wrap;
+
+ #no-posters, #no-screens{
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ }
+
+ .poster, .screen{
+
+ min-width: 10%;
+ max-width: 20%;
+
+ display: flex;
+ flex-direction: column;
+
+ margin: 10px;
+ border: 2px solid darkgrey;
+ border-radius: 4px;
+
+ padding: 10px;
+
+
+ background-color: lightgrey;
+
+ *{
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ }
+
+ .name{
+
+ padding-bottom: 5px;
+ margin-bottom: 5px;
+ border-bottom: 1px solid whitesmoke;
+
+ }
+
+ .image{
+
+ flex-grow: 1;
+
+ position: relative;
+
+ padding-bottom: 5px;
+ margin-bottom: 5px;
+ border-bottom: 1px solid whitesmoke;
+
+ img{
+
+ max-height: 20vw;
+ max-width: 100%;
+
+ }
+
+ &:hover{
+
+ &::before{
+
+ position: absolute;
+ width: 100%;
+ height: 100%;
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-wrap: wrap;
+
+ top: 0;
+ left: 0;
+ z-index: 10;
+
+ content: "Click to expand";
+
+ color: white;
+ background-color: rgba(black, 0.5);
+
+ }
+
+ }
+
+ }
+
+ .dates{
+
+ padding-bottom: 5px;
+ margin-bottom: 5px;
+ border-bottom: 1px solid whitesmoke;
+
+ *{
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-wrap: wrap;
+
+ margin-left: 5px;
+ margin-right: 5px;
+
+ }
+
+ .begin, .end{
+
+ width: 48%;
+
+ }
+
+ .begin{
+
+ border-right: 1px solid whitesmoke;
+
+ padding-right: 2%;
+
+ }
+
+ }
+
+ .edit, .moderate, .slideshow{
+
+ padding: 5px;
+
+ border-radius: 20px;
+
+ background-color: #ffaa00;
+
+ color: black;
+
+ &:hover{
+
+ color: black;
+
+ background-color: #c99836;
+
+ }
+
+ &:nth-child(2n){
+
+ margin-top: 5px;
+ margin-bottom: 5px;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ #view{
+
+ position: fixed;
+
+ width: 100vw;
+ height: 100vh;
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ top: 0;
+ left: 0;
+ z-index: 10;
+
+ visibility: hidden;
+ background-color: rgba(10, 10, 10, 0.9);
+
+ overflow: hidden;
+
+ &.active{
+
+ visibility: visible;
+
+ }
+
+ #placeholder{
+
+ width: 80vw;
+ height: 80vh;
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ top: 0;
+ left: 0;
+
+ img{
+
+ max-width: 100%;
+ max-height: 100%;
+
+ }
+
+ }
+
+ }
+
+}
+
+
/*---------------------------ACCOUNTING----------------------------*/
#accounting {
.journal-table {