diff --git a/CHANGELOG.md b/CHANGELOG.md index 7325e600..1ba5f52a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project tries to adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.16.0] - 2020-07-15 +### Added +- answered questions of finished category can be re-seen + +### Changed +- merged landscape view into portrait view +- app checks for mobile/desktop view and shows only related parts +- major redesign of answer page (question form is shown with correct/wrong answers) + +### Fixed +- share links + ## [0.15.0] - 2020-07-13 ### Added - slogan to finished and share link diff --git a/e_metrobus/__init__.py b/e_metrobus/__init__.py index f3a9b54f..a828b55d 100644 --- a/e_metrobus/__init__.py +++ b/e_metrobus/__init__.py @@ -1,4 +1,4 @@ -__version__ = "0.15.0" +__version__ = "0.16.0" __version_info__ = tuple( [ int(num) if num.isdigit() else num diff --git a/e_metrobus/navigation/chart.py b/e_metrobus/navigation/chart.py index b222721d..2729140e 100644 --- a/e_metrobus/navigation/chart.py +++ b/e_metrobus/navigation/chart.py @@ -37,7 +37,7 @@ def __init__(self, figure, **config): div_id_end = plotly_div.find('"', div_id_start + 9) self.div_id = plotly_div[div_id_start + 9 : div_id_end] - self.div = f'
' + self.div = f'
' def get_sizes(max_value): diff --git a/e_metrobus/navigation/constants.py b/e_metrobus/navigation/constants.py index 3255b817..988f3f8d 100644 --- a/e_metrobus/navigation/constants.py +++ b/e_metrobus/navigation/constants.py @@ -78,7 +78,7 @@ class Vehicle: ] DATA_SOURCES = [ - 'Umweltbundesamt, "Vergleich der durchschnittlicher Emissionen einzelner Verkehrsmittel im Personenverkehr in Deutschland - Bezugsjahr 2018", 01/2020', + 'Umweltbundesamt, "Vergleich der durchschnittlichen Emissionen einzelner Verkehrsmittel im Personenverkehr in Deutschland - Bezugsjahr 2018", 01/2020', 'Umweltbundesamt, "Entwicklung der spezifischen Kohlendioxid-Emissionen des deutschen Strommix in den Jahren 1990 - 2019", 13/2020', ] diff --git a/e_metrobus/navigation/questions.cfg b/e_metrobus/navigation/questions.cfg index 259b45fd..42ac56c7 100644 --- a/e_metrobus/navigation/questions.cfg +++ b/e_metrobus/navigation/questions.cfg @@ -4,15 +4,9 @@ icon = "images/icons/i_ebus_black_line.svg" small_icon = "images/icons/i_ebus_black_fill.svg" [[questions]] - [[[route]]] - label = "This is a placeholder for route selection" - question = "" - answers = "", "" - correct = 0 - short_answer = "" [[[loading_time]]] label = "Ladezeiten" - question = "Wie lange müssen die Elektro-Gelenkbusse der 200 an den Endhaltestellen laden?" + question = "Wie lange müssen die Elektro-Gelenkbusse der Linie 200 an den Endhaltestellen laden?" answers = "Eine halbe Stunde", "Eine Stunde", "Wenige Minuten", "Wenige Sekunden" correct = 2 short_answer = "Die Ladezeit beträgt in der Regel wenige Minuten." @@ -24,13 +18,13 @@ short_answer = "Der Bus wird an den Endhaltestellen Hertzallee und Michelangelostraße sowie im Betriebshof mit einem Pantographen aufgeladen." [[[batteries]]] label = "Batterien" - question = "Wo befinden sich die Batterien der Elektro-Gelenkbusse der Linie 200?" + question = "Wo befinden sich die Batterien in den Elektro-Gelenkbussen der Linie 200?" answers = "Im Boden", "Am Heck", "Auf dem Dach", "An den Seiten" correct = 2 short_answer = "Die Batterien der Elektro-Gelenkbusse, die auf der Linie 200 eingesetzt werden, sich auf dem Dach angebracht." [[[costs]]] label = "Kosten" - question = "Wie viel mehr kostet ein Elektrobus als ein konventioneller Dieselbus?" + question = "Wie viel mehr kostet ein Elektrobus im Vergleich zu einem konventionellen Dieselbus?" answers = "Doppelt", "Dreifach", "Zehnfach", "Genauso" correct = 0 short_answer = "Elektrobusse kosten aktuell noch etwa doppelt so viel wie konventionelle Dieselbusse der gleichen Größenklasse." @@ -42,8 +36,8 @@ [[questions]] [[[energy]]] label = "Energie" - question = "Wieviel Energie ist für die jährliche Stromversorgung der Elektrobusse auf der Linie 200 notwendig? So viel wie ausreichen würde zur Versorgung von:" - answers = "584 Haushalten", "56 Haushalten", "285 Haushalten", "1010 Haushalten" + question = "Wie viel Energie ist für die jährliche Stromversorgung der Elektrobusse auf der Linie 200 notwendig? So viel wie der Jahresstromverbrauch von:" + answers = "584 Dreipersonenhaushalten", "56 Dreipersonenhaushalten", "285 Dreipersonenhaushalten", "1010 Dreipersonenhaushalten" correct = 0 short_answer = "Der jährliche Stromverbrauch der gesamten Buslinie 200 mit allen im Betrieb befindlichen Elektrobussen liegt bei etwa 2.044.000 kWh, was dem Energiebedarf von ca. 584 Dreipersonenhaushalten entspricht." [[[weather]]] diff --git a/e_metrobus/navigation/questions.py b/e_metrobus/navigation/questions.py index c15341c8..a65979df 100644 --- a/e_metrobus/navigation/questions.py +++ b/e_metrobus/navigation/questions.py @@ -121,11 +121,14 @@ def get_category_shares(category, session): correct = 0 if "questions" not in session or category not in session["questions"]: return Shares(0, 0) - for question in QUESTIONS[category].questions: + for question_name, question in QUESTIONS[category].questions.items(): total += 1 - if question in session["questions"][category]: + if question_name in session["questions"][category]: done += 1 - correct += session["questions"][category][question] + correct += check_answer( + question, + session["questions"][category][question_name], + ) return Shares(done / total, correct / total) @@ -133,10 +136,14 @@ def get_category_answers(category, session): """Returns list of correct/wrong/unanswered questions for category""" if "questions" not in session or category not in session["questions"]: return [Answer.Unanswered for question in QUESTIONS[category].questions] - return [ - Answer.get(session["questions"][category].get(question)) - for question in QUESTIONS[category].questions - ] + answers = [] + for question_name, question in QUESTIONS[category].questions.items(): + answer = session["questions"][category].get(question_name) + if answer is None: + answers.append(Answer.Unanswered) + else: + answers.append(Answer.get(check_answer(question, answer))) + return answers def get_all_answers(session, sort=True): @@ -160,6 +167,21 @@ def get_next_question(category, session): return None +def get_next_answer(category, current_answer=None): + if category not in QUESTIONS: + raise KeyError("Invalid category") + if current_answer is None: + return list(QUESTIONS[category].questions.keys())[0] + questions_iterator = iter(QUESTIONS[category].questions) + question = None + try: + while question != current_answer: + question = next(questions_iterator) + return next(questions_iterator) + except StopIteration: + return None + + def get_question_from_name(question_name): for category in QUESTIONS.values(): if question_name in category.questions: @@ -172,3 +194,10 @@ def all_questions_answered(session): if get_category_shares(category, session).done != 1.0: return False return True + + +def check_answer(question, answer): + if isinstance(question.correct, list): + return answer == question.correct + else: + return answer == question.correct diff --git a/e_metrobus/navigation/tests/test_questions.py b/e_metrobus/navigation/tests/test_questions.py index 8b5a412e..d9917bae 100644 --- a/e_metrobus/navigation/tests/test_questions.py +++ b/e_metrobus/navigation/tests/test_questions.py @@ -1,35 +1,32 @@ -from django.test import TestCase +from django.test import TestCase, tag from e_metrobus.navigation import questions +@tag("questions") class QuestionTestCase(TestCase): def setUp(self): self.session = { "stations": (3, 4), "questions": { "e_metrobus": {"loading_time": True, "line_200": False}, - "personal": {"advantages": True}, - "politics": {"invalid": True}, + "ich": {"advantages": True}, + "politik": {"invalid": True}, }, } def test_score_category_empty(self): - self.assertEqual( - questions.get_score_for_category("environment", self.session), 0 - ) + self.assertEqual(questions.get_score_for_category("umwelt", self.session), 0) def test_score_category_complete(self): self.assertEqual( - questions.get_score_for_category("e_metrobus", self.session), - questions.SCORE_CORRECT - + questions.SCORE_WRONG + questions.get_score_for_category("e_metrobus", self.session), 1 / 4 ) def test_score_category_not_complete(self): self.assertEqual( - questions.get_score_for_category("personal", self.session), - questions.SCORE_CORRECT + questions.SCORE_CATEGORY_COMPLETE + questions.get_score_for_category("ich", self.session), + questions.SCORE_CORRECT + questions.SCORE_CATEGORY_COMPLETE, ) def test_score_category_error(self): @@ -37,7 +34,7 @@ def test_score_category_error(self): questions.get_score_for_category("not_there", self.session) def test_score_invalid_question(self): - self.assertEqual(questions.get_score_for_category("politics", self.session), 0) + self.assertEqual(questions.get_score_for_category("politik", self.session), 0) def test_total_score(self): self.assertEqual( @@ -49,28 +46,31 @@ def test_total_score(self): def test_percentage(self): self.assertEqual( - questions.get_category_done_share("e_metrobus", self.session), 2/3 - ) - self.assertEqual( - questions.get_category_done_share("personal", self.session), 1 - ) - self.assertEqual( - questions.get_category_done_share("politics", self.session), 0 + questions.get_category_shares("e_metrobus", self.session).done, 1 / 4 ) + self.assertEqual(questions.get_category_shares("ich", self.session), 1) + self.assertEqual(questions.get_category_shares("politik", self.session), 0) def test_next_question(self): self.assertEqual( questions.get_next_question("e_metrobus", self.session), questions.QUESTIONS["e_metrobus"].questions["loading"], ) - self.assertIsNone( - questions.get_next_question("personal", self.session) + self.assertIsNone(questions.get_next_question("ich", self.session)) + self.assertEqual( + questions.get_next_question("politik", self.session), + questions.QUESTIONS["politik"].questions["ebus_time"], ) self.assertEqual( - questions.get_next_question("politics", self.session), - questions.QUESTIONS["politics"].questions["ebus_time"], + questions.get_next_question("umwelt", self.session), + questions.QUESTIONS["umwelt"].questions["co2_reduction"], + ) + + def test_next_answer(self): + self.assertEqual(questions.get_next_answer("e_metrobus"), "loading_time") + self.assertEqual( + questions.get_next_answer("e_metrobus", "loading_time"), "loading" ) self.assertEqual( - questions.get_next_question("environment", self.session), - questions.QUESTIONS["environment"].questions["co2_reduction"], + questions.get_next_answer("e_metrobus", "costs"), None ) diff --git a/e_metrobus/navigation/urls.py b/e_metrobus/navigation/urls.py index ecc6f1e4..f8cf0577 100644 --- a/e_metrobus/navigation/urls.py +++ b/e_metrobus/navigation/urls.py @@ -17,6 +17,7 @@ path("quiz/", view=views.DashboardView.as_view(), name="dashboard"), path("quiz//", view=views.QuestionView.as_view(), name="question"), path("antwort/", view=views.AnswerView.as_view(), name="answer"), + path("antwort//", view=views.AnswerView.as_view(), name="answer"), path("tour/", view=views.TourView.as_view(), name="tour"), path( "abgeschlossen//", diff --git a/e_metrobus/navigation/utils.py b/e_metrobus/navigation/utils.py index 235da76d..94158054 100644 --- a/e_metrobus/navigation/utils.py +++ b/e_metrobus/navigation/utils.py @@ -37,7 +37,7 @@ def share_url(request): def share_text(request): if "non_bus_user" in request.session: text = _( - "Ich bin gerade in einem E-Bus auf der Linie 200 gefahren. Schau mal hier:" + "Ich bin gerade in einem E-Bus auf der Linie 200 gefahren. Schau mal hier" ) else: current_stations = [ @@ -46,7 +46,7 @@ def share_text(request): route_data = stations.STATIONS.get_route_data(*current_stations) co2 = route_data["bus"].co2 - route_data["e-bus"].co2 text = _( - "Ich bin gerade in einem E-Bus auf der Linie 200 gefahren und habe der Welt dabei %(co2)s g CO2-Emissionen erspart. Schau mal hier:" + "Ich bin gerade in einem E-Bus auf der Linie 200 gefahren und habe der Welt dabei %(co2)s g CO2-Emissionen erspart. Schau mal hier" ) % {"co2": round(co2, 2)} return text diff --git a/e_metrobus/navigation/views.py b/e_metrobus/navigation/views.py index 8235d27b..a24b96d5 100644 --- a/e_metrobus/navigation/views.py +++ b/e_metrobus/navigation/views.py @@ -177,10 +177,6 @@ def get(self, request, *args, **kwargs): # Set first question as "answered": if "questions" not in request.session: request.session["questions"] = {} - if "e_metrobus" not in request.session["questions"]: - request.session["questions"]["e_metrobus"] = {} - request.session["questions"]["e_metrobus"]["route"] = True - request.session["last_answered_question"] = "route" request.session.save() return super(DisplayRouteView, self).get(request, *args, **kwargs) @@ -246,8 +242,20 @@ def get_context_data(self, **kwargs): return context def get(self, request, *args, **kwargs): + if kwargs["category"] in request.session["questions"] and request.session[ + "questions" + ][kwargs["category"]].get("finished", False): + next_answer = questions.get_next_answer(kwargs["category"]) + if next_answer is None: + return redirect("navigation:dashboard") + else: + request.session["last_answered_question"] = next_answer + return redirect("navigation:answer", category=kwargs["category"]) + next_question = questions.get_next_question(kwargs["category"], request.session) if next_question is None: + request.session["questions"][kwargs["category"]]["finished"] = True + request.session.save() return redirect("navigation:category_finished", category=kwargs["category"]) context = self.get_context_data(**kwargs, question=next_question) @@ -256,11 +264,9 @@ def get(self, request, *args, **kwargs): def post(self, request, **kwargs): question = questions.get_question_from_name(request.POST["question"]) if isinstance(question.correct, list): - answer = request.POST.getlist("answer") == [ - question.answers[i] for i in map(int, question.correct) - ] + answer = request.POST.getlist("answer") else: - answer = request.POST["answer"] == question.answers[int(question.correct)] + answer = request.POST["answer"] if "questions" not in request.session: request.session["questions"] = {} @@ -291,15 +297,25 @@ def get_context_data(self, question, **kwargs): self.title_icon = questions.QUESTIONS[question.category].small_icon context = super(AnswerView, self).get_context_data(**kwargs) context["question"] = question - context["answer"] = self.request.session["questions"][question.category][ - question.name - ] + answer = self.request.session["questions"][question.category][question.name] + context["given_answer"] = list(map(int, answer)) + context["correct_answer"] = list(map(int, question.correct)) + context["flashes"] = questions.get_category_answers( + question.category, self.request.session + ) + if "category" in kwargs and self.request.session["questions"][ + kwargs["category"] + ].get("finished", False): + self.request.session["last_answered_question"] = questions.get_next_answer( + kwargs["category"], self.request.session["last_answered_question"] + ) + context["category_finished"] = True return context def get(self, request, **kwargs): question_name = request.session.get("last_answered_question") if question_name is None: - raise ValueError("No question answered yet!") + return redirect("navigation:dashboard") question = questions.get_question_from_name(question_name) context = self.get_context_data(question=question, **kwargs) return self.render_to_response(context) @@ -329,10 +345,6 @@ def get_context_data(self, **kwargs): context["footer"] = widgets.FooterWidget(links=self.footer_links) answers = questions.get_all_answers(self.request.session) context["answers"] = answers - correct = len( - [answer for answer in answers if answer == questions.Answer.Correct] - ) - total = len(answers) percent = questions.get_total_score(self.request.session) context["score"] = percent context["slogan"] = utils.get_slogan(percent) @@ -341,8 +353,8 @@ def get_context_data(self, **kwargs): return context def get(self, request, *args, **kwargs): - if not questions.all_questions_answered(request.session): - raise Http404("Not all questions answered. Please go back to quiz.") + # if not questions.all_questions_answered(request.session): + # raise Http404("Not all questions answered. Please go back to quiz.") if "hashed_score" not in request.session: score = models.Score.save_score(request.session) request.session["hashed_score"] = score.hash diff --git a/e_metrobus/static/images/icons/i_correct.svg b/e_metrobus/static/images/icons/i_correct.svg new file mode 100644 index 00000000..871ae0b9 --- /dev/null +++ b/e_metrobus/static/images/icons/i_correct.svg @@ -0,0 +1,49 @@ + +image/svg+xml \ No newline at end of file diff --git a/e_metrobus/static/images/icons/i_wrong.svg b/e_metrobus/static/images/icons/i_wrong.svg new file mode 100644 index 00000000..31650e4b --- /dev/null +++ b/e_metrobus/static/images/icons/i_wrong.svg @@ -0,0 +1,48 @@ + +image/svg+xml \ No newline at end of file diff --git a/e_metrobus/static/js/clipboard.min.js b/e_metrobus/static/js/clipboard.min.js new file mode 100644 index 00000000..28650f3c --- /dev/null +++ b/e_metrobus/static/js/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.6 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return o={},r.m=n=[function(t,e){t.exports=function(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}return e}},function(t,e){function n(){}n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o div { background-color: $primary-color-1; border-radius: $border-radius; diff --git a/e_metrobus/static/sass/_comparison.scss b/e_metrobus/static/sass/_comparison.scss index 31e20309..dcfe2e57 100644 --- a/e_metrobus/static/sass/_comparison.scss +++ b/e_metrobus/static/sass/_comparison.scss @@ -96,4 +96,8 @@ button.close-button:hover { display: flex; flex-direction: column; justify-content: center; + + @media (orientation: landscape) { + height: auto; + } } diff --git a/e_metrobus/static/sass/_components.scss b/e_metrobus/static/sass/_components.scss index d0e9f3ac..f686b097 100644 --- a/e_metrobus/static/sass/_components.scss +++ b/e_metrobus/static/sass/_components.scss @@ -27,6 +27,10 @@ button, button:hover, button:active, button:focus, button:visited, .button, .but margin-bottom: 0; } + &.button--question { + width: 10rem !important; + } + &.button--xsmall { width: 6rem !important; padding-left: .25rem!important; diff --git a/e_metrobus/static/sass/_dashboard.scss b/e_metrobus/static/sass/_dashboard.scss index 8d1a4668..0db98fc9 100644 --- a/e_metrobus/static/sass/_dashboard.scss +++ b/e_metrobus/static/sass/_dashboard.scss @@ -8,6 +8,15 @@ left: 50%; transform: translateY(-50%) translateX(-50%); + @media (orientation: landscape) { + padding-top: 1rem; + padding-bottom: 1rem; + position: relative; + top: 0; + left: 0; + transform: none; + } + @media only screen and (min-width: 600px) { width: 60%!important; margin: 0 auto; @@ -107,6 +116,10 @@ @media only screen and (min-width: 600px) { background-size: 18rem; } + + @media (orientation: landscape) { + display: none; + } } .flash-icons { diff --git a/e_metrobus/static/sass/_display_route.scss b/e_metrobus/static/sass/_display_route.scss index 80fd8e53..8d9357ad 100644 --- a/e_metrobus/static/sass/_display_route.scss +++ b/e_metrobus/static/sass/_display_route.scss @@ -7,6 +7,10 @@ height: 100%; background-color: $primary-color-1; + @media (orientation: landscape) { + top: 30%; + } + &__start { padding-bottom: .5rem; } @@ -24,6 +28,8 @@ position: relative; img { + margin-left: auto; + margin-right: auto; height: 3rem; margin-top: 6rem; } @@ -166,6 +172,17 @@ z-index: -1; } +.plotly-graph-div { + height:55vh; + width:100vw; + + @media (orientation: landscape) { + height: 100vh; + width: 80vw; + margin: 0 auto; + } +} + // Animations #display-route-line { diff --git a/e_metrobus/static/sass/_environment.scss b/e_metrobus/static/sass/_environment.scss index 3c7f2e90..f67c3ed3 100644 --- a/e_metrobus/static/sass/_environment.scss +++ b/e_metrobus/static/sass/_environment.scss @@ -145,6 +145,10 @@ .my-route__chart { margin-bottom: 1rem; height: 55vh; + + @media (orientation: landscape) { + height: 100vh; + } } .loader { diff --git a/e_metrobus/static/sass/_landing_page.scss b/e_metrobus/static/sass/_landing_page.scss index fa88a6bb..ff699894 100644 --- a/e_metrobus/static/sass/_landing_page.scss +++ b/e_metrobus/static/sass/_landing_page.scss @@ -184,12 +184,26 @@ text-align: left; padding: 0 .5rem; color: $gray-4; + animation: fadein 2s; + animation-delay: 2s; + animation-fill-mode: backwards; + + p { + text-align: center; + } + + @media (orientation: landscape) { + padding-top: 2rem; + } } &__bottom { padding: 0 .5rem 0; position: fixed; bottom: 0; - //height: 15vh; + + @media (orientation: landscape) { + position: relative; + } } } #language_popup { @@ -585,85 +599,6 @@ $desktop-padding-xxsmall: .6rem; } } -// CSS for Landscape only -@media only screen and (min-width: 1024px) { - .grid-container.landscape { - display: none!important; - } -} - -@media only screen and (orientation: landscape) { - .landscape { - background-image: url(/static/images/Dashboard_Pattern.svg); - background-size: 13rem; - height: 100%; - - &__header { - font-size: 1.55rem; - } - &__subheader { - font-size: 1rem; - color: $gray-4; - } - &__text { - font-size: 1.25rem; - font-weight: 700; - } - } -} - -@media only screen -and (max-width: 1024px) -and (orientation: landscape) { - - .landscape { - - &__header { - padding-top: 1rem; - } - &__img { - padding-top: 2.5rem; - } - &__text { - padding-top: 2.5rem; - } - &__img img { - height: 3rem; - } - } -} -@media only screen and (min-height: 370px) -and (max-height: 450px) -and (max-width: 1024px) -and (orientation: landscape) { - .landscape { - - &__header { - padding-top: 2rem; - } - } -} -@media only screen and (min-height: 450px) -and (max-height: 580px) -and (max-width: 1024px) -and (orientation: landscape) { - .landscape { - - &__header { - padding-top: 4rem; - } - } -} -@media only screen and (min-height: 580px) -and (max-width: 1024px) -and (orientation: landscape) { - .landscape { - - &__header { - padding-top: 9rem; - } - } -} .desktop__top-right { position: relative; diff --git a/e_metrobus/static/sass/_layout.scss b/e_metrobus/static/sass/_layout.scss index aef49772..0375b4d5 100644 --- a/e_metrobus/static/sass/_layout.scss +++ b/e_metrobus/static/sass/_layout.scss @@ -13,15 +13,27 @@ $top-bar-height: 2.8rem; position: relative; height: 100%; + @media (orientation: landscape) { + height: auto; + } + &.finished-page { section.footer { position: fixed; + + @media (orientation: landscape) { + position: relative; + } } } } .l-no-scroll { overflow: hidden; + + @media (orientation: landscape) { + overflow: scroll; + } } .l-scroll--nonav { @@ -59,10 +71,18 @@ $top-bar-height: 2.8rem; .top-bar, .footer { position: fixed; + + @media (orientation: landscape) { + position: relative; + } } .main-content { margin-top: $top-bar-height; - height: calc(100vh - #{$top-bar-height} - #{$footer-height}) + height: calc(100vh - #{$top-bar-height} - #{$footer-height}); + + @media (orientation: landscape) { + height: auto; + } } } @@ -75,6 +95,10 @@ $top-bar-height: 2.8rem; margin-top: 0; margin-bottom: 0; height: 100vh; + + @media (orientation: landscape) { + height: auto; + } } } diff --git a/e_metrobus/static/sass/_legal.scss b/e_metrobus/static/sass/_legal.scss index fcd8f092..c09d759e 100644 --- a/e_metrobus/static/sass/_legal.scss +++ b/e_metrobus/static/sass/_legal.scss @@ -37,6 +37,12 @@ &--rli img { height: 2.75rem; } + &--bvdi { + @media (orientation: landscape) { + max-width: 27rem; + margin: 0 auto; + } + } } } diff --git a/e_metrobus/static/sass/_question.scss b/e_metrobus/static/sass/_question.scss index 75c567f7..47f9557f 100644 --- a/e_metrobus/static/sass/_question.scss +++ b/e_metrobus/static/sass/_question.scss @@ -1,3 +1,8 @@ +@mixin question-padding { + padding-right: 2.5rem; + padding-left: 1rem; +} + .top-flash { padding-top: 1.5rem; text-align: center; @@ -14,7 +19,16 @@ } &__text { - margin: 1rem 1rem .5rem; + margin: 1rem 0 .5rem; + padding-left: 1rem; + padding-right: 1rem; + + h2 { + font-size: 1.25rem; + } + } + &__answer { + @include question-padding; } &__answer input { margin: 0; @@ -22,15 +36,60 @@ opacity: 0; } &__answer label { + position: relative; min-width: 100%; - background-color: $gray-1; + background-color: $gray-5; + color: $gray-2; border-radius: 50px; - padding: .3rem 0 .25rem 1rem; + padding: .3rem 1rem .25rem 1rem; margin: 1rem 0 0 0 !important; + line-height: 1.3rem; } &__answer input:checked + label { background-color: $primary-color-1; } + &__answer input.answered + label { + background-color: $gray-5; + color: $gray-2; + + &::after { + background-image: url(../images/icons/i_wrong.svg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + content: ""; + display: inline-block; + height: 1rem; + width: 1rem; + position: absolute; + right: -1.5rem; + top: 0; + bottom: 0; + margin: auto; + } + } + &__answer input.correct + label { + background-color: $primary-color-2-light; + color: $primary-color-2-darker; + } + &__answer input.correct.answered + label::after { + background-image: url(../images/icons/i_correct.svg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + content: ""; + display: inline-block; + height: 1rem; + width: 1rem; + position: absolute; + right: -1.5rem; + top: 0; + bottom: 0; + margin: auto; + } + .question__answer label { + color: #252424; + } &__btn { background-color: rgba(255, 255, 255, .75); position: fixed; @@ -44,8 +103,14 @@ background-color: #252424; } } + +#answers-view.question__answer input:not(.correct) + label { + background-color: $gray-5; + color: $gray-2; +} + .answer--ready { - background-color: $primary-color-1; + background-color: rgba(255, 255, 255, .75); input { background-color: #252424 !important; } @@ -96,54 +161,69 @@ } .answer__text { - margin: 1.5rem 1rem 0; + margin: 1.5rem 0 0; + @include question-padding; +} - &--top { - padding: 1rem; - border-radius: 1rem; +.answer__text-more { + margin-bottom: 8rem; - @include breakpoint(medium) { - text-align: center; - } + .accordion-content, + :last-child > .accordion-content:last-child { + border: none; + padding-left: 0; + padding-right: 0; } - &--correct { - background-color: $primary-color-2-light; + .accordion-title:hover, + .accordion-title:focus { + background-color: $white; + } - .answer__text-icon { - @include answer-top-box ($primary-color-2-dark); + .accordion-item .icon { + display: inline-block; + width: 1rem; + height: 1rem; + transform: translateY(2px); + background-image: url(../images/icons/i_next_gray.svg); + background-size: cover; + margin-right: .25rem; + } - &::before { - @include answer-top-box-icon ($primary-color-2-dark); - } - } + .accordion-item.is-active .icon { + background-image: url(../images/icons/i_back_gray.svg); + } + img { + margin: 2rem 0; } - &--wrong { - background-color: $error-color-light; + .accordion-title, + .accordion-title:visited, + .accordion-title:focus, + .accordion-title:active, + .accordion-title:hover { + padding-top: .25rem; + padding-left: 0; + font-size: 1rem; + color: $gray-4; - .answer__text-icon { - @include answer-top-box ($error-color); + & > div { + display: inline-block; + } - &::before { - @include answer-top-box-icon ($error-color); - } + &::before { + content: ""; } } - &--more { - margin-bottom: 8rem; - img { - margin: 2rem 0; + .accordion-item.is-active .accordion-title { + &::before { + content: ""; } } } -.a-answer-text-top { - animation: a-answer-text-top 1s cubic-bezier(0.230, 1.000, 0.320, 1.000) both; -} - -.a-answer-text { +.a-accordion-more { animation: a-answer-text 1s cubic-bezier(0.470, 0.000, 0.745, 0.715) 1.5s both; } @@ -151,17 +231,6 @@ animation: a-answer-text 1s cubic-bezier(0.470, 0.000, 0.745, 0.715) 2s both; } -@keyframes a-answer-text-top { - 0% { - opacity: 0; - transform: translateY(100rem); - } - 100% { - opacity: 1; - transform: translateY(0); - } -} - @keyframes a-answer-text { 0% { opacity: 0; @@ -178,7 +247,7 @@ &__next { position: fixed; bottom: 0; - background-color: $primary-color-1; + background-color: rgba(255, 255, 255, .9); a, a:hover { margin: 1.5rem 0 5.25rem; @@ -188,6 +257,6 @@ } .question__hint { - font-size: 1rem; + font-size: .875rem; color: $gray-2; } \ No newline at end of file diff --git a/e_metrobus/static/sass/_quiz_finished.scss b/e_metrobus/static/sass/_quiz_finished.scss index ce54c1fb..f95cf5da 100644 --- a/e_metrobus/static/sass/_quiz_finished.scss +++ b/e_metrobus/static/sass/_quiz_finished.scss @@ -70,11 +70,23 @@ top: 50%; padding-left: 1rem; padding-right: 1rem; + + @media (orientation: landscape) { + position: relative; + top: 0; + padding-top: 2rem; + padding-bottom: 2rem; + } } &__btn { position: absolute; bottom: 5rem; + + @media (orientation: landscape) { + position: relative; + bottom: 0; + } } &__reveal-wrap { diff --git a/e_metrobus/static/sass/_route.scss b/e_metrobus/static/sass/_route.scss index e20acd99..94969ea1 100644 --- a/e_metrobus/static/sass/_route.scss +++ b/e_metrobus/static/sass/_route.scss @@ -137,7 +137,11 @@ $station-font-line-height: 1rem; padding-bottom: 1rem; position: absolute; bottom: 0; - width: 100%; + width: 100%; + + @media (orientation: landscape) { + position: relative; + } .landing__bottom-btn { text-align: center; @@ -154,6 +158,11 @@ $station-font-line-height: 1rem; min-height: 0 !important; text-align: center; + @media (orientation: landscape) { + left: 0 !important; + transform: none; + } + .same-stations__img { display: block; padding-top: 4.5rem; diff --git a/e_metrobus/static/sass/_variables.scss b/e_metrobus/static/sass/_variables.scss index 71f3d047..08cf92e4 100644 --- a/e_metrobus/static/sass/_variables.scss +++ b/e_metrobus/static/sass/_variables.scss @@ -2,6 +2,7 @@ $primary-color-1: #F0D722; // BVG Verkehrgelb $primary-color-2: #17BEBB; $primary-color-2-light: #D8F3F3; $primary-color-2-dark: #25A6A3; +$primary-color-2-darker: #204140; $secondary-color: #252424; // BVG Verkehrsschwarz @@ -9,6 +10,7 @@ $gray-1: #EFEFEF; $gray-2: #B0B0B0; $gray-3: #D0D0D0; $gray-4: #757575; +$gray-5: #F5F5F5; $white: #FFF; // BVG Verkehrsweiß @@ -17,6 +19,7 @@ $light-text: $gray-1; $error-color: #d7724d; $error-color-light: #F4D8CE; +$error-color-darker: #532B1C; $border-radius: 1rem; diff --git a/e_metrobus/templates/base.html b/e_metrobus/templates/base.html index ffb3dddd..5fe3f97d 100644 --- a/e_metrobus/templates/base.html +++ b/e_metrobus/templates/base.html @@ -2,12 +2,18 @@ + + + + + + {% block title %}E-MetroBus{% endblock title %}{% block subtitle %}{% endblock %} - - + + @@ -37,11 +43,10 @@ --> -
+ - {% include "includes/landscape.html" %} -
+
{{top_bar}} @@ -64,6 +69,7 @@ + {% compress js %} @@ -85,14 +91,9 @@ resetHeight(); {% if top_bar.share_link_js %} - function shareLink() { - var text = "{{top_bar.share_url}}"; - var input = document.createElement('input'); - input.setAttribute('value', text); - document.body.appendChild(input); - input.select(); - var result = document.execCommand('copy'); - document.body.removeChild(input); + new ClipboardJS('#share_link'); + + function link_copied() { $('#link_copied').fadeIn(); setTimeout( function () { @@ -112,15 +113,15 @@ }); } - function disable_landscape() { - $(".landscape").removeClass("show-for-landscape"); - $(".landscape").hide(); - $(".portrait").removeClass("show-for-portrait"); - } + function check_mobile() { + let check = false; + (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); + return check; + }; - function enable_landscape() { - $(".landscape").addClass("show-for-landscape"); - $(".portrait").addClass("show-for-portrait"); + if (!check_mobile()) { + $("#desktop").show(); + $("#portrait").hide(); } {% endblock javascript %} diff --git a/e_metrobus/templates/includes/landscape.html b/e_metrobus/templates/includes/landscape.html index f8a2dabe..d20f01fb 100644 --- a/e_metrobus/templates/includes/landscape.html +++ b/e_metrobus/templates/includes/landscape.html @@ -1,19 +1,17 @@ {% load i18n %} -
-
-
- {% trans "E-Metrobus Berlin" %} -
-
- {% trans "Elektrifizierung von MetroBus-Linien im Berliner ÖPNV mit Schnellladeinfrastruktur" %} -
-
- Elektro-Bus -
-
- {% trans "Bitte besuchen Sie diese Seite im Portrait Modus, wenn Sie Interesse am E-Metrobus Projekt haben." %} -
+
+
+ {% trans "E-Metrobus Berlin" %} +
+
+ {% trans "Elektrifizierung von MetroBus-Linien im Berliner ÖPNV mit Schnellladeinfrastruktur" %} +
+
+ Elektro-Bus +
+
+ {% trans "Bitte besuchen Sie diese Seite im Portrait Modus, wenn Sie Interesse am E-Metrobus Projekt haben." %}
diff --git a/e_metrobus/templates/navigation/answer.html b/e_metrobus/templates/navigation/answer.html index 1d5b528b..f0c1cf47 100644 --- a/e_metrobus/templates/navigation/answer.html +++ b/e_metrobus/templates/navigation/answer.html @@ -6,18 +6,73 @@ {% block subtitle %} - {% trans 'Antwort' %}{% endblock %} {% block content %} -
-
-
-
{%if answer %}{% trans 'Korrekt' %}{% else %}{% trans 'Falsch' %}{% endif %}
- {% trans question.short_answer %} -
-
- {% include question.template %} -
-
- {% trans "Zur nächsten Frage" %} +
+
+
+
+ {% for flash in flashes %} + {% with "images/icons/i_flash_"|add:flash.value|add:".svg" as flash_icon %} + + {% endwith %} + {% endfor %} +
+
+ {% csrf_token %} +

{% trans question.question %}

+ {% if question.is_multiple_choice %} + ({% trans 'Mehrere Antworten möglich' %}) + {% endif %} +
+
+
+ + {% for answer in question.answers %} + {% if question.is_multiple_choice %} + + {% else %} + + {% endif %} + + {% endfor %} +
+
+
+ +
+
+ {% if category_finished %} + {% trans "Weiter" %} + {% else %} + {% trans "Weiter" %} + {% endif %} +
{% endblock content %} + +{% block javascript %} + {{block.super}} + +{% endblock javascript %} diff --git a/e_metrobus/templates/navigation/display_route.html b/e_metrobus/templates/navigation/display_route.html index 336596da..f0d0a728 100644 --- a/e_metrobus/templates/navigation/display_route.html +++ b/e_metrobus/templates/navigation/display_route.html @@ -19,7 +19,7 @@
{{stations.0}}
-
+
{% trans 'Symbolisierte Strecke' %} @@ -48,7 +48,7 @@