Improve sidebar embed look and feel
This commit is contained in:
parent
05f985d611
commit
cba66c794e
@ -1,4 +1,31 @@
|
||||
import re
|
||||
|
||||
from jinja2 import pass_eval_context
|
||||
from markupsafe import Markup, escape
|
||||
from starlette.templating import Jinja2Templates
|
||||
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
|
||||
@pass_eval_context
|
||||
def nl2br(eval_ctx, value):
|
||||
br = "<br>\n"
|
||||
|
||||
if eval_ctx.autoescape:
|
||||
value = escape(value)
|
||||
br = Markup(br)
|
||||
|
||||
result = "\n\n".join(
|
||||
# need to convert p to Markup again after applying re.split(...)
|
||||
f"<p>{br.join(Markup(p).splitlines())}</p>"
|
||||
for p in re.split(r"(?:\r\n|\r(?!\n)|\n){2,}", value)
|
||||
)
|
||||
|
||||
if eval_ctx.autoescape:
|
||||
result = Markup(result)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
templates.env.filters["nl2br"] = nl2br
|
||||
|
@ -8,7 +8,7 @@ router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/events.ics")
|
||||
async def events():
|
||||
async def events_ics():
|
||||
return Response(
|
||||
await get_data(),
|
||||
headers={
|
||||
|
@ -15,8 +15,7 @@ from fabcal.routers import templates
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/embed-sidebar.html", response_class=HTMLResponse)
|
||||
async def embed(request: Request, max_width: str = None):
|
||||
async def generate_response(request: Request, template_name: str, **additional_context):
|
||||
events = await get_future_events()
|
||||
|
||||
grouped_events = list(group_by_date(events).items())
|
||||
@ -32,8 +31,19 @@ async def embed(request: Request, max_width: str = None):
|
||||
def base64_encode(s: str):
|
||||
return base64.b64encode(s.encode()).decode()
|
||||
|
||||
context = {
|
||||
"request": request,
|
||||
"grouped_events": grouped_events,
|
||||
"dir": dir,
|
||||
"localized_abbreviated_month": localized_abbreviated_month,
|
||||
"localized_abbreviated_weekday": localized_abbreviated_weekday,
|
||||
"base64_encode": base64_encode,
|
||||
}
|
||||
|
||||
context.update(additional_context)
|
||||
|
||||
return templates.TemplateResponse(
|
||||
"embed-sidebar.html",
|
||||
template_name,
|
||||
context={
|
||||
"request": request,
|
||||
"grouped_events": grouped_events,
|
||||
@ -43,3 +53,8 @@ async def embed(request: Request, max_width: str = None):
|
||||
"base64_encode": base64_encode,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.get("/sidebar/embed.html", response_class=HTMLResponse)
|
||||
async def embed_sidebar(request: Request):
|
||||
return await generate_response(request, "sidebar/embed.html")
|
||||
|
@ -26,7 +26,6 @@ body {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-direction: row;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.calendar-date-date {
|
||||
@ -36,6 +35,7 @@ body {
|
||||
margin-right: 8px;
|
||||
flex: 35px 0 0;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
}
|
||||
.calendar-date-month {
|
||||
background-color: var(--calendar-fablab-red);
|
||||
@ -96,6 +96,12 @@ body {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.calendar-event-description p {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.calendar-event-description p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.calendar-event-type {
|
||||
flex: 0 0 12px;
|
||||
margin: -5px -5px -5px 0;
|
||||
|
@ -1,68 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
{#- TODO: replace with locally served files #}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
|
||||
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='style.css') }}" type="text/css"/>
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='roboto.css') }}" type="text/css"/>
|
||||
<title>Embeddable calendar</title>
|
||||
</head>
|
||||
|
||||
<body{% if max_width %} style="max-width: {{ max_width }}"{% endif %}>
|
||||
<div class="calendar">
|
||||
{% for start_date, events in grouped_events[:3] %}
|
||||
<div class="calendar-date">
|
||||
<div class="calendar-date-date">
|
||||
<div class="calendar-date-month">
|
||||
{{ start_date.strftime("%b") }}
|
||||
</div>
|
||||
<div class="calendar-date-day">
|
||||
{{ start_date.strftime("%d") }}
|
||||
</div>
|
||||
<div class="calendar-date-weekday">
|
||||
{{ start_date.strftime("%a") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="calendar-events">
|
||||
{% for event in events %}
|
||||
<div class="calendar-event" title="{{ event.summary }}{% if event.description %} — {{ event.description }}{% endif %}">
|
||||
<div class="calendar-event-time">
|
||||
<div class="calendar-event-starttime">{{ event.start.strftime("%H:%M") }}</div>
|
||||
<div class="calendar-event-timesep"></div>
|
||||
<div class="calendar-event-endtime">{{ event.end.strftime("%H:%M") }}</div>
|
||||
</div>
|
||||
<div class="calendar-event-description">
|
||||
{% if event.description or event.location %}
|
||||
<details class="calendar-event-details">
|
||||
<summary>{{ event.summary }}</summary>
|
||||
<div class="calendar-popover-content">
|
||||
{% if event.description %}
|
||||
<div class="calendar-popover-entry">
|
||||
{#- description doesn't need an icon, just wastes space #}
|
||||
<div class="calendar-popover-entry-text">{{ event.description }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if event.location %}
|
||||
<div class="calendar-popover-entry">
|
||||
<div class="calendar-popover-entry-icon"><i class="fa-solid fa-location-dot"></i></div>
|
||||
<div class="calendar-popover-entry-text">{{ event.location }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</details>
|
||||
{% else %}
|
||||
<span>{{ event.summary }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="calendar-event-type" style="background-color: {{ event.color }};"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
21
templates/sidebar/base.html
Normal file
21
templates/sidebar/base.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
{% block header %}
|
||||
{#- TODO: replace with locally served files #}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
|
||||
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='style.css') }}" type="text/css"/>
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='roboto.css') }}" type="text/css"/>
|
||||
|
||||
<title>Embeddable calendar</title>
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
21
templates/sidebar/embed.html
Normal file
21
templates/sidebar/embed.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
{#- TODO: replace with locally served files #}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
|
||||
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='style.css') }}" type="text/css"/>
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='roboto.css') }}" type="text/css"/>
|
||||
<title>Embeddable calendar</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="calendar">
|
||||
{% include "sidebar/includes/header.html" %}
|
||||
{% include "sidebar/includes/events-list.html" %}
|
||||
{% include "sidebar/includes/footer.html" %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
57
templates/sidebar/includes/events-list.html
Normal file
57
templates/sidebar/includes/events-list.html
Normal file
@ -0,0 +1,57 @@
|
||||
{% for start_date, events in grouped_events %}
|
||||
<div class="calendar-date">
|
||||
<div class="calendar-date-date">
|
||||
<div class="calendar-date-month">
|
||||
{{ start_date.strftime("%b") }}
|
||||
</div>
|
||||
<div class="calendar-date-day">
|
||||
{{ start_date.strftime("%d") }}
|
||||
</div>
|
||||
<div class="calendar-date-weekday">
|
||||
{{ start_date.strftime("%a") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="calendar-events">
|
||||
{% for event in events %}
|
||||
<div class="calendar-event" title="{{ event.summary }}{% if event.description %} — {{ event.description }}{% endif %}">
|
||||
<div class="calendar-event-time">
|
||||
<div class="calendar-event-starttime">{{ event.start.strftime("%H:%M") }}</div>
|
||||
<div class="calendar-event-timesep"></div>
|
||||
<div class="calendar-event-endtime">{{ event.end.strftime("%H:%M") }}</div>
|
||||
</div>
|
||||
<div class="calendar-event-description">
|
||||
{% if event.description or event.location %}
|
||||
<details class="calendar-event-details">
|
||||
<summary>{{ event.summary | urlize }}</summary>
|
||||
<div class="calendar-popover-content">
|
||||
{% if event.description %}
|
||||
<div class="calendar-popover-entry">
|
||||
{#- description doesn't need an icon, just wastes space #}
|
||||
<div class="calendar-popover-entry-text">{{ event.description | urlize | nl2br }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if event.location %}
|
||||
<div class="calendar-popover-entry">
|
||||
<div class="calendar-popover-entry-icon"><i class="fa-solid fa-location-dot"></i></div>
|
||||
<div class="calendar-popover-entry-text">{{ event.location | urlize | nl2br }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</details>
|
||||
{% else %}
|
||||
<span>{{ event.summary }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{%- if "AusbauLab" in event.categories %}
|
||||
<div class="calendar-event-type calendar-event-type-ausbau"></div>
|
||||
{%- elif event.color %}
|
||||
<div class="calendar-event-type" style="background-color: {{ event.color }};"></div>
|
||||
{%- else %}
|
||||
<div class="calendar-event-type calendar-event-type-unknown"></div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
3
templates/sidebar/includes/footer.html
Normal file
3
templates/sidebar/includes/footer.html
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="calendar-subscription-buttons">
|
||||
<a href="{{ url_for('events_ics') }}"><i class="fa-solid fa-calendar"></i> Kalender abonnieren</a>
|
||||
</div>
|
1
templates/sidebar/includes/header.html
Normal file
1
templates/sidebar/includes/header.html
Normal file
@ -0,0 +1 @@
|
||||
<h3>Veranstaltungen</h3>
|
Loading…
Reference in New Issue
Block a user