From f6c619bd23f29df322aae27c058971ed8890350c Mon Sep 17 00:00:00 2001 From: Aviad Amar Date: Fri, 15 Jan 2021 22:09:28 +0100 Subject: [PATCH 01/42] Hello Wrold --- .gitignore | 3 +++ app/main.py | 13 ++++++++++--- app/static/style.css | 16 ++++++++++++++++ app/templates/home.html | 11 ----------- 4 files changed, 29 insertions(+), 14 deletions(-) delete mode 100644 app/templates/home.html diff --git a/.gitignore b/.gitignore index b6e47617..1ffc615e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ __pycache__/ # Distribution / packaging .Python build/ +Scripts/ +include/ develop-eggs/ dist/ downloads/ @@ -26,6 +28,7 @@ share/python-wheels/ .installed.cfg *.egg MANIFEST +pyvenv.cfg # PyInstaller # Usually these files are written by a python script from a template diff --git a/app/main.py b/app/main.py index dfbf4ca2..8431a58f 100644 --- a/app/main.py +++ b/app/main.py @@ -1,15 +1,22 @@ +import uvicorn from fastapi import FastAPI, Request from fastapi.templating import Jinja2Templates - +from fastapi.staticfiles import StaticFiles app = FastAPI() +app.mount("/static", StaticFiles(directory="static"), name="static") + templates = Jinja2Templates(directory="templates") @app.get("/") -def home(request: Request): - return templates.TemplateResponse("home.html", { +async def home(request: Request): + return templates.TemplateResponse("home.j2", { "request": request, "message": "Hello, World!" }) + + +if __name__ == "__main__": + uvicorn.run(app) diff --git a/app/static/style.css b/app/static/style.css index e69de29b..c695452d 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -0,0 +1,16 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + font-family: "Assistant", sans-serif; + font-weight: 400; + font-size: 62.5%; /*16px / 10px = 62.5% -> 1rem = 10px*/ + line-height: 1.7; +} + +body { + background-color: red; +} diff --git a/app/templates/home.html b/app/templates/home.html deleted file mode 100644 index 81fece4f..00000000 --- a/app/templates/home.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - Calendar - - - {{message}} - - \ No newline at end of file From 1ee94e44665cd7c056fa7728582b6dd9777c228d Mon Sep 17 00:00:00 2001 From: Aviad Amar Date: Fri, 15 Jan 2021 22:16:49 +0100 Subject: [PATCH 02/42] Creating Html Template --- app/templates/home.j2 | 5 +++++ app/templates/layout.j2 | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 app/templates/home.j2 create mode 100644 app/templates/layout.j2 diff --git a/app/templates/home.j2 b/app/templates/home.j2 new file mode 100644 index 00000000..8ceb43be --- /dev/null +++ b/app/templates/home.j2 @@ -0,0 +1,5 @@ +{% extends 'layout.j2' %} + +{% block body %} +

{{message}}

