diff --git a/com/api.py b/com/api.py new file mode 100644 index 00000000..64f375fd --- /dev/null +++ b/com/api.py @@ -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", + ) diff --git a/com/static/bundled/com/components/ics-calendar-index.ts b/com/static/bundled/com/components/ics-calendar-index.ts new file mode 100644 index 00000000..f88b9b0f --- /dev/null +++ b/com/static/bundled/com/components/ics-calendar-index.ts @@ -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(); + } +} diff --git a/com/static/com/components/ics-calendar.scss b/com/static/com/components/ics-calendar.scss new file mode 100644 index 00000000..bb858dd5 --- /dev/null +++ b/com/static/com/components/ics-calendar.scss @@ -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; +} \ No newline at end of file diff --git a/com/static/com/css/news-detail.scss b/com/static/com/css/news-detail.scss new file mode 100644 index 00000000..0a07e62d --- /dev/null +++ b/com/static/com/css/news-detail.scss @@ -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; +} \ No newline at end of file diff --git a/com/static/com/css/news-list.scss b/com/static/com/css/news-list.scss new file mode 100644 index 00000000..a33e6315 --- /dev/null +++ b/com/static/com/css/news-list.scss @@ -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; + } +} \ No newline at end of file diff --git a/com/static/com/css/posters.scss b/com/static/com/css/posters.scss new file mode 100644 index 00000000..26cf2b91 --- /dev/null +++ b/com/static/com/css/posters.scss @@ -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%; + } + } + } +} \ No newline at end of file diff --git a/com/templates/com/news_detail.jinja b/com/templates/com/news_detail.jinja index cbfa596c..238515ed 100644 --- a/com/templates/com/news_detail.jinja +++ b/com/templates/com/news_detail.jinja @@ -11,6 +11,11 @@ {{ gen_news_metatags(news) }} {% endblock %} + +{% block additional_css %} + +{% endblock %} + {% block content %}

{% trans %}Back to news{% endtrans %}

diff --git a/com/templates/com/news_list.jinja b/com/templates/com/news_list.jinja index ac9a7892..3f2444f1 100644 --- a/com/templates/com/news_list.jinja +++ b/com/templates/com/news_list.jinja @@ -5,6 +5,15 @@ {% trans %}News{% endtrans %} {% endblock %} +{% block additional_css %} + + +{% endblock %} + +{% block additional_js %} + +{% endblock %} + {% block content %} {% if user.is_com_admin %}
@@ -98,16 +107,6 @@ type="EVENT").order_by('dates__start_date') %} {% endfor %} {% endif %} -

{% trans %}All coming events{% endtrans %}

- -
-
{% trans %}Agenda{% endtrans %}
@@ -154,8 +153,14 @@ type="EVENT").order_by('dates__start_date') %} {%- endif -%}
+ +

{% trans %}All coming events{% endtrans %}

+ + + + {% endblock %} diff --git a/com/templates/com/poster_list.jinja b/com/templates/com/poster_list.jinja index 8c4f5cd1..c9af62c0 100644 --- a/com/templates/com/poster_list.jinja +++ b/com/templates/com/poster_list.jinja @@ -10,6 +10,10 @@ {% trans %}Poster{% endtrans %} {% endblock %} +{% block additional_css %} + +{% endblock %} + {% block content %}
diff --git a/com/templates/com/poster_moderate.jinja b/com/templates/com/poster_moderate.jinja index 36e3dae7..6370becf 100644 --- a/com/templates/com/poster_moderate.jinja +++ b/com/templates/com/poster_moderate.jinja @@ -5,6 +5,10 @@ {% endblock %} +{% block additional_css %} + +{% endblock %} + {% block content %}
diff --git a/core/management/commands/populate.py b/core/management/commands/populate.py index 0a26b4b8..6613fb14 100644 --- a/core/management/commands/populate.py +++ b/core/management/commands/populate.py @@ -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", diff --git a/core/static/core/devices.scss b/core/static/core/devices.scss new file mode 100644 index 00000000..25839f24 --- /dev/null +++ b/core/static/core/devices.scss @@ -0,0 +1,5 @@ +/*--------------------------MEDIA QUERY HELPERS------------------------*/ + +$small-devices: 576px; +$medium-devices: 768px; +$large-devices: 992px; \ No newline at end of file diff --git a/core/static/core/style.scss b/core/static/core/style.scss index a9205e23..2f3af9f7 100644 --- a/core/static/core/style.scss +++ b/core/static/core/style.scss @@ -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 { diff --git a/core/templates/core/poster_list.jinja b/core/templates/core/poster_list.jinja deleted file mode 100644 index fe65658c..00000000 --- a/core/templates/core/poster_list.jinja +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "core/base.jinja" %} - -{% block script %} - {{ super() }} - -{% endblock %} - - -{% block title %} - {% trans %}Poster{% endtrans %} -{% endblock %} - -{% block content %} -
- -
-

{% trans %}Posters{% endtrans %}

- -
- -
- - {% if poster_list.count() == 0 %} -
{% trans %}No posters{% endtrans %}
- {% else %} - - {% for poster in poster_list %} -
-
{{ 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/package-lock.json b/package-lock.json index 9b49ac0e..bfa05f40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 9721eea4..379fc782 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/poetry.lock b/poetry.lock index 311df18a..3c4c08b0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -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" diff --git a/pyproject.toml b/pyproject.toml index be892cdf..f3427faf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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 diff --git a/sith/settings.py b/sith/settings.py index 5fdc3786..a88734d3 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -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", diff --git a/tsconfig.json b/tsconfig.json index 7b3be5fc..aaee9330 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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/*"] } } }