Refactor com scss and add basic unified event calendar

This commit is contained in:
Antoine Bartuccio 2024-12-28 18:54:42 +01:00
parent 82e88dcab0
commit 593171970a
20 changed files with 963 additions and 668 deletions

53
com/api.py Normal file
View File

@ -0,0 +1,53 @@
from datetime import timedelta
import urllib3
from django.core.cache import cache
from django.http import HttpResponse
from django.utils import timezone
from ics import Calendar, Event
from ninja_extra import ControllerBase, api_controller, route
from com.models import NewsDate
@api_controller("/calendar")
class CalendarController(ControllerBase):
@route.get("/external.ics")
def calendar_external(self):
CACHE_KEY = "external_calendar"
if cached := cache.get(CACHE_KEY):
return HttpResponse(
cached,
content_type="text/calendar",
status=200,
)
calendar = urllib3.request(
"GET",
"https://calendar.google.com/calendar/ical/ae.utbm%40gmail.com/public/basic.ics",
)
if calendar.status == 200:
cache.set(CACHE_KEY, calendar.data, 3600) # Cache for one hour
return HttpResponse(
calendar.data,
content_type="text/calendar",
status=calendar.status,
)
@route.get("/internal.ics")
def calendar_internal(self):
calendar = Calendar()
for news_date in NewsDate.objects.filter(
news__is_moderated=True,
start_date__lte=timezone.now() + timedelta(days=30),
).prefetch_related("news"):
event = Event(
name=news_date.news.title,
begin=news_date.start_date,
end=news_date.end_date,
)
calendar.events.add(event)
return HttpResponse(
calendar.serialize().encode("utf-8"),
content_type="text/calendar",
)

View File

@ -0,0 +1,75 @@
import { makeUrl } from "#core:utils/api";
import { inheritHtmlElement, registerComponent } from "#core:utils/web-components";
import { Calendar } from "@fullcalendar/core";
import enLocale from "@fullcalendar/core/locales/en-gb";
import frLocale from "@fullcalendar/core/locales/fr";
import dayGridPlugin from "@fullcalendar/daygrid";
import iCalendarPlugin from "@fullcalendar/icalendar";
import listPlugin from "@fullcalendar/list";
import { calendarCalendarExternal, calendarCalendarInternal } from "#openapi";
@registerComponent("ics-calendar")
export class IcsCalendar extends inheritHtmlElement("div") {
static observedAttributes = ["locale"];
private calendar: Calendar;
private locale = "en";
attributeChangedCallback(name: string, _oldValue?: string, newValue?: string) {
if (name !== "locale") {
return;
}
this.locale = newValue;
}
isMobile() {
return window.innerWidth < 765;
}
currentView() {
// Get view type based on viewport
return this.isMobile() ? "listMonth" : "dayGridMonth";
}
currentToolbar() {
if (this.isMobile()) {
return {
left: "prev,next",
center: "title",
right: "",
};
}
return {
left: "prev,next today",
center: "title",
right: "dayGridMonth,dayGridWeek,dayGridDay",
};
}
async connectedCallback() {
super.connectedCallback();
this.calendar = new Calendar(this.node, {
plugins: [dayGridPlugin, iCalendarPlugin, listPlugin],
locales: [frLocale, enLocale],
height: "auto",
locale: this.locale,
initialView: this.currentView(),
headerToolbar: this.currentToolbar(),
eventSources: [
{
url: await makeUrl(calendarCalendarInternal),
format: "ics",
},
{
url: await makeUrl(calendarCalendarExternal),
format: "ics",
},
],
windowResize: () => {
this.calendar.changeView(this.currentView());
this.calendar.setOption("headerToolbar", this.currentToolbar());
},
});
this.calendar.render();
}
}

View File

