Updated design and backend

This commit is contained in:
Edgar P. Burkhart 2022-01-27 17:43:06 +01:00
parent b5d909f832
commit 8b9ce75959
Signed by: edpibu
GPG key ID: 9833D3C5A25BD227
7 changed files with 158 additions and 67 deletions

View file

@ -1,6 +1,7 @@
import argparse import argparse
import configparser import configparser
import logging import logging
import locale
## dev imports ## dev imports
from pprint import pp from pprint import pp
import sys import sys
@ -23,6 +24,8 @@ args = parser.parse_args()
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read(args.config) config.read(args.config)
locale.setlocale(locale.LC_ALL, config.get('locale', 'locale', fallback=None))
logging.basicConfig(level=config.get('logging', 'level', fallback='WARN')) logging.basicConfig(level=config.get('logging', 'level', fallback='WARN'))
log = logging.getLogger('saturn') log = logging.getLogger('saturn')
@ -30,7 +33,9 @@ log.info('Starting saturn')
davclient = get_davclient(config['caldav']) davclient = get_davclient(config['caldav'])
app = create_app(davclient) app = create_app(
davclient,
)
if __name__ == '__main__': if __name__ == '__main__':
app.run( app.run(

View file

@ -1,6 +1,9 @@
import re
from datetime import date, datetime, time
import caldav import caldav
from datetime import date, datetime from .event import Event
def get_davclient(config): def get_davclient(config):
@ -10,6 +13,15 @@ def get_davclient(config):
password=config.get('password', fallback=None), password=config.get('password', fallback=None),
) )
def get_comparable_dt(event):
if type(event.dtstart.value) == date:
return datetime.combine(
event.dtstart.value,
time.min,
).timestamp()
else:
return event.dtstart.value.timestamp()
def get_events(davclient): def get_events(davclient):
pri = davclient.principal() pri = davclient.principal()
@ -18,12 +30,7 @@ def get_events(davclient):
for cal in pri.calendars(): for cal in pri.calendars():
events += [event.instance.vevent events += [event.instance.vevent
for event in cal.date_search(start=date.today()) for event in cal.date_search(start=date.today())]
if type(event.instance.vevent.dtstart.value) == datetime] events.sort(key=get_comparable_dt)
events_day += [event.instance.vevent
for event in cal.date_search(start=date.today())
if type(event.instance.vevent.dtstart.value) != datetime]
events.sort(key=lambda event:event.dtstart.value)
events_day.sort(key=lambda event:event.dtstart.value)
return events, events_day return [Event(event) for event in events]

47
saturn/calendar/event.py Normal file
View file

@ -0,0 +1,47 @@
import re
class Event:
def __init__(
self,
vobject,
):
for attr in [
'dtstart',
'dtend',
'summary',
'description',
'location',
'rrule',
]:
setattr(self, f'_{attr}',
getattr(getattr(vobject, attr, None), 'value', None))
@property
def dtstart(self):
return self._dtstart
@property
def dtend(self):
return self._dtend
@property
def summary(self):
return self._summary
@property
def description(self):
return self._description
@property
def location(self):
return self._location
@property
def freq(self):
if self._rrule is None: return None
return re.search(
r'FREQ=([A-Z]+?);',
self._rrule,
).group(1)

View file

@ -4,17 +4,18 @@ from datetime import date, datetime
from ..calendar import get_events from ..calendar import get_events
def create_app(davclient): def create_app(
davclient,
):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@app.route('/') @app.route('/')
def home(): def home():
events, events_day = get_events(davclient) events = get_events(davclient)
return flask.render_template( return flask.render_template(
'index.html', 'index.html',
events = events, events = events,
events_day = events_day,
) )
return app return app

View file