+{% endblock %} \ No newline at end of file diff --git a/app/templates/layout.j2 b/app/templates/layout.j2 new file mode 100644 index 00000000..fa266955 --- /dev/null +++ b/app/templates/layout.j2 @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + Calendar + + + + {% block body %} + {% endblock %} + + + \ No newline at end of file From 82249b571c0764d3fc4a546b24cdb72b45be0bff Mon Sep 17 00:00:00 2001 From: Aviad Amar Date: Sun, 17 Jan 2021 01:54:16 +0100 Subject: [PATCH 03/42] Calendar dates calculation intigrating with html, HTML\CSS improvments. --- app/List[List] | 0 app/List[int] | 0 app/calendar_grid.py | 58 ++++++++++++++++++++++++++++-------- app/main.py | 18 ++++++----- app/static/style.css | 6 ---- app/templates/monthview.html | 37 ++++++++++------------- 6 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 app/List[List] create mode 100644 app/List[int] diff --git a/app/List[List] b/app/List[List] new file mode 100644 index 00000000..e69de29b diff --git a/app/List[int] b/app/List[int] new file mode 100644 index 00000000..e69de29b diff --git a/app/calendar_grid.py b/app/calendar_grid.py index d75cdd56..69636a3c 100644 --- a/app/calendar_grid.py +++ b/app/calendar_grid.py @@ -1,17 +1,51 @@ -from calendar import monthrange -from typing import Tuple -from datetime import datetime +import calendar +import datetime +from typing import List, Tuple -DAYS_OF_THE_WEEK = ['Monday', 'Tuesday', 'Wednesday', - 'Thursday', 'Friday', 'Saturday', 'Sunday'] +DAYS_OF_THE_WEEK: List[str] = ['Monday', 'Tuesday', 'Wednesday', + 'Thursday', 'Friday', 'Saturday', 'Sunday'] -def get_day_name(date: datetime) -> Tuple[str, int]: - """Returns the name of a day for a given date and its numeric value""" - day = date.weekday() - return DAYS_OF_THE_WEEK[day], day +def get_date_as_string(date: datetime) -> str: + return date.strftime("%A %B %b %Y").split() -def get_month_days(year: int, month: int) -> Tuple[int, int]: - """Returns the first and last day in a given month and year.""" - return monthrange(year, month) +def get_next_date(date): + """Generate date objects from a starting given date.""" + while True: + next_day = date + datetime.timedelta(days=1) + yield next_day + date = next_day + + +def get_day_n_before(date: datetime, n: int) -> datetime: + return date - datetime.timedelta(days=n) + + +def get_n_days(date: datetime, n: int) -> List[datetime]: + g = get_next_date(date) + days = [] + for day in range(n): + days.append(next(g)) + return days + + +def arrange_weeks(dates: List, n: int) -> List[List]: + """Returns a list of lists with length of n for a given list""" + weeks = [] + week = [] + for day in dates: + if len(week) > 0 and len(week) % n - 1 == 0: + week.append(day) + weeks.append(week) + week = [] + else: + week.append(day) + return weeks + + +def get_month_block(date) -> List[List]: + days = calendar.monthrange(date.year, date.month) + before = get_day_n_before(date, days[0] + 1) + cal = get_n_days(before, 1000) + return arrange_weeks(cal, 7) diff --git a/app/main.py b/app/main.py index 8d8c70b3..d110b9f4 100644 --- a/app/main.py +++ b/app/main.py @@ -1,15 +1,14 @@ +import datetime + import uvicorn from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates -from datetime import datetime -import calendar_grid +import calendar_grid app = FastAPI() - app.mount("/static", StaticFiles(directory="static"), name="static") - templates = Jinja2Templates(directory="templates") @@ -23,15 +22,18 @@ def home(request: Request): @app.get("/monthview") async def monthview(request: Request): - date = datetime.now() + date = datetime.date.today() return templates.TemplateResponse("monthview.html", { "request": request, - "dates": { + "calendar": { 'date': date, - 'month_days': calendar_grid.get_month_days(date.year, date.month), + 'strf_date': calendar_grid.get_date_as_string(date), 'days_of_the_week': calendar_grid.DAYS_OF_THE_WEEK, - 'day': calendar_grid.get_day_name(date), + 'month_block': calendar_grid.get_month_block( + datetime.date(date.year, date.month, 1) + ) }}) + if __name__ == "__main__": uvicorn.run(app) diff --git a/app/static/style.css b/app/static/style.css index 6c640c16..b2206ae8 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -45,18 +45,12 @@ nav { grid-row: 1/3; font-size: 2.8rem; padding-left: 0.5rem; - transition: width 1s; - position: relative; } .menu div:hover { color: #FFDE4D; } -nav:hover { - width: 40rem; - text-align: left; -} .menu { position: sticky; diff --git a/app/templates/monthview.html b/app/templates/monthview.html index e5a5e36c..f3f96661 100644 --- a/app/templates/monthview.html +++ b/app/templates/monthview.html @@ -21,19 +21,20 @@
-
10 OCTOBER 2021
+
{{calendar['date'].day}} {{ calendar['strf_date'][1].upper() }} {{calendar['date'].year + }}
Milano 4 oc
Search
Month
- {% for day in dates['days_of_the_week'] %} - {% if day == dates['day'][0] %} + {% for day in calendar['days_of_the_week'] %} + {% if day == calendar['strf_date'][0] %}
{{ day.upper() }}
{% else %}
{{ day.upper() }}
@@ -44,37 +45,29 @@

PYLENDER

- {% for month in range(dates['date'].month, dates['date'].month + 2) %} - {% for day in range(dates['month_days'][0], dates['month_days'][1] + 1) %} - {% if day == dates['date'].day and month == dates['date'].month %} + {% for week in calendar['month_block'] %} + {% for i in range(week|length) %} + {% if week[i] == calendar['date'] %}
-
{{day}}
+
{{week[i].day}}
daily event
6PM Meeting with Ode
9PM Meeting with Michele
- {% elif day in (9, 10, 17, 23, 24, 30, 31) %} -
-
{{day}}
-
- {% elif day in (13, 29) %} + {% elif week[i].day == 1 %}
-
{{day}}
+
{{week[i].strftime('%A %b %y')}}
daily event
6PM Meeting with yam
7PM Meeting with Sagi
- - {% elif day in (18, ) %} -
-
{{day}}
-
daily event
-
6PM Meeting with yam
-
7PM Meeting with Sagi
+ {% elif i in (5, 6) and not (week[i] == calendar['date']) %} +
+
{{week[i].day}}
{% else %}
-
{{day}}
+
{{week[i].day}}
{% endif %} {% endfor %} From 178e9049991cd0cc043d40eb43faa58e869581ea Mon Sep 17 00:00:00 2001 From: Aviad Amar Date: Sun, 17 Jan 2021 17:52:54 +0100 Subject: [PATCH 04/42] Tests for calender_grid.py, changing function according to currections, fixing bugs --- app/List[List] | 0 app/List[int] | 0 app/calendar_grid.py | 51 ------------------------------- app/main.py | 22 +++++++++++--- app/routers/calendar_grid.py | 47 +++++++++++++++++++++++++++++ app/templates/monthview.html | 2 +- requirements.txt | 2 ++ tests/conftest.py | 8 +++++ tests/test_calender_grid.py | 58 ++++++++++++++++++++++++++++++++++++ 9 files changed, 134 insertions(+), 56 deletions(-) delete mode 100644 app/List[List] delete mode 100644 app/List[int] delete mode 100644 app/calendar_grid.py create mode 100644 app/routers/calendar_grid.py create mode 100644 tests/conftest.py create mode 100644 tests/test_calender_grid.py diff --git a/app/List[List] b/app/List[List] deleted file mode 100644 index e69de29b..00000000 diff --git a/app/List[int] b/app/List[int] deleted file mode 100644 index e69de29b..00000000 diff --git a/app/calendar_grid.py b/app/calendar_grid.py deleted file mode 100644 index 69636a3c..00000000 --- a/app/calendar_grid.py +++ /dev/null @@ -1,51 +0,0 @@ -import calendar -import datetime -from typing import List, Tuple - -DAYS_OF_THE_WEEK: List[str] = ['Monday', 'Tuesday', 'Wednesday', - 'Thursday', 'Friday', 'Saturday', 'Sunday'] - - -def get_date_as_string(date: datetime) -> str: - return date.strftime("%A %B %b %Y").split() - - -def get_next_date(date): - """Generate date objects from a starting given date.""" - while True: - next_day = date + datetime.timedelta(days=1) - yield next_day - date = next_day - - -def get_day_n_before(date: datetime, n: int) -> datetime: - return date - datetime.timedelta(days=n) - - -def get_n_days(date: datetime, n: int) -> List[datetime]: - g = get_next_date(date) - days = [] - for day in range(n): - days.append(next(g)) - return days - - -def arrange_weeks(dates: List, n: int) -> List[List]: - """Returns a list of lists with length of n for a given list""" - weeks = [] - week = [] - for day in dates: - if len(week) > 0 and len(week) % n - 1 == 0: - week.append(day) - weeks.append(week) - week = [] - else: - week.append(day) - return weeks - - -def get_month_block(date) -> List[List]: - days = calendar.monthrange(date.year, date.month) - before = get_day_n_before(date, days[0] + 1) - cal = get_n_days(before, 1000) - return arrange_weeks(cal, 7) diff --git a/app/main.py b/app/main.py index d110b9f4..3449a0e9 100644 --- a/app/main.py +++ b/app/main.py @@ -5,7 +5,7 @@ from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates -import calendar_grid +import routers.calendar_grid app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") @@ -20,6 +20,20 @@ def home(request: Request): }) +@app.get("/profile") +def profile(request: Request): + + # Get relevant data from database + upcouming_events = range(5) + current_username = "Chuck Norris" + + return templates.TemplateResponse("profile.html", { + "request": request, + "username": current_username, + "events": upcouming_events + }) + + @app.get("/monthview") async def monthview(request: Request): date = datetime.date.today() @@ -27,9 +41,9 @@ async def monthview(request: Request): "request": request, "calendar": { 'date': date, - 'strf_date': calendar_grid.get_date_as_string(date), - 'days_of_the_week': calendar_grid.DAYS_OF_THE_WEEK, - 'month_block': calendar_grid.get_month_block( + 'strf_date': routers.calendar_grid.get_date_as_string(date), + 'days_of_the_week': routers.calendar_grid.DAYS_OF_THE_WEEK, + 'month_block': routers.calendar_grid.get_month_block( datetime.date(date.year, date.month, 1) ) }}) diff --git a/app/routers/calendar_grid.py b/app/routers/calendar_grid.py new file mode 100644 index 00000000..1b8ea0f2 --- /dev/null +++ b/app/routers/calendar_grid.py @@ -0,0 +1,47 @@ +import calendar +import itertools +from datetime import datetime, timedelta + +from typing import Any, Iterator, Generator, List, Tuple + +DAYS_OF_THE_WEEK: List[str] = ['Monday', 'Tuesday', 'Wednesday', + 'Thursday', 'Friday', 'Saturday', 'Sunday'] +CALENDAR = calendar.Calendar(0) + + +def get_date_as_string(date: datetime) -> List[str]: + """Returns list represent date as string.""" + return date.strftime("%A %B %b %Y").split() + + +def get_next_date(date: datetime) -> Generator[datetime, None, None]: + """Generate date objects from a starting given date.""" + yield from (date + timedelta(days=i) for i in itertools.count(start=1)) + + +def get_date_before_n_days(date: datetime, n: int) -> datetime: + """Returns the date before n days.""" + return date - timedelta(days=n) + + +def get_first_day_month_block(date): + return list(CALENDAR.itermonthdates(date.year, date.month))[0] + + +def get_n_days(date: datetime, n: int) -> Iterator[datetime]: + """Generate n dates from a starting given date.""" + next_date_gen = get_next_date(date) + yield from itertools.islice(next_date_gen, n) + + +def split_list_to_lists(dates: List[Any], length: int) -> List[List[Any]]: + """Return a 2D list with inner lists length of given size.""" + return [dates[i:i + length] for i in range(0, len(dates), length)] + + +def get_month_block(date: datetime, n: int = 100) -> List[List]: + """Returns a 2D list represent a n days calendar from current month.""" + start = get_first_day_month_block(date) + cal = list(get_n_days(start, n)) + cal.insert(0, start) + return split_list_to_lists(cal, 7) diff --git a/app/templates/monthview.html b/app/templates/monthview.html index f3f96661..c585a1cc 100644 --- a/app/templates/monthview.html +++ b/app/templates/monthview.html @@ -56,7 +56,7 @@

PYLENDAR

{% elif week[i].day == 1 %}
-
{{week[i].strftime('%A %b %y')}}
+
{{week[i].strftime('%d %b %y')}}
daily event
6PM Meeting with yam
7PM Meeting with Sagi
diff --git a/requirements.txt b/requirements.txt index ffed4ae5..84a07740 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ atomicwrites==1.4.0 attrs==20.3.0 click==7.1.2 colorama==0.4.4 +coverage==5.3.1 fastapi==0.63.0 h11==0.12.0 h2==4.0.0 @@ -19,6 +20,7 @@ py==1.10.0 pydantic==1.7.3 pyparsing==2.4.7 pytest==6.2.1 +pytest-cov==2.10.1 SQLAlchemy==1.3.22 starlette==0.13.6 toml==0.10.2 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..213dd07c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,8 @@ +import calendar + +import pytest + + +@pytest.fixture +def Calendar(): + return calendar.Calendar(0) diff --git a/tests/test_calender_grid.py b/tests/test_calender_grid.py new file mode 100644 index 00000000..1b4e4860 --- /dev/null +++ b/tests/test_calender_grid.py @@ -0,0 +1,58 @@ +import datetime + +from app.routers.calendar_grid import (get_date_as_string, get_date_before_n_days, + get_first_day_month_block, get_month_block, + get_n_days, get_next_date, split_list_to_lists) + +DATE = datetime.date(1988, 5, 3) +N_DAYS = 3 +N_DAYS_BEFORE = datetime.date(1988, 4, 30) +NEXT_N_DAYS = [ + datetime.date(1988, 5, 4), + datetime.date(1988, 5, 5), + datetime.date(1988, 5, 6) +] + + +class TestCalendarGrid: + + @staticmethod + def test_get_date_as_string(): + assert get_date_as_string(DATE) == [ + 'Tuesday', 'May', 'May', '1988'] + + @staticmethod + def test_get_next_date(): + next_day = DATE + datetime.timedelta(days=1) + next_day_generator = get_next_date(DATE) + assert next(next_day_generator) == next_day + + @staticmethod + def test_get_date_before_n_days(): + assert get_date_before_n_days(DATE, N_DAYS) == N_DAYS_BEFORE + + @staticmethod + def test_get_n_days(): + next_n_dates = get_n_days(DATE, N_DAYS) + for i in range(N_DAYS): + assert next(next_n_dates) == NEXT_N_DAYS[i] + + @staticmethod + def test_get_first_day_month_block(Calendar): + assert get_first_day_month_block( + DATE) == list(Calendar.itermonthdates(DATE.year, DATE.month))[0] + + @staticmethod + def test_split_list_to_lists(): + sub_length = 7 + total_length = 20 + list_before_split = list(range(total_length)) + list_after_split = [list_before_split[i: i + sub_length] + for i in range(0, len(list_before_split), sub_length)] + assert split_list_to_lists( + list_before_split, sub_length) == list_after_split + + @staticmethod + def test_get_month_block(Calendar): + test = split_list_to_lists(list(Calendar.itermonthdates(1988, 5)), 7) + assert get_month_block(DATE, n=41) == test From f385c56a412b8f8a1e42adcc8a7488ab3d90a651 Mon Sep 17 00:00:00 2001 From: Aviad Amar Date: Mon, 18 Jan 2021 12:47:55 +0100 Subject: [PATCH 05/42] linting bug fixing --- .vscode/settings.json | 3 + app/main.py | 4 +- app/routers/calendar_grid.py | 8 ++- app/static/style.css | 65 +++++-------------- .../{monthview.html => calendar.html} | 0 tests/test_calender_grid.py | 42 ++++++------ 6 files changed, 51 insertions(+), 71 deletions(-) create mode 100644 .vscode/settings.json rename app/templates/{monthview.html => calendar.html} (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..f2d90cbd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.linting.enabled": true +} \ No newline at end of file diff --git a/app/main.py b/app/main.py index 3449a0e9..e81110c1 100644 --- a/app/main.py +++ b/app/main.py @@ -34,10 +34,10 @@ def profile(request: Request): }) -@app.get("/monthview") +@app.get("/calendar") async def monthview(request: Request): date = datetime.date.today() - return templates.TemplateResponse("monthview.html", { + return templates.TemplateResponse("calendar.html", { "request": request, "calendar": { 'date': date, diff --git a/app/routers/calendar_grid.py b/app/routers/calendar_grid.py index 1b8ea0f2..54f958a9 100644 --- a/app/routers/calendar_grid.py +++ b/app/routers/calendar_grid.py @@ -2,11 +2,13 @@ import itertools from datetime import datetime, timedelta -from typing import Any, Iterator, Generator, List, Tuple +from typing import Any, Iterator, Generator, List DAYS_OF_THE_WEEK: List[str] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] CALENDAR = calendar.Calendar(0) +DISPLAY_BLOCK = 100 +WEEK_DAYS = 7 def get_date_as_string(date: datetime) -> List[str]: @@ -39,9 +41,9 @@ def split_list_to_lists(dates: List[Any], length: int) -> List[List[Any]]: return [dates[i:i + length] for i in range(0, len(dates), length)] -def get_month_block(date: datetime, n: int = 100) -> List[List]: +def get_month_block(date: datetime, n: int = DISPLAY_BLOCK) -> List[List]: """Returns a 2D list represent a n days calendar from current month.""" start = get_first_day_month_block(date) cal = list(get_n_days(start, n)) cal.insert(0, start) - return split_list_to_lists(cal, 7) + return split_list_to_lists(cal, WEEK_DAYS) diff --git a/app/static/style.css b/app/static/style.css index b2206ae8..38997dc4 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -31,11 +31,12 @@ a { text-decoration: none; color: inherit; } + /* Grids */ /* -> Website Structure */ .container { display: grid; - grid-template-columns: minmax(4.5rem, auto) 1fr; /* The Header Hight */ + grid-template-columns: minmax(4.5rem, auto) 1fr; grid-auto-rows: minmax(3rem, auto); } @@ -47,10 +48,7 @@ nav { padding-left: 0.5rem; } -.menu div:hover { - color: #FFDE4D; -} - +.menu div:hover {color: #FFDE4D;} .menu { position: sticky; @@ -58,9 +56,7 @@ nav { flex-direction: column; } -img { - fill: #F7F7F7; -} +img {fill: #F7F7F7;} header { background-color: #F7F7F7; @@ -93,13 +89,7 @@ header { margin-top: 1rem; } -/* -> The calendar grid */ -.calender-grid { - display: grid; - grid-template-columns: repeat(7, 1fr); -} - -/* -> Main structure */ +/* -> Main Grid */ .main-grid { display: grid; width: 100%; @@ -108,8 +98,10 @@ header { padding: 0 1rem 0 1rem; } -.week { - border: 3px solid black; +/* -> The calendar grid */ +.calender-grid { + display: grid; + grid-template-columns: repeat(7, 1fr); } #event-menu { @@ -118,7 +110,6 @@ header { grid-row: 1/3; } - .calendar-grid div { font-weight: 900; height: 12rem; @@ -127,7 +118,6 @@ header { .day { display: flex; - /* flex-flow: column wrap; */ flex-direction: column; height: 12rem; @@ -137,7 +127,6 @@ header { } .day:hover { - /* font-size: 3rem; */ border: 0.3rem solid #222831; color: #F24726; transition: border 0.1s; @@ -181,40 +170,22 @@ header { } /* Text Colors */ -.t-yellow { - color: #FFDE4D; -} +.t-yellow {color: #FFDE4D;} -.t-gray { - color: #adb5bd; -} +.t-gray {color: #adb5bd;} -.t-very-lightgray { - color: #F7F7F7; -} +.t-very-lightgray {color: #F7F7F7;} -.t-darkblue { - color: #222831; -} +.t-darkblue {color: #222831;} /* Borders */ -.b-dashed-darkblue { - border: 2px dashed #222831; -} +.b-dashed-darkblue {border: 2px dashed #222831;} -.b-darkblue { - border: 2px solid #222831; -} +.b-darkblue {border: 2px solid #222831;} -.uline-yellow { - border-bottom: 4px solid #FFDE4D; -} +.uline-yellow {border-bottom: 4px solid #FFDE4D;} /* Background Color */ -.bg-darkblue { - background-color: #222831; -} +.bg-darkblue {background-color: #222831;} -.bg-red { - background-color: #F24726; -} \ No newline at end of file +.bg-red {background-color: #F24726;} \ No newline at end of file diff --git a/app/templates/monthview.html b/app/templates/calendar.html similarity index 100% rename from app/templates/monthview.html rename to app/templates/calendar.html diff --git a/tests/test_calender_grid.py b/tests/test_calender_grid.py index 1b4e4860..d159afe8 100644 --- a/tests/test_calender_grid.py +++ b/tests/test_calender_grid.py @@ -1,8 +1,6 @@ import datetime -from app.routers.calendar_grid import (get_date_as_string, get_date_before_n_days, - get_first_day_month_block, get_month_block, - get_n_days, get_next_date, split_list_to_lists) +import app.routers.calendar_grid as cg DATE = datetime.date(1988, 5, 3) N_DAYS = 3 @@ -15,44 +13,50 @@ class TestCalendarGrid: - @staticmethod def test_get_date_as_string(): - assert get_date_as_string(DATE) == [ + assert cg.get_date_as_string(DATE) == [ 'Tuesday', 'May', 'May', '1988'] @staticmethod def test_get_next_date(): next_day = DATE + datetime.timedelta(days=1) - next_day_generator = get_next_date(DATE) + next_day_generator = cg.get_next_date(DATE) assert next(next_day_generator) == next_day @staticmethod def test_get_date_before_n_days(): - assert get_date_before_n_days(DATE, N_DAYS) == N_DAYS_BEFORE + assert cg.get_date_before_n_days(DATE, N_DAYS) == N_DAYS_BEFORE @staticmethod def test_get_n_days(): - next_n_dates = get_n_days(DATE, N_DAYS) + next_n_dates = cg.get_n_days(DATE, N_DAYS) for i in range(N_DAYS): assert next(next_n_dates) == NEXT_N_DAYS[i] @staticmethod def test_get_first_day_month_block(Calendar): - assert get_first_day_month_block( - DATE) == list(Calendar.itermonthdates(DATE.year, DATE.month))[0] + assert ( + cg.get_first_day_month_block(DATE) + == list(Calendar.itermonthdates(DATE.year, DATE.month))[0] + ) @staticmethod def test_split_list_to_lists(): - sub_length = 7 - total_length = 20 - list_before_split = list(range(total_length)) - list_after_split = [list_before_split[i: i + sub_length] - for i in range(0, len(list_before_split), sub_length)] - assert split_list_to_lists( - list_before_split, sub_length) == list_after_split + s_length = 7 + t_length = 20 + list_before_split = list(range(t_length)) + list_after_split = [ + list_before_split[i: i + s_length] + for i in range(0, len(list_before_split), s_length) + ] + assert ( + cg.split_list_to_lists(list_before_split, s_length) + == list_after_split + ) @staticmethod def test_get_month_block(Calendar): - test = split_list_to_lists(list(Calendar.itermonthdates(1988, 5)), 7) - assert get_month_block(DATE, n=41) == test + test = cg.split_list_to_lists( + list(Calendar.itermonthdates(1988, 5)), 7) + assert cg.get_month_block(DATE, n=41) == test From c2aa5192425d91d376896cd66fdccb1ffb28dc88 Mon Sep 17 00:00:00 2001 From: Aviad Amar Date: Wed, 20 Jan 2021 00:15:14 +0100 Subject: [PATCH 06/42] before merge with develop --- .gitignore | 1 + app/main.py | 23 ------- app/routers/calendar.py | 25 ++++++++ app/static/scripts.js | 19 ++++++ app/static/style.css | 99 +++++++++++++++++++++--------- app/templates/calendar.html | 119 +++++++++++++++++++----------------- app/templates/layout.html | 3 +- 7 files changed, 181 insertions(+), 108 deletions(-) create mode 100644 app/routers/calendar.py create mode 100644 app/static/scripts.js diff --git a/.gitignore b/.gitignore index 1ffc615e..6f4a041c 100644 --- a/.gitignore +++ b/.gitignore @@ -112,6 +112,7 @@ venv/ ENV/ env.bak/ venv.bak/ +.vscode/ # Spyder project settings .spyderproject diff --git a/app/main.py b/app/main.py index e81110c1..28532718 100644 --- a/app/main.py +++ b/app/main.py @@ -1,11 +1,7 @@ -import datetime - -import uvicorn from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates -import routers.calendar_grid app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") @@ -32,22 +28,3 @@ def profile(request: Request): "username": current_username, "events": upcouming_events }) - - -@app.get("/calendar") -async def monthview(request: Request): - date = datetime.date.today() - return templates.TemplateResponse("calendar.html", { - "request": request, - "calendar": { - 'date': date, - 'strf_date': routers.calendar_grid.get_date_as_string(date), - 'days_of_the_week': routers.calendar_grid.DAYS_OF_THE_WEEK, - 'month_block': routers.calendar_grid.get_month_block( - datetime.date(date.year, date.month, 1) - ) - }}) - - -if __name__ == "__main__": - uvicorn.run(app) diff --git a/app/routers/calendar.py b/app/routers/calendar.py new file mode 100644 index 00000000..353a318e --- /dev/null +++ b/app/routers/calendar.py @@ -0,0 +1,25 @@ +import datetime + +from app.routers import calendar_gridcg as cg +from app.dependencies import templates + +from fastapi import Request + + +@router.get("/calendar") +async def calendar(request: Request): + date = datetime.date.today() + return templates.TemplateResponse( + "calendar.html", + { + "request": request, + "calendar": { + 'date': date, + 'strf_date': cg.get_date_as_string(date), + 'days_of_the_week': cg.DAYS_OF_THE_WEEK, + 'month_block': cg.get_month_block( + datetime.date(date.year, date.month, 1) + ) + } + } + ) diff --git a/app/static/scripts.js b/app/static/scripts.js new file mode 100644 index 00000000..5a97c908 --- /dev/null +++ b/app/static/scripts.js @@ -0,0 +1,19 @@ +document.addEventListener( + 'DOMContentLoaded', + function () { + var all_days = document.querySelectorAll('.day'), i; + + for (i = 0; i < all_days.length; ++i) { + all_days[i].onclick = function () { + var daily_event = document.querySelector("#daily-event"); + if (daily_event.style.flex === '0 1 30%') { + daily_event.style.opacity = '0'; + daily_event.style.flex = '0 0 0'; + } + else { + daily_event.style.opacity = '1'; + daily_event.style.flex = '0 1 30%'; + } + }; + } + }); \ No newline at end of file diff --git a/app/static/style.css b/app/static/style.css index 38997dc4..36336a42 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -24,7 +24,7 @@ html { text-rendering: optimizeLegibility; scroll-behavior: smooth; background-color: #F7F7F7; - color: #222831 + color: #222831; } a { @@ -37,7 +37,6 @@ a { .container { display: grid; grid-template-columns: minmax(4.5rem, auto) 1fr; - grid-auto-rows: minmax(3rem, auto); } nav { @@ -48,27 +47,28 @@ nav { padding-left: 0.5rem; } -.menu div:hover {color: #FFDE4D;} - .menu { - position: sticky; + position: fixed; display: flex; flex-direction: column; } +.menu div:hover {color: #FFDE4D;} + img {fill: #F7F7F7;} header { - background-color: #F7F7F7; z-index: 1; + position: sticky; + top: 0; display: grid; grid-template-columns:80% 20%; margin: 0 1rem 0 1rem; + background-color: #F7F7F7; } #header-bottom { display: none; - grid-column: 1/3 } #logo-div { @@ -82,37 +82,45 @@ header { float: left; } +/* Main Element Grid */ +main { + display: flex; + flex-flow: row wrap; +} + +.calendar { + flex: 1; +} + +#daily-event { + flex: 0 0 0; + opacity: 0; + transition: all 1s; +} + .calender-days-titles { + z-index: 1; + position: sticky; + top: 6rem; + align-self: flex-start; grid-column: 1/3; display: grid; grid-template-columns: repeat(7, 1fr); - margin-top: 1rem; -} - -/* -> Main Grid */ -.main-grid { - display: grid; - width: 100%; - grid-template-columns: 1fr; - grid-template-rows: 1fr; - padding: 0 1rem 0 1rem; + margin: 1rem 1rem 0 1rem; + background-color: #F7F7F7; } -/* -> The calendar grid */ +/* The Calendar Grid */ .calender-grid { + flex: 1; display: grid; grid-template-columns: repeat(7, 1fr); -} - -#event-menu { - display: none; - grid-column: 2/3; - grid-row: 1/3; + grid-auto-rows: minmax(12rem, auto); + margin: 0 1rem 0 1rem; } .calendar-grid div { font-weight: 900; - height: 12rem; font-size: 2rem; } @@ -120,7 +128,6 @@ header { display: flex; flex-direction: column; - height: 12rem; padding: 0 1rem 0 1rem; border: 1px solid #e9ecef; font-size: 1.2rem; @@ -128,10 +135,13 @@ header { .day:hover { border: 0.3rem solid #222831; - color: #F24726; transition: border 0.1s; } +.day:hover .day-number{ + color: #F24726; +} + .day-number { font-weight: 900; font-size: 2rem; @@ -146,7 +156,36 @@ header { background-color: #e9ecef; } -.daily-event { +/* Dates Navigation */ +.dates-navigation { + position: fixed; +} + +/* Events - Rotation*/ +.month-event { + position: relative; + perspective: 150rem; + -moz-perspective: 150rem; + height: 2.4rem; +} + +.month-event div{ + height: 2.4rem; + width: 100%; + transition: all 0.3s ease; + position: absolute; + top: 0; + left: 0; + backface-visibility: hidden; +} + +.back {transform: rotateX(180deg);} + +.month-event:hover .front{transform: rotateX(-180deg);} + +.month-event:hover .back{transform: rotateX(0);} + +.daily { font-weight: 700; border-radius: 0.4rem; padding: 0 0.5rem 0 0.5rem; @@ -188,4 +227,6 @@ header { /* Background Color */ .bg-darkblue {background-color: #222831;} -.bg-red {background-color: #F24726;} \ No newline at end of file +.bg-red {background-color: #F24726;} + +.bg-lightgray {background-color: #e9ecef;} diff --git a/app/templates/calendar.html b/app/templates/calendar.html index c585a1cc..c948e1d4 100644 --- a/app/templates/calendar.html +++ b/app/templates/calendar.html @@ -13,67 +13,76 @@
-
+
- -
-
-
{{calendar['date'].day}} {{ calendar['strf_date'][1].upper() }} {{calendar['date'].year - }}
-
Milano 4 oc
-
- -
-
Search
-
Month
-
-
- {% for day in calendar['days_of_the_week'] %} - {% if day == calendar['strf_date'][0] %} -
{{ day.upper() }}
- {% else %} -
{{ day.upper() }}
- {% endif %} - {% endfor %} -
-
- -
-
- {% for week in calendar['month_block'] %} - {% for i in range(week|length) %} - {% if week[i] == calendar['date'] %} -
-
{{week[i].day}}
-
daily event
-
6PM Meeting with Ode
-
9PM Meeting with Michele
-
- {% elif week[i].day == 1 %} -
-
{{week[i].strftime('%d %b %y')}}
-
daily event
-
6PM Meeting with yam
-
7PM Meeting with Sagi
+
+
+
+
{{calendar['date'].day}} {{ calendar['strf_date'][1].upper() }} + {{calendar['date'].year + }}
+
Milano 4 oc
- {% elif i in (5, 6) and not (week[i] == calendar['date']) %} -
-
{{week[i].day}}
+ +
+
Search
+
Month
- {% else %} -
-
{{week[i].day}}
+
+
+
+
+ {% for day in calendar['days_of_the_week'] %} + {% if day == calendar['strf_date'][0] %} +
{{ day.upper() }}
+ {% else %} +
{{ day.upper() }}
+ {% endif %} + {% endfor %} +
+
+ {% for week in calendar['month_block'] %} + {% for i in range(week|length) %} + {% if week[i] == calendar['date'] %} +
+
{{week[i].day}}
+
+
daily front
+
more information
+
+
6PM Meeting with Ode
+
9PM Meeting with Michele
+
+ {% elif week[i].day == 1 %} +
+
{{week[i].strftime('%d %b %y')}}
+
+
daily front
+
more information
+
+
6PM Meeting with yam
+
7PM Meeting with Sagi
+
+ {% elif i in (5, 6) and not (week[i] == calendar['date']) %} +
+
{{week[i].day}}
+
+ {% else %} +
+
{{week[i].day}}
+
+ {% endif %} + {% endfor %} + {% endfor %} +
- {% endif %} - {% endfor %} - {% endfor %} -
-
event
-
+
lalalal lilili aviad aviad
+
+
{% endblock %} \ No newline at end of file diff --git a/app/templates/layout.html b/app/templates/layout.html index 74b1c2aa..6da15507 100644 --- a/app/templates/layout.html +++ b/app/templates/layout.html @@ -14,6 +14,7 @@ + Calendar @@ -21,7 +22,7 @@ {% block body %} - {% endblock %} + {% endblock %} \ No newline at end of file From 6f9a2ba7c7e0f84c9fa978331c93559f5fa907c1 Mon Sep 17 00:00:00 2001 From: Aviad Amar Date: Wed, 20 Jan 2021 23:28:38 +0100 Subject: [PATCH 07/42] Creating a Day object and days subclasses, changing all function and tests according to the new objects, Changing front to get information from Day objects, Re-arranging calendar.html grid stracture to be render by weeks, adding js functionality for day view section, adding css effects on daily event display --- .github/workflows/python-app.yml | 41 ---------- .gitignore | 2 + .vscode/settings.json | 3 - app/config.py.example | 10 --- app/main.py | 2 +- app/media/fake_user.png | Bin 0 -> 3556 bytes app/routers/calendar.py | 15 ++-- app/routers/calendar_grid.py | 124 ++++++++++++++++++++++++++----- app/static/grid_style.css | 43 +++++++---- app/static/js/grid_scripts.js | 2 +- app/templates/calendar.html | 61 ++++++--------- app/templates/layout.html | 2 +- tests/conftest.py | 8 +- tests/test_calendar_grid.py | 94 +++++++++++++++++++++++ tests/test_calender_grid.py | 62 ---------------- 15 files changed, 265 insertions(+), 204 deletions(-) delete mode 100644 .github/workflows/python-app.yml delete mode 100644 .vscode/settings.json delete mode 100644 app/config.py.example create mode 100644 app/media/fake_user.png create mode 100644 tests/test_calendar_grid.py delete mode 100644 tests/test_calender_grid.py diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml deleted file mode 100644 index dd168392..00000000 --- a/.github/workflows/python-app.yml +++ /dev/null @@ -1,41 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a single version of Python -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Python application - -on: - push: - branches: [ main, develop ] - pull_request: - branches: [ main, develop ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.9 - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install flake8 pytest pytest-cov - cp app/config.py.example app/config.py - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --show-source --statistics - # exit-zero treats all errors as warnings. - flake8 . --count --exit-zero --max-complexity=10 --statistics - - name: Test with pytest - run: | - pytest -vvv --junitxml=junit/test-results.xml --cov-report=xml --cov=app ./tests - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1.0.13 - with: - file: coverage.xml diff --git a/.gitignore b/.gitignore index 26c76b31..09ec541d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ share/python-wheels/ MANIFEST pyvenv.cfg + # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. @@ -57,6 +58,7 @@ coverage.xml *.py,cover .hypothesis/ .pytest_cache/ +.github/* # Translations *.mo diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f2d90cbd..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.linting.enabled": true -} \ No newline at end of file diff --git a/app/config.py.example b/app/config.py.example deleted file mode 100644 index b4c8ccf2..00000000 --- a/app/config.py.example +++ /dev/null @@ -1,10 +0,0 @@ -# flake8: noqa - - -# DATABASE -DEVELOPMENT_DATABASE_STRING = "sqlite:///./dev.db" - -# MEDIA -MEDIA_DIRECTORY = 'media' -PICTURE_EXTENSION = '.png' -AVATAR_SIZE = (120, 120) diff --git a/app/main.py b/app/main.py index df083203..1ecd1c03 100644 --- a/app/main.py +++ b/app/main.py @@ -5,7 +5,7 @@ from app.database.database import engine from app.dependencies import ( MEDIA_PATH, STATIC_PATH, templates) -from app.routers import agenda, event, profile +from app.routers import agenda, calendar, event, profile models.Base.metadata.create_all(bind=engine) diff --git a/app/media/fake_user.png b/app/media/fake_user.png new file mode 100644 index 0000000000000000000000000000000000000000..bd856aaa02ed8fc75fb310971827e4734b8785d5 GIT binary patch literal 3556 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 literal 0 HcmV?d00001 diff --git a/app/routers/calendar.py b/app/routers/calendar.py index 3c4e8aa8..413c2a3d 100644 --- a/app/routers/calendar.py +++ b/app/routers/calendar.py @@ -1,8 +1,8 @@ import datetime from app.dependencies import templates -from app.routers import calendar_gridcg as cg -from fastapi import Request +from app.routers import calendar_grid as cg +from fastapi import APIRouter, Request router = APIRouter( prefix="/calendar", @@ -11,19 +11,18 @@ ) -@router.get("/calendar") +@router.get("/") async def calendar(request: Request): - date = datetime.date.today() + today = cg.Day(datetime.date.today()) return templates.TemplateResponse( "calendar.html", { "request": request, "calendar": { - 'date': date, - 'strf_date': cg.get_date_as_string(date), - 'days_of_the_week': cg.DAYS_OF_THE_WEEK, + 'day': today, + 'week_days': cg.Week.DAYS_OF_THE_WEEK, 'month_block': cg.get_month_block( - datetime.date(date.year, date.month, 1) + datetime.date(today.date.year, today.date.month, 1) ) } } diff --git a/app/routers/calendar_grid.py b/app/routers/calendar_grid.py index 54f958a9..34342cfa 100644 --- a/app/routers/calendar_grid.py +++ b/app/routers/calendar_grid.py @@ -1,24 +1,107 @@ import calendar import itertools -from datetime import datetime, timedelta +import locale +from datetime import date, datetime, timedelta +from typing import Any, Generator, Iterator, List, Union -from typing import Any, Iterator, Generator, List - -DAYS_OF_THE_WEEK: List[str] = ['Monday', 'Tuesday', 'Wednesday', - 'Thursday', 'Friday', 'Saturday', 'Sunday'] CALENDAR = calendar.Calendar(0) DISPLAY_BLOCK = 100 -WEEK_DAYS = 7 - - -def get_date_as_string(date: datetime) -> List[str]: - """Returns list represent date as string.""" - return date.strftime("%A %B %b %Y").split() - -def get_next_date(date: datetime) -> Generator[datetime, None, None]: +locale.setlocale(locale.LC_TIME, ("en", "UTF-8")) + + +class Week: + WEEK_DAYS = 7 + DAYS_OF_THE_WEEK = calendar.day_name + + +class Day: + def __init__(self, date: datetime): + self.date = date + self.sday = self.date.strftime("%A") + self.dailyevents = [("Daily Event", "More Information")] + self.events = [ + ("6PM", "Meeting with Ode"), + ("7PM", "Meeting with Sagi") + ] + self.css = { + 'div': 'day', + 'date': 'day-number', + 'daily_event': 'month-event', + 'daily_event_front': 'daily front bg-warmyellow', + 'daily_event_back': 'daily back t-darkblue bg-lightgray', + 'event': 'event', + } + + def __str__(self) -> str: + return self.date.strftime("%d") + + def display(self) -> str: + """Returns day date inf the format of 00 MONTH 00""" + return self.date.strftime("%d %B %y").upper() + + @classmethod + def is_weekend(cls, date: datetime) -> bool: + """Returns true if this day is represent a weekend.""" + return date.strftime("%A") in Week.DAYS_OF_THE_WEEK[-2:] + + +class DayWeekend(Day): + def __init__(self, date: datetime): + super().__init__(date) + self.css = { + 'div': 'day ', + 'date': 'day-number t-gray', + 'daily_event': 'month-event', + 'daily_event_front': 'daily front bg-warmyellow', + 'daily_event_back': 'daily back t-darkblue bg-lightgray', + 'event': 'event', + } + + +class Today(Day): + def __init__(self, date: datetime): + super().__init__(date) + self.css = { + 'div': 'day t-darkblue bg-yellow', + 'date': 'day-number', + 'daily_event': 'month-event', + 'daily_event_front': 'daily front t-lightgray bg-darkblue', + 'daily_event_back': 'daily back t-darkblue bg-lightgray', + 'event': 'event', + } + + +class FirstDayMonth(Day): + def __init__(self, date: datetime): + super().__init__(date) + self.css = { + 'div': 'day t-darkblue bg-lightgray', + 'date': 'day-number', + 'daily_event': 'month-event', + 'daily_event_front': 'daily front t-lightgray bg-red', + 'daily_event_back': 'daily back t-darkblue bg-lightgray', + 'event': 'event', + } + + def __str__(self) -> str: + return self.date.strftime("%d %b %y").upper() + + +def create_day(day: datetime) -> Day: + """Return the currect day object according to given date.""" + if Day.is_weekend(day): + return DayWeekend(day) + if day == date.today(): + return Today(day) + if int(day.day) == 1: + return FirstDayMonth(day) + return Day(day) + + +def get_next_date(date: datetime) -> Generator[Day, None, None]: """Generate date objects from a starting given date.""" - yield from (date + timedelta(days=i) for i in itertools.count(start=1)) + yield from (create_day(date + timedelta(days=i)) for i in itertools.count(start=1)) def get_date_before_n_days(date: datetime, n: int) -> datetime: @@ -26,11 +109,12 @@ def get_date_before_n_days(date: datetime, n: int) -> datetime: return date - timedelta(days=n) -def get_first_day_month_block(date): +def get_first_day_month_block(date: datetime) -> datetime: + """Returns the first date in a month block of given date.""" return list(CALENDAR.itermonthdates(date.year, date.month))[0] -def get_n_days(date: datetime, n: int) -> Iterator[datetime]: +def get_n_days(date: datetime, n: int) -> Iterator[Day]: """Generate n dates from a starting given date.""" next_date_gen = get_next_date(date) yield from itertools.islice(next_date_gen, n) @@ -41,9 +125,9 @@ def split_list_to_lists(dates: List[Any], length: int) -> List[List[Any]]: return [dates[i:i + length] for i in range(0, len(dates), length)] -def get_month_block(date: datetime, n: int = DISPLAY_BLOCK) -> List[List]: +def get_month_block(date: datetime, n: int = DISPLAY_BLOCK) -> List[List[Day]]: """Returns a 2D list represent a n days calendar from current month.""" - start = get_first_day_month_block(date) - cal = list(get_n_days(start, n)) + start = create_day(get_first_day_month_block(date)) + cal = list(get_n_days(start.date, n)) cal.insert(0, start) - return split_list_to_lists(cal, WEEK_DAYS) + return split_list_to_lists(cal, Week.WEEK_DAYS) diff --git a/app/static/grid_style.css b/app/static/grid_style.css index 537fda5a..f42b364c 100644 --- a/app/static/grid_style.css +++ b/app/static/grid_style.css @@ -44,7 +44,7 @@ nav { width: 4.5rem; grid-row: 1/3; font-size: 2.8rem; - padding-left: 0.5rem; + padding-left: 0.8rem; } .menu { @@ -92,7 +92,7 @@ main { flex: 1; } -#daily-event { +#day-display { flex: 0 0 0; opacity: 0; transition: all 1s; @@ -113,29 +113,44 @@ main { /* The Calendar Grid */ .calender-grid { flex: 1; - display: grid; - grid-template-columns: repeat(7, 1fr); - grid-auto-rows: minmax(12rem, auto); + display: flex; + flex-direction: column; margin: 0 1rem 0 1rem; } -.calendar-grid div { +.week { + flex: 1; + display: grid; + grid-template-columns: repeat(7, 1fr); + grid-auto-rows: 12rem; font-weight: 900; font-size: 2rem; } +.week:hover { + box-shadow: -5px 0px 0px 0px #FFDE4D; +} + .day { display: flex; flex-direction: column; + overflow: hidden; + font-size: 1.2rem; padding: 0 1rem 0 1rem; border: 1px solid #e9ecef; - font-size: 1.2rem; + + overflow-y: auto; + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ } +.day::-webkit-scrollbar {display: none;} + +.event { font-weight: 400; } + .day:hover { - border: 0.3rem solid #222831; - transition: border 0.1s; + border: 0.2rem solid #222831; } .day:hover .day-number{ @@ -152,10 +167,6 @@ main { color: white; } -.day_first { - background-color: #e9ecef; -} - /* Dates Navigation */ .dates-navigation { position: fixed; @@ -213,7 +224,7 @@ main { .t-gray {color: #adb5bd;} -.t-very-lightgray {color: #F7F7F7;} +.t-lightgray {color: #F7F7F7;} .t-darkblue {color: #222831;} @@ -229,4 +240,6 @@ main { .bg-red {background-color: #F24726;} -.bg-lightgray {background-color: #e9ecef;} \ No newline at end of file +.bg-lightgray {background-color: #e9ecef;} + +.bg-yellow {background-color: #FFDE4D;} \ No newline at end of file diff --git a/app/static/js/grid_scripts.js b/app/static/js/grid_scripts.js index 5a97c908..c6821038 100644 --- a/app/static/js/grid_scripts.js +++ b/app/static/js/grid_scripts.js @@ -5,7 +5,7 @@ document.addEventListener( for (i = 0; i < all_days.length; ++i) { all_days[i].onclick = function () { - var daily_event = document.querySelector("#daily-event"); + var daily_event = document.querySelector("#day-display"); if (daily_event.style.flex === '0 1 30%') { daily_event.style.opacity = '0'; daily_event.style.flex = '0 0 0'; diff --git a/app/templates/calendar.html b/app/templates/calendar.html index c948e1d4..b964a9e2 100644 --- a/app/templates/calendar.html +++ b/app/templates/calendar.html @@ -2,7 +2,7 @@ {% block body %}
-