@ -0,0 +1,60 @@
@import "core/static/core/colors";
:root {
--fc-button-border-color: #fff;
--fc-button-hover-border-color: #fff;
--fc-button-active-border-color: #fff;
--fc-button-text-color: #fff;
--fc-button-bg-color: #1a78b3;
--fc-button-active-bg-color: #15608F;
--fc-button-hover-bg-color: #15608F;
--fc-today-bg-color: rgba(26, 120, 179, 0.1);
--fc-border-color: #DDDDDD;
--sc-main-background-color: #f9fafb;
--sc-main-padding: 5px;
--sc-main-border: 0px solid #DDDDDD;
--sc-main-border-radius: 0px;
--sc-body-font-family: Roboto;
--sc-title-font-family: Roboto;
--sc-body-font-size: 16px;
--sc-title-font-size: 28px;
--sc-body-font-weight: 400;
--sc-title-font-weight: 500;
--sc-title-font-color: #111111;
--sc-base-body-font-color: #222222;
--sc-title-font-style: normal;
--sc-body-font-style: normal;
--sc-event-dot-color: #1a78b3;
--sc-button-border: 1px solid #ffffff;
--sc-button-border-radius: 4px;
--sc-button-icons-size: 22px;
--sc-grid-event-white-space: nowrap;
--sc-block-event-background-color-hovered: rgb(245, 245, 245);
--sc-block-event-border: 1px solid rgba(255, 255, 255, 0);
--sc-block-event-border-radius: 2.5px;
--sc-dot-event-background-color: rgba(255, 255, 255, 0);
--sc-dot-event-background-color-hovered: rgb(245, 245, 245);
--sc-dot-event-text-color: #222222;
--sc-dot-event-border: 1px solid rgba(255, 255, 255, 0);
--sc-dot-event-border-radius: 2.5px;
--sc-grid-day-header-background-color: rgba(255, 255, 255, 0);
--sc-list-day-header-background-color: rgba(208, 208, 208, 0.3);
--sc-inner-calendar-background-color: rgba(255, 255, 255, 0);
--sc-past-day-background-color: rgba(255, 255, 255, 0);
--sc-future-day-background-color: rgba(255, 255, 255, 0);
--sc-disabled-day-background-color: rgba(208, 208, 208, 0.3);
--sc-event-overlay-background-color: #FFFFFF;
--sc-event-overlay-padding: 20px;
--sc-event-overlay-border: 1px solid #EEEEEE;
--sc-event-overlay-border-radius: 4px;
--sc-event-overlay-primary-icon-color: #1a78b3;
--sc-event-overlay-secondary-icon-color: #000000;
--sc-event-overlay-box-shadow: 0px 6px 20px 4px rgb(0 0 0 / 16%);
--sc-event-overlay-max-width: 600px;
}
ics-calendar {
border: none;
box-shadow: none;
}

View File

@ -0,0 +1,66 @@
@import "core/static/core/colors";
#news_details {
display: inline-block;
margin-top: 20px;
padding: 0.4em;
width: 80%;
background: $white-color;
h4 {
margin-top: 1em;
text-transform: uppercase;
}
.club_logo {
display: inline-block;
text-align: center;
width: 19%;
float: left;
min-width: 15em;
margin: 0;
img {
max-height: 15em;
max-width: 12em;
display: block;
margin: 0 auto;
margin-bottom: 10px;
}
}
.share_button {
border: none;
color: white;
padding: 0.5em 1em;
text-align: center;
text-decoration: none;
font-size: 1.2em;
border-radius: 2px;
float: right;
display: block;
margin-left: 0.3em;
&:hover {
color: lightgrey;
}
}
.facebook {
background: $faceblue;
}
.twitter {
background: $twitblue;
}
.news_meta {
margin-top: 10em;
font-size: small;
}
}
.helptext {
margin-top: 10px;
display: block;
}

View File