@ -1,7 +1,6 @@
body { body {
display: grid; display: grid;
grid-template-columns: grid-template-columns:
1fr
1fr; 1fr;
grid-template-rows: grid-template-rows:
auto auto
@ -22,13 +21,10 @@ body > * {
margin: 1rem; margin: 1rem;
display: grid; display: grid;
grid-template-columns: grid-template-columns:
1fr 6rem
1fr; 1fr;
grid-template-rows: row-gap: .5rem;
auto column-gap: 1rem;
auto
auto;
gap: .5rem;
background: var(--ui-01); background: var(--ui-01);
padding: 1rem; padding: 1rem;
} }
@ -39,23 +35,33 @@ body > * {
grid-column: 1 / span 2; grid-column: 1 / span 2;
} }
.event > .date { .event > .date {
grid-row: 2; grid-column: 1;
font-size: 1.1rem; font-size: 1.1rem;
display: grid;
grid-template-columns: auto;
gap: 1rem;
text-align: center;
} }
.event > .start-date { .event > .date > div {
grid-column: 1; display: grid;
text-align: right; grid-template-columns: auto;
} }
.event > .end-date { .date .day {
font-size: 3em;
}
.date .time {
font-size: 1.5em;
}
.event .end-date,
.event .other {
color: var(--text-02);
}
.event > .info {
grid-column: 2; grid-column: 2;
} display: grid;
.event > .description { grid-template-columns: 1fr;
grid-column: 1; grid-template-rows:
} 1fr
.event > .other { auto;
grid-column: 2; gap: 1rem;
}
.event > .description,
.event > .other > * {
padding-top: 1rem;
} }

View file

@ -2,8 +2,10 @@
--ui-background: white; --ui-background: white;
--ui-01: var(--gray-10); --ui-01: var(--gray-10);
--text-01: var(--gray-100); --text-01: var(--gray-100);
--text-02: var(--gray-70);
--gray-10: #f4f4f4; --gray-10: #f4f4f4;
--gray-70: #525252;
--gray-100: #161616; --gray-100: #161616;
} }

View file

@ -3,6 +3,7 @@
{% block style %} {% block style %}
{{ super() }} {{ super() }}
<link rel="stylesheet" href="/static/css/index.css" /> <link rel="stylesheet" href="/static/css/index.css" />
<link href="https://cdn.jsdelivr.net/npm/remixicon/fonts/remixicon.css" rel="stylesheet">
{% endblock %} {% endblock %}
{% block body %} {% block body %}
@ -11,41 +12,63 @@
<div id="events"> <div id="events">
{% for event in events %} {% for event in events %}
<div class="event"> <div class="event">
<div class="summary">{{ event.summary.value }}</div> <div class="summary">{{ event.summary }}</div>
<div class="date start-date">{{ event.dtstart.value.isoformat() }}</div> <div class="date">
<div class="date end-date">{{ event.dtend.value.isoformat() }}</div> <div class="start-date">
{% if event.description %} <span class="weekday">
<div class="description">{{ event.description.value }}</div> {{ event.dtstart.strftime('%A').capitalize() }}
</span>
<span class="day">
{{ event.dtstart.strftime('%d') }}
</span>
<span class="month">
{{ event.dtstart.strftime('%B').capitalize() }}
</span>
<span class="time">
{{ event.dtstart.strftime('%H:%M') }}
</span>
</div>
<div class="end-date">
{% if not event.dtend.date or event.dtend.date() != event.dtstart.date() %}
<span class="weekday">
{{ event.dtend.strftime('%A').capitalize() }}
</span>
<span class="day">
{{ event.dtend.strftime('%d') }}
</span>
{% endif %} {% endif %}
<div class="other"> {% if event.dtend.month != event.dtstart.month %}
{% if event.location %} <span class="month">
<div>{{ event.location.value }}</div> {{ event.dtend.strftime('%B').capitalize() }}
{% endif %} </span>
{% if event.rrule %}
<div>{{ event.rrule.value }}</div>
{% endif %} {% endif %}
<span class="time">
{{ event.dtend.strftime('%H:%M') }}
</span>
</div> </div>
</div> </div>
{% endfor %} <div class="info">
</div> <div class="description">
<div id="events_day">
{% for event in events_day %}
<div class="event">
<div class="summary">{{ event.summary.value }}</div>
<div class="date start-date">{{ event.dtstart.value }}</div>
<div class="date end-date">{{ event.dtend.value }}</div>
{% if event.description %} {% if event.description %}
<div class="description">{{ event.description.value }}</div> {{ event.description }}
{% endif %} {% endif %}
</div>
<div class="other"> <div class="other">
{% if event.location %} {% if event.location %}
<div>{{ event.location.value }}</div> <div>
<i class="ri-map-pin-line ri-fw ri-sm"></i>
{{ event.location }}
</div>
{% endif %} {% endif %}
{% if event.rrule %} {% if event.freq %}
<div>{{ event.rrule.value }}</div> <div>
<i class="ri-repeat-line ri-fw ri-sm"></i>
{{ event.freq}}
</div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div>
{% endfor %} {% endfor %}
</div> </div>
{% endblock %} {% endblock %}