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 %}

+ +
+ +
+ +
+ {% csrf_token %} + {{ form.as_p() }} +

+
+ + +
+ +
+{% 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 %}

+ +
+ +
+ +
+ {% csrf_token %} + {{ form.as_p() }} +

+
+ +
+ +
+{% 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 %} +
+
{{ screen.name }}
+
Club: {{ screen.club }}
+ {% trans %}Edit{% endtrans %} + {% trans %}Slideshow{% endtrans %} +
+ {% 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 {