@ -0,0 +1,298 @@
@import "core/static/core/colors";
@import "core/static/core/devices";
#news {
display: flex;
@media (max-width: 800px) {
flex-direction: column;
}
.news_column {
display: inline-block;
margin: 0;
vertical-align: top;
}
#news_admin {
margin-bottom: 1em;
}
#right_column {
flex: 20%;
float: right;
margin: 0.2em;
}
#left_column {
flex: 79%;
margin: 0.2em;
h3 {
background: $second-color;
box-shadow: $shadow-color 1px 1px 1px;
padding: 0.4em;
margin: 0 0 0.5em 0;
text-transform: uppercase;
font-size: 1.1em;
&:not(:first-of-type) {
margin: 2em 0 1em 0;
}
}
}
@media screen and (max-width: $small-devices) {
#left_column,
#right_column {
flex: 100%;
}
}
/* AGENDA/BIRTHDAYS */
#agenda,
#birthdays {
display: block;
width: 100%;
background: white;
font-size: 70%;
margin-bottom: 1em;
#agenda_title,
#birthdays_title {
margin: 0;
border-radius: 5px 5px 0 0;
box-shadow: $shadow-color 1px 1px 1px;
padding: 0.5em;
font-weight: bold;
font-size: 150%;
text-align: center;
text-transform: uppercase;
background: $second-color;
}
#agenda_content {
overflow: auto;
box-shadow: $shadow-color 1px 1px 1px;
height: 20em;
}
#agenda_content,
#birthdays_content {
.agenda_item {
padding: 0.5em;
margin-bottom: 0.5em;
&:nth-of-type(even) {
background: $secondary-neutral-light-color;
}
.agenda_time {
font-size: 90%;
color: grey;
}
.agenda_item_content {
p {
margin-top: 0.2em;
}
}
}
ul.birthdays_year {
margin: 0;
list-style-type: none;
font-weight: bold;
>li {
padding: 0.5em;
&:nth-child(even) {
background: $secondary-neutral-light-color;
}
}
ul {
margin: 0;
margin-left: 1em;
list-style-type: square;
list-style-position: inside;
font-weight: normal;
}
}
}
}
/* END AGENDA/BIRTHDAYS */
/* EVENTS TODAY AND NEXT FEW DAYS */
.news_events_group {
box-shadow: $shadow-color 1px 1px 1px;
margin-left: 1em;
margin-bottom: 0.5em;
.news_events_group_date {
display: table-cell;
padding: 0.6em;
vertical-align: middle;
background: $primary-neutral-dark-color;
color: $white-color;
text-transform: uppercase;
text-align: center;
font-weight: bold;
font-family: monospace;
font-size: 1.4em;
border-radius: 7px 0 0 7px;
div {
margin: 0 auto;
.day {
font-size: 1.5em;
}
}
}
.news_events_group_items {
display: table-cell;
width: 100%;
.news_event:nth-of-type(odd) {
background: white;
}
.news_event:nth-of-type(even) {
background: $primary-neutral-light-color;
}
.news_event {
display: block;
padding: 0.4em;
&:not(:last-child) {
border-bottom: 1px solid grey;
}
div {
margin: 0.2em;
}
h4 {
margin-top: 1em;
text-transform: uppercase;
}
.club_logo {
float: left;
min-width: 7em;
max-width: 9em;
margin: 0;
margin-right: 1em;
margin-top: 0.8em;
img {
max-height: 6em;
max-width: 8em;
display: block;
margin: 0 auto;
}
}
.news_date {
font-size: 100%;
}
.news_content {
clear: left;
.button_bar {
text-align: right;
.fb {
color: $faceblue;
}
.twitter {
color: $twitblue;
}
}
}
}
}
}
/* END EVENTS TODAY AND NEXT FEW DAYS */
/* COMING SOON */
.news_coming_soon {
display: list-item;
list-style-type: square;
list-style-position: inside;
margin-left: 1em;
padding-left: 0;
a {
font-weight: bold;
text-transform: uppercase;
}
.news_date {
font-size: 0.9em;
}
}
/* END COMING SOON */
/* NOTICES */
.news_notice {
margin: 0 0 1em 1em;
padding: 0.4em;
padding-left: 1em;
background: $secondary-neutral-light-color;
box-shadow: $shadow-color 0 0 2px;
border-radius: 18px 5px 18px 5px;
h4 {
margin: 0;
}
.news_content {
margin-left: 1em;
}
}
/* END NOTICES */
/* CALLS */
.news_call {
margin: 0 0 1em 1em;
padding: 0.4em;
padding-left: 1em;
background: $secondary-neutral-light-color;
border: 1px solid grey;
box-shadow: $shadow-color 1px 1px 1px;
h4 {
margin: 0;
}
.news_date {
font-size: 0.9em;
}
.news_content {
margin-left: 1em;
}
}
/* END CALLS */
.news_empty {
margin-left: 1em;
}
.news_date {
color: grey;
}
}

View File

@ -0,0 +1,230 @@
#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: hsl(40, 100%, 50%);
color: black;
&:hover {
color: black;
background-color: hsl(40, 58%, 50%);
}
&.delete {
background-color: hsl(0, 100%, 40%);
}
}
}
}
#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: hsl(40, 100%, 50%);
color: black;
&:hover {
color: black;
background-color: hsl(40, 58%, 50%);
}
&:nth-child(2n) {
margin-top: 5px;
margin-bottom: 5px;
}
}
.tooltip {
visibility: hidden;
width: 120px;
background-color: hsl(210, 20%, 98%);
color: hsl(0, 0%, 0%);
text-align: center;
padding: 5px 0;
border-radius: 6px;
position: absolute;
z-index: 10;
ul {
margin-left: 0;
display: inline-block;
li {
display: list-item;
list-style-type: none;
}
}
}
&.not_moderated {
border: 1px solid red;
}
&:hover .tooltip {
visibility: visible;
}
}
}
#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%;
}
}
}
}

View File

@ -11,6 +11,11 @@
{{ gen_news_metatags(news) }}
{% endblock %}
{% block additional_css %}
<link rel="stylesheet" href="{{ static('com/css/news-detail.scss') }}">
{% endblock %}
{% block content %}
<p><a href="{{ url('com:news_list') }}">{% trans %}Back to news{% endtrans %}</a></p>
<section id="news_details">

View File

@ -5,6 +5,15 @@
{% trans %}News{% endtrans %}
{% endblock %}
{% block additional_css %}
<link rel="stylesheet" href="{{ static('com/css/news-list.scss') }}">
<link rel="stylesheet" href="{{ static('com/components/ics-calendar.scss') }}">
{% endblock %}
{% block additional_js %}
<script type="module" src={{ static("bundled/com/components/ics-calendar-index.ts") }}></script>
{% endblock %}
{% block content %}
{% if user.is_com_admin %}
<div id="news_admin">
@ -98,16 +107,6 @@ type="EVENT").order_by('dates__start_date') %}
{% endfor %}
{% endif %}
<h3>{% trans %}All coming events{% endtrans %}</h3>
<iframe
src="https://embed.styledcalendar.com/#2mF2is8CEXhr4ADcX6qN"
title="Styled Calendar"
class="styled-calendar-container"
style="width: 100%; border: none; height: 1060px"
data-cy="calendar-embed-iframe">
</iframe>
</div>
<div id="right_column" class="news_column">
<div id="agenda">
<div id="agenda_title">{% trans %}Agenda{% endtrans %}</div>
@ -154,8 +153,14 @@ type="EVENT").order_by('dates__start_date') %}
{%- endif -%}
</div>
</div>
<h3>{% trans %}All coming events{% endtrans %}</h3>
<ics-calendar locale="{{ get_language() }}"></ics-calendar>
</div>
</div>
{% endblock %}

View File

@ -10,6 +10,10 @@
{% trans %}Poster{% endtrans %}
{% endblock %}
{% block additional_css %}
<link rel="stylesheet" href="{{ static('com/css/posters.scss') }}">
{% endblock %}
{% block content %}
<div id="poster_list">

View File

@ -5,6 +5,10 @@
<script src="{{ static('com/js/poster_list.js') }}"></script>
{% endblock %}
{% block additional_css %}
<link rel="stylesheet" href="{{ static('com/css/posters.scss') }}">
{% endblock %}
{% block content %}
<div id="poster_list">

View File

@ -741,7 +741,7 @@ Welcome to the wiki page!
NewsDate(
news=n,
start_date=friday + timedelta(hours=24 * 7 + 1),
end_date=self.now + timedelta(hours=24 * 7 + 9),
end_date=friday + timedelta(hours=24 * 7 + 9),
)
)
# Weekly
@ -768,7 +768,7 @@ Welcome to the wiki page!
)
NewsDate.objects.bulk_create(news_dates)
# Create som data for pedagogy
# Create some data for pedagogy
UV(
code="PA00",

View File

@ -0,0 +1,5 @@
/*--------------------------MEDIA QUERY HELPERS------------------------*/
$small-devices: 576px;
$medium-devices: 768px;
$large-devices: 992px;

View File

@ -1,10 +1,6 @@
@import "colors";
@import "forms";
/*--------------------------MEDIA QUERY HELPERS------------------------*/
$small-devices: 576px;
$medium-devices: 768px;
$large-devices: 992px;
@import "devices";
/*--------------------------------GENERAL------------------------------*/
@ -453,302 +449,6 @@ body {
}
}
/*---------------------------------NEWS--------------------------------*/
#news {
display: flex;
@media (max-width: 800px) {
flex-direction: column;
}
.news_column {
display: inline-block;
margin: 0;
vertical-align: top;
}
#news_admin {
margin-bottom: 1em;
}
#right_column {
flex: 20%;
float: right;
margin: 0.2em;
}
#left_column {
flex: 79%;
margin: 0.2em;
h3 {
background: $second-color;
box-shadow: $shadow-color 1px 1px 1px;
padding: 0.4em;
margin: 0 0 0.5em 0;
text-transform: uppercase;
font-size: 1.1em;
&:not(:first-of-type) {
margin: 2em 0 1em 0;
}
}
}
@media screen and (max-width: $small-devices) {
#left_column,
#right_column {
flex: 100%;
}
}
/* AGENDA/BIRTHDAYS */
#agenda,
#birthdays {
display: block;
width: 100%;
background: white;
font-size: 70%;
margin-bottom: 1em;
#agenda_title,
#birthdays_title {
margin: 0;
border-radius: 5px 5px 0 0;
box-shadow: $shadow-color 1px 1px 1px;
padding: 0.5em;
font-weight: bold;
font-size: 150%;
text-align: center;
text-transform: uppercase;
background: $second-color;
}
#agenda_content {
overflow: auto;
box-shadow: $shadow-color 1px 1px 1px;
height: 20em;
}
#agenda_content,
#birthdays_content {
.agenda_item {
padding: 0.5em;
margin-bottom: 0.5em;
&:nth-of-type(even) {
background: $secondary-neutral-light-color;
}
.agenda_time {
font-size: 90%;
color: grey;
}
.agenda_item_content {
p {
margin-top: 0.2em;
}
}
}
ul.birthdays_year {
margin: 0;
list-style-type: none;
font-weight: bold;
>li {
padding: 0.5em;
&:nth-child(even) {
background: $secondary-neutral-light-color;
}
}
ul {
margin: 0;
margin-left: 1em;
list-style-type: square;
list-style-position: inside;
font-weight: normal;
}
}
}
}
/* END AGENDA/BIRTHDAYS */
/* EVENTS TODAY AND NEXT FEW DAYS */
.news_events_group {
box-shadow: $shadow-color 1px 1px 1px;
margin-left: 1em;
margin-bottom: 0.5em;
.news_events_group_date {
display: table-cell;
padding: 0.6em;
vertical-align: middle;
background: $primary-neutral-dark-color;
color: $white-color;
text-transform: uppercase;
text-align: center;
font-weight: bold;
font-family: monospace;
font-size: 1.4em;
border-radius: 7px 0 0 7px;
div {
margin: 0 auto;
.day {
font-size: 1.5em;
}
}
}
.news_events_group_items {
display: table-cell;
width: 100%;
.news_event:nth-of-type(odd) {
background: white;
}
.news_event:nth-of-type(even) {
background: $primary-neutral-light-color;
}
.news_event {
display: block;
padding: 0.4em;
&:not(:last-child) {
border-bottom: 1px solid grey;
}
div {
margin: 0.2em;
}
h4 {
margin-top: 1em;
text-transform: uppercase;
}
.club_logo {
float: left;
min-width: 7em;
max-width: 9em;
margin: 0;
margin-right: 1em;
margin-top: 0.8em;
img {
max-height: 6em;
max-width: 8em;
display: block;
margin: 0 auto;
}
}
.news_date {
font-size: 100%;
}
.news_content {
clear: left;
.button_bar {
text-align: right;
.fb {
color: $faceblue;
}
.twitter {
color: $twitblue;
}
}
}
}
}
}
/* END EVENTS TODAY AND NEXT FEW DAYS */
/* COMING SOON */
.news_coming_soon {
display: list-item;
list-style-type: square;
list-style-position: inside;
margin-left: 1em;
padding-left: 0;
a {
font-weight: bold;
text-transform: uppercase;
}
.news_date {
font-size: 0.9em;
}
}
/* END COMING SOON */
/* NOTICES */
.news_notice {
margin: 0 0 1em 1em;
padding: 0.4em;
padding-left: 1em;
background: $secondary-neutral-light-color;
box-shadow: $shadow-color 0 0 2px;
border-radius: 18px 5px 18px 5px;
h4 {
margin: 0;
}
.news_content {
margin-left: 1em;
}
}
/* END NOTICES */
/* CALLS */
.news_call {
margin: 0 0 1em 1em;
padding: 0.4em;
padding-left: 1em;
background: $secondary-neutral-light-color;
border: 1px solid grey;
box-shadow: $shadow-color 1px 1px 1px;
h4 {
margin: 0;
}
.news_date {
font-size: 0.9em;
}
.news_content {
margin-left: 1em;
}
}
/* END CALLS */
.news_empty {
margin-left: 1em;
}
.news_date {
color: grey;
}
}
}
@media screen and (max-width: $small-devices) {
@ -757,304 +457,6 @@ body {
}
}
#news_details {
display: inline-block;
margin-top: 20px;
padding: 0.4em;
width: 80%;
background: $white-color;
h4 {
margin-top: 1em;
text-transform: uppercase;
}
.club_logo {
display: inline-block;
text-align: center;
width: 19%;
float: left;
min-width: 15em;
margin: 0;
img {
max-height: 15em;
max-width: 12em;
display: block;
margin: 0 auto;
margin-bottom: 10px;
}
}
.share_button {
border: none;
color: white;
padding: 0.5em 1em;
text-align: center;
text-decoration: none;
font-size: 1.2em;
border-radius: 2px;
float: right;
display: block;
margin-left: 0.3em;
&:hover {
color: lightgrey;
}
}
.facebook {
background: $faceblue;
}
.twitter {
background: $twitblue;
}
.news_meta {
margin-top: 10em;
font-size: small;
}
}
.helptext {
margin-top: 10px;
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: hsl(40, 100%, 50%);
color: black;
&:hover {
color: black;
background-color: hsl(40, 58%, 50%);
}
&.delete {
background-color: hsl(0, 100%, 40%);
}
}
}
}
#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: hsl(40, 100%, 50%);
color: black;
&:hover {
color: black;
background-color: hsl(40, 58%, 50%);
}
&:nth-child(2n) {
margin-top: 5px;
margin-bottom: 5px;
}
}
.tooltip {
visibility: hidden;
width: 120px;
background-color: hsl(210, 20%, 98%);
color: hsl(0, 0%, 0%);
text-align: center;
padding: 5px 0;
border-radius: 6px;
position: absolute;
z-index: 10;
ul {
margin-left: 0;
display: inline-block;
li {
display: list-item;
list-style-type: none;
}
}
}
&.not_moderated {
border: 1px solid red;
}
&:hover .tooltip {
visibility: visible;
}
}
}
#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 {

View File

@ -1,54 +0,0 @@
{% extends "core/base.jinja" %}
{% block script %}
{{ super() }}
<script src="{{ static('com/js/poster_list.js') }}"></script>
{% endblock %}
{% block title %}
{% trans %}Poster{% endtrans %}
{% endblock %}
{% block content %}
<div id="poster_list">
<div id="title">
<h3>{% trans %}Posters{% endtrans %}</h3>
<div id="links" class="right">
<a id="create" class="link" href="{{ url(app + ":poster_list") }}">{% trans %}Create{% endtrans %}</a>
{% if app == "com" %}
<a id="moderation" class="link" href="{{ url("com:poster_moderate_list") }}">{% trans %}Moderation{% endtrans %}</a>
{% endif %}
</div>
</div>
<div id="posters">
{% if poster_list.count() == 0 %}
<div id="no-posters">{% trans %}No posters{% endtrans %}</div>
{% else %}
{% for poster in poster_list %}
<div class="poster">
<div class="name">{{ poster.name }}</div>
<div class="image"><img src="{{ poster.file.url }}"></img></div>
<div class="dates">
<div class="begin">{{ poster.date_begin | date("d/M/Y H:m") }}</div>
<div class="end">{{ poster.date_end | date("d/M/Y H:m") }}</div>
</div>
<a class="edit" href="{{ url(poster_edit_url_name, poster.id) }}">{% trans %}Edit{% endtrans %}</a>
</div>
{% endfor %}
{% endif %}
</div>
<div id="view"><div id="placeholder"></div></div>
</div>
{% endblock %}

52
package-lock.json generated
View File

@ -11,6 +11,10 @@
"dependencies": {
"@alpinejs/sort": "^3.14.7",
"@fortawesome/fontawesome-free": "^6.6.0",
"@fullcalendar/core": "^6.1.15",
"@fullcalendar/daygrid": "^6.1.15",
"@fullcalendar/icalendar": "^6.1.15",
"@fullcalendar/list": "^6.1.15",
"@hey-api/client-fetch": "^0.4.0",
"@sentry/browser": "^8.34.0",
"@zip.js/zip.js": "^2.7.52",
@ -2384,6 +2388,39 @@
"node": ">=6"
}
},
"node_modules/@fullcalendar/core": {
"version": "6.1.15",
"resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.15.tgz",
"integrity": "sha512-BuX7o6ALpLb84cMw1FCB9/cSgF4JbVO894cjJZ6kP74jzbUZNjtwffwRdA+Id8rrLjT30d/7TrkW90k4zbXB5Q==",
"dependencies": {
"preact": "~10.12.1"
}
},
"node_modules/@fullcalendar/daygrid": {
"version": "6.1.15",
"resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.15.tgz",
"integrity": "sha512-j8tL0HhfiVsdtOCLfzK2J0RtSkiad3BYYemwQKq512cx6btz6ZZ2RNc/hVnIxluuWFyvx5sXZwoeTJsFSFTEFA==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.15"
}
},
"node_modules/@fullcalendar/icalendar": {
"version": "6.1.15",
"resolved": "https://registry.npmjs.org/@fullcalendar/icalendar/-/icalendar-6.1.15.tgz",
"integrity": "sha512-iroDc02fjxWCEYE9Lg8x+4HCJTrt04ZgDddwm0LLaWUbtx24rEcnzJP34NUx0KOTLsBjel6U/33lXvU9qDCrhg==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.15",
"ical.js": "^1.4.0"
}
},
"node_modules/@fullcalendar/list": {
"version": "6.1.15",
"resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.15.tgz",
"integrity": "sha512-U1bce04tYDwkFnuVImJSy2XalYIIQr6YusOWRPM/5ivHcJh67Gm8CIMSWpi3KdRSNKFkqBxLPkfZGBMaOcJYug==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.15"
}
},
"node_modules/@hey-api/client-fetch": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@hey-api/client-fetch/-/client-fetch-0.4.0.tgz",
@ -4162,6 +4199,12 @@
"node": ">=16.17.0"
}
},
"node_modules/ical.js": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/ical.js/-/ical.js-1.5.0.tgz",
"integrity": "sha512-7ZxMkogUkkaCx810yp0ZGKvq1ZpRgJeornPttpoxe6nYZ3NLesZe1wWMXDdwTkj/b5NtXT+Y16Aakph/ao98ZQ==",
"peer": true
},
"node_modules/import-from-esm": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-1.3.4.tgz",
@ -4924,6 +4967,15 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/preact": {
"version": "10.12.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",

View File

@ -19,7 +19,8 @@
"#openapi": "./staticfiles/generated/openapi/index.ts",
"#core:*": "./core/static/bundled/*",
"#pedagogy:*": "./pedagogy/static/bundled/*",
"#counter:*": "./counter/static/bundled/*"
"#counter:*": "./counter/static/bundled/*",
"#com:*": "./com/static/bundled/*"
},
"devDependencies": {
"@babel/core": "^7.25.2",
@ -36,6 +37,10 @@
"dependencies": {
"@alpinejs/sort": "^3.14.7",
"@fortawesome/fontawesome-free": "^6.6.0",
"@fullcalendar/core": "^6.1.15",
"@fullcalendar/daygrid": "^6.1.15",
"@fullcalendar/icalendar": "^6.1.15",
"@fullcalendar/list": "^6.1.15",
"@hey-api/client-fetch": "^0.4.0",
"@sentry/browser": "^8.34.0",
"@zip.js/zip.js": "^2.7.52",

84
poetry.lock generated
View File

@ -22,6 +22,25 @@ files = [
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
]
[[package]]
name = "arrow"
version = "1.3.0"
description = "Better dates & times for Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"},
{file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"},
]
[package.dependencies]
python-dateutil = ">=2.7.0"
types-python-dateutil = ">=2.8.10"
[package.extras]
doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"]
test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"]
[[package]]
name = "asgiref"
version = "3.8.1"
@ -51,6 +70,25 @@ files = [
astroid = ["astroid (>=2,<4)"]
test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"]
[[package]]
name = "attrs"
version = "24.3.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.8"
files = [
{file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"},
{file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"},
]
[package.extras]
benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
[[package]]
name = "babel"
version = "2.16.0"
@ -931,6 +969,24 @@ files = [
{file = "hiredis-3.1.0.tar.gz", hash = "sha256:51d40ac3611091020d7dea6b05ed62cb152bff595fa4f931e7b6479d777acf7c"},
]
[[package]]
name = "ics"
version = "0.7.2"
description = "Python icalendar (rfc5545) parser"
optional = false
python-versions = "*"
files = [
{file = "ics-0.7.2-py2.py3-none-any.whl", hash = "sha256:5fcf4d29ec6e7dfcb84120abd617bbba632eb77b097722b7df70e48dbcf26103"},
{file = "ics-0.7.2.tar.gz", hash = "sha256:6743539bca10391635249b87d74fcd1094af20b82098bebf7c7521df91209f05"},
]
[package.dependencies]
arrow = ">=0.11"
attrs = ">=19.1.0"
python-dateutil = "*"
six = ">1.5"
tatsu = ">4.2"
[[package]]
name = "identify"
version = "2.6.3"
@ -2524,6 +2580,21 @@ pure-eval = "*"
[package.extras]
tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
[[package]]
name = "tatsu"
version = "5.12.2"
description = "TatSu takes a grammar in a variation of EBNF as input, and outputs a memoizing PEG/Packrat parser in Python."
optional = false
python-versions = ">=3.11"
files = [
{file = "TatSu-5.12.2-py3-none-any.whl", hash = "sha256:9c313186ae5262662cb3fbec52c9a12db1ef752e615f46cac3eb568cb91eacf9"},
{file = "tatsu-5.12.2.tar.gz", hash = "sha256:5894dc7ddba9a1886a95ff2f06cef1be2b3d3a37c776eba8177ef4dcd80ccb03"},
]
[package.extras]
colorization = ["colorama"]
parproc = ["rich"]
[[package]]
name = "tomli"
version = "2.2.1"
@ -2580,6 +2651,17 @@ files = [
docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"]
test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"]
[[package]]
name = "types-python-dateutil"
version = "2.9.0.20241206"
description = "Typing stubs for python-dateutil"
optional = false
python-versions = ">=3.8"
files = [
{file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"},
{file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"},
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
@ -2724,4 +2806,4 @@ filelock = ">=3.4"
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "5836c1a8ad42645d7d045194c8c371754b19957ebdcd2aaa902a2fb3dc97cc53"
content-hash = "f0acbbe66fd99ac04891bcc8a5f28167a927e0b1f3677ebd8ab302a0e2fb9be2"

View File

@ -45,6 +45,7 @@ Sphinx = "^5" # Needed for building xapian
tomli = "^2.2.1"
django-honeypot = "^1.2.1"
pydantic-extra-types = "^2.10.1"
ics = "^0.7.2"
[tool.poetry.group.prod.dependencies]
# deps used in prod, but unnecessary for development

View File

@ -163,6 +163,7 @@ TEMPLATES = [
"ProductType": "counter.models.ProductType",
"timezone": "django.utils.timezone",
"get_sith": "com.views.sith",
"get_language": "django.utils.translation.get_language",
},
"bytecode_cache": {
"name": "default",

View File

@ -16,7 +16,8 @@
"#openapi": ["./staticfiles/generated/openapi/index.ts"],
"#core:*": ["./core/static/bundled/*"],
"#pedagogy:*": ["./pedagogy/static/bundled/*"],
"#counter:*": ["./counter/static/bundled/*"]
"#counter:*": ["./counter/static/bundled/*"],
"#com:*": ["./com/static/bundled/*"]
}
}
}