diff --git a/src/plainui/jinja2/plainui/components/header_buttons.html b/src/plainui/jinja2/plainui/components/header_buttons.html index 55067cc0cbf0bf3cbefa1a3feb66da3179d2498c..121a19a530a6eaac72e2491a38c8f5d4acfffe29 100644 --- a/src/plainui/jinja2/plainui/components/header_buttons.html +++ b/src/plainui/jinja2/plainui/components/header_buttons.html @@ -49,22 +49,22 @@ <ellipse class="st3" cx="250" cy="250" rx="100.58" ry="169"/> <path class="st3" d="M250 84.68v329.59M85.83 250h328.49"/> </svg> - <form + <form class="rc3-header__additional-lang" - method="POST" + method="POST" action="{{ url('plainui:modify_language') }}" > {{ csrf_input }} <input type="hidden" name="next" value="{{ request.get_full_path() }}"> - <button - class="btn btn-icont px-2" + <button + class="btn btn-icont px-2" value="de" name="language" > {{ _("de") }} </button> - <button - class="btn btn-icont px-2" + <button + class="btn btn-icont px-2" value="en" name="language" > @@ -85,8 +85,8 @@ {% macro logout() -%} {% if request.user.is_authenticated %} - <a - class="rc3-header__additional-btn btn-icon p-2" + <a + class="rc3-header__additional-btn btn-icon py-2 pl-2 pr-0" title="{{ _("logout") }}" href="{{ url('plainui:logout') }}" > @@ -96,8 +96,8 @@ </svg> </a> {% else %} - <a - class="rc3-header__additional-btn btn-icon p-2" + <a + class="rc3-header__additional-btn btn-icon py-2 pl-2 pr-0" title="{{ _("login") }}" href="{{ url('plainui:login') }}" > @@ -110,9 +110,9 @@ {%- endmacro %} {% macro report(report_url, kind="url", next=request.get_full_path() , title=_("report this url"), color="transparent" ) %} - <a - href="{{ url('plainui:report_content') ~ '?kind=' ~ kind ~ '&kind_data=' ~ report_url | urlencode ~ '&next=' ~ next }}" - class="btn-icon-big btn btn-{{ color }} p-2" + <a + href="{{ url('plainui:report_content') ~ '?kind=' ~ kind ~ '&kind_data=' ~ report_url | urlencode ~ '&next=' ~ next }}" + class="btn-icon-big btn btn-{{ color }} p-2" title="{{ title }}" > <svg width="1.25rem" height="1.25rem" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500" fill="currentColor"> @@ -123,10 +123,10 @@ {% endmacro %} {% macro share(share_url, title=_("share this "), color="transparent" ) -%} - <a - href="{{ share_url }}" - class="btn-icon-big btn btn-{{ color }} p-2" - title="{{ title }}" + <a + href="{{ share_url }}" + class="btn-icon-big btn btn-{{ color }} p-2" + title="{{ title }}" target="_blank" > <svg width="1.25rem" height="1.25rem" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500" fill="currentColor"> @@ -143,9 +143,9 @@ <input type="hidden" name="id" value="{{ sch_id }}"> {%- if sch_is %} <input type="hidden" name="mode" value="remove"> - <button - type="submit" - id="sch_{{ sch_id }}" + <button + type="submit" + id="sch_{{ sch_id }}" class="active btn-icon-big btn btn-{{ color }} p-2" title="{{ _("remove from schedule") }}" > @@ -155,10 +155,10 @@ </button> {%- else -%} <input type="hidden" name="mode" value="add"> - <button - type="submit" - id="sch_{{ sch_id }}" - class="btn-icon-big btn btn-{{ color }} p-2" + <button + type="submit" + id="sch_{{ sch_id }}" + class="btn-icon-big btn btn-{{ color }} p-2" title="{{ _("add to schedule") }}" > <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" style="position: relative; top: 2px;" fill="currentColor" class="bi bi-calendar2-week" viewBox="0 0 16 16"> @@ -181,10 +181,10 @@ {%- if fav_is %} <input type="hidden" name="mode" value="remove"> - <button - type="submit" - id="fav_{{ fav_id }}" - class="active btn-icon-big btn btn-{{ color }} p-2" + <button + type="submit" + id="fav_{{ fav_id }}" + class="active btn-icon-big btn btn-{{ color }} p-2" title="{{ _("remove from favorites") }}" > <svg width="16px" height="16px" style="position: relative; top: 2px;" xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-heart-fill" viewBox="0 0 16 16"> @@ -193,10 +193,10 @@ </button> {%- else -%} <input type="hidden" name="mode" value="add"> - <button - type="submit" - id="fav_{{ fav_id }}" - class="btn-icon-big btn btn-{{ color }} p-2" + <button + type="submit" + id="fav_{{ fav_id }}" + class="btn-icon-big btn btn-{{ color }} p-2" title="{{ _("add to favorites") }}" > <svg width="1.25rem" height="1.25rem" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500" fill="currentColor"> <style>.st0{display:none}.st1{display:inline}.st2{fill:none;stroke:#000;stroke-width:18;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}</style> @@ -206,3 +206,52 @@ {% endif -%} </form> {% endmacro %} + +{% macro themeswitcher() -%} + <form method="POST" action="{{ url('plainui:modify_theme') }}"> + {{ csrf_input }} + <input type="hidden" name="next" value="{{ request.get_full_path() }}"> + {% if user.theme == 'full' %} + <button + class="rc3-header__additional-btn btn btn-icon py-2 pl-2 pr-0" + value="default" + name="theme" + title="switch to eyecandy theme" + > + <!-- icon animations full--> + <svg width="1.25rem" height="1.25rem" fill="currentColor" version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500" xml:space="preserve"><style>.st0{display:none}.st1{display:inline}.st2{fill:none;stroke:#000;stroke-width:18;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}</style><path d="M411.1 237.1 142.2 81.8c-4.8-2.8-10.7-2.8-15.5 0s-7.8 7.9-7.8 13.4v310.5c0 5.5 3 10.7 7.8 13.4 2.4 1.4 5 2.1 7.8 2.1s5.4-.7 7.8-2.1l268.9-155.2c4.8-2.8 7.8-7.9 7.8-13.4s-3.1-10.7-7.9-13.4z" id="animation"/></svg> + </button> + {% else %} + <button + class="rc3-header__additional-btn btn btn-icon py-2 pl-2 pr-0" + value="full" + title="switch to eyecandy deluxe theme" + name="theme" + > + <!-- icon animations --> + <svg width="1.25rem" height="1.25rem" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500" xml:space="preserve"><style>.st0{display:none}.st1{display:inline}.st2{fill:none;stroke:#000;stroke-width:18;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}</style><path d="M411.13 237.06 142.25 81.82a15.543 15.543 0 0 0-15.5 0c-4.78 2.76-7.75 7.9-7.75 13.42v310.48c0 5.52 2.97 10.66 7.75 13.42 2.35 1.36 5.03 2.08 7.75 2.08s5.4-.72 7.75-2.08L411.13 263.9c4.78-2.76 7.75-7.9 7.75-13.42s-2.96-10.66-7.75-13.42zm-38.75 13.42L150 378.88V122.09l222.38 128.39z" id="animation"/></svg> + </button> + {% endif %} + {% if user.theme == 'full' or user.theme == 'default' %} + <button + class="rc3-header__additional-btn btn btn-icon p-2" + value="distractfree" + title="switch to dark theme" + name="theme" + > + <!-- icon bulb active --> + <svg width="1.25rem" height="1.25rem" fill="currentColor" version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500" xml:space="preserve"><style>.st0{display:none}.st1{display:inline}.st3{fill:none;stroke:#000;stroke-width:18;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}</style><g id="light"><path d="M250.2 38.1c-76.6 0-139 62.3-139 139 0 26.4 7.5 52.2 21.6 74.5 13.3 21 31.9 37.9 54.1 49.2v14c0 11.8 9.6 21.4 21.4 21.4h85.1c11.8 0 21.4-9.6 21.4-21.4v-14.6c21.8-11.4 40.1-28.4 53.2-49.2 13.9-22.2 21.3-47.7 21.3-73.8-.1-76.7-62.4-139.1-139.1-139.1z"/><path d="M250.8 86.5c-2.1 0-21.3.3-41.6 11.5-19.3 10.6-42.9 32.9-46 79.4-.5 8 5.5 14.9 13.5 15.5h1c7.6 0 14-6 14.5-13.6 1.8-26.6 12.1-45.4 30.6-55.7 13.8-7.7 27.9-8.1 28-8.1 8 0 14.5-6.5 14.5-14.5 0-7.9-6.5-14.5-14.5-14.5z" style="fill:rgb(0, 0, 0)"/><path d="M294.4 351.4H211c-16.4 0-29.8 13.3-29.8 29.7v19.1c0 11.6 6.7 21.8 16.6 26.6 3.1 18.3 19 32.3 38.2 32.3h29.1c18.5 0 34.1-13.1 37.9-30.5 12.2-3.7 21.2-15.1 21.2-28.5V381c-.1-16.2-13.4-29.6-29.8-29.6z"/></g></svg> + </button> + {% else %} + <button + class="rc3-header__additional-btn btn btn-icon p-2" + value="default" + title="switch to eyecandy theme" + name="theme" + > + <!-- icon bulb --> + <svg width="1.25rem" height="1.25rem" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500" xml:space="preserve"><style>.st0{display:none}.st1{display:inline}.st2{fill:none;stroke:#000;stroke-width:18;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}</style><g id="light"><path d="M250.76 86.54c-2.12 0-21.29.32-41.59 11.46-19.26 10.57-42.88 32.92-46 79.43-.54 8 5.54 14.95 13.53 15.48.33.02.66.03.99.03 7.62 0 13.99-5.96 14.51-13.57 1.79-26.63 12.09-45.36 30.62-55.69 13.84-7.71 27.92-8.06 27.97-8.06 8-.02 14.52-6.54 14.52-14.54-.01-8.01-6.53-14.54-14.55-14.54z"/><path d="M250.22 38.14c-76.64 0-138.99 62.35-138.99 138.99 0 26.44 7.48 52.19 21.63 74.48a139.018 139.018 0 0 0 54.06 49.25v13.96c0 11.79 9.59 21.38 21.38 21.38h85.08c11.79 0 21.38-9.59 21.38-21.38V300.2a139.15 139.15 0 0 0 53.17-49.25c13.92-22.17 21.27-47.69 21.27-73.82 0-76.64-62.35-138.99-138.98-138.99zm35.54 243.5v25.55h-69.84v-25.11l-8.8-3.76c-40.64-17.38-66.9-57.1-66.9-101.19 0-60.65 49.34-109.99 109.99-109.99 60.65 0 109.99 49.34 109.99 109.99 0 43.56-25.82 83.09-65.79 100.7l-8.65 3.81zM294.4 351.41h-83.38c-16.4 0-29.75 13.34-29.75 29.74v19.14c0 11.58 6.73 21.75 16.56 26.65 3.07 18.32 19.04 32.32 38.21 32.32h29.07c18.53 0 34.07-13.08 37.86-30.49 12.23-3.69 21.16-15.06 21.16-28.48v-19.14c.01-16.4-13.33-29.74-29.73-29.74zm.66 29.75v19.14c0 .36-.3.66-.66.66h-83.38c-.36 0-.66-.3-.66-.66v-19.14c0-.36.3-.66.66-.66h83.38c.36 0 .66.29.66.66z"/></g></svg> + </button> + {% endif %} + </form> +{%- endmacro %} diff --git a/src/plainui/jinja2/plainui/header.html b/src/plainui/jinja2/plainui/header.html index a111d889d39c0f98bd8cdd821b6f10e5643a6fde..5e516836f4c768f94e814977a5fa18e1e50036c4 100644 --- a/src/plainui/jinja2/plainui/header.html +++ b/src/plainui/jinja2/plainui/header.html @@ -24,16 +24,16 @@ <div class="rc3-header__additional"> <div class="d-inline-block"> <div class="d-flex justify-content-between"> - <a + <a class="rc3-header-link ml-3" href="{{ url('plainui:fahrplan') }}" title="{{ _("plan") }}" > {{ _("plan") }} </a> - <a + <a class="rc3-header-link ml-3 text-nowrap" - href="{{ url('plainui:personal_message') }}" + href="{{ url('plainui:personal_message') }}" title="{{ _("chat") }}" > {{ _("chat") }} @@ -44,16 +44,16 @@ </span> {% endif %} </a> - <a + <a class="rc3-header-link ml-3" title="{{ _("board") }}" href="{{ url('plainui:board') }}" > {{ _("board") }} </a> - <a + <a class="rc3-header-link ml-3" - href="{{ url('plainui:userprofile') }}" + href="{{ url('plainui:userprofile') }}" title="{{ _('profile') }}" > {{ _('profile') }} @@ -66,6 +66,7 @@ {{ hbtns.bulb() }} {{ hbtns.heart() }} --> + {{ hbtns.themeswitcher() }} {% if fav_info %} {{ hbtns.fav(fav_info['id'], fav_info['type'], fav_info['is']) }} {% endif %} diff --git a/src/plainui/styles/components/_header.scss b/src/plainui/styles/components/_header.scss index 63dcc2963d97a0e109464c5f61cb345234a49679..ae416f977be0acfd1b5a9a3b4160b51e8a4f10bd 100644 --- a/src/plainui/styles/components/_header.scss +++ b/src/plainui/styles/components/_header.scss @@ -95,10 +95,6 @@ height: 20px; width: 20px; } - - &:last-of-type { - padding-right: 0 !important; - } } &-lang { diff --git a/src/plainui/tests.py b/src/plainui/tests.py index e6f4fb3a2d7626a361aca4f4c520ebd726d2ed11..662951af687e77f382703df2929954363a4da398 100644 --- a/src/plainui/tests.py +++ b/src/plainui/tests.py @@ -445,6 +445,43 @@ class ViewsTest(TestCase): self.assertFalse(self.user.receive_video) self.assertSetsMessage(resp, 'Updated Profile') + def test_ModifyThemeView_get(self): + self.assertNeedsLogin(reverse('plainui:search')) + resp = self.client.get(reverse('plainui:search'), follow=False) + self.assertRedirects(resp, reverse('plainui:index')) + + def test_ModifyThemeView_post(self): + self.assertNeedsLogin(reverse('plainui:modify_theme'), post=True) + + # setting theme works + resp = self.client.post(reverse('plainui:modify_theme'), { + 'theme': 'distractfree', + 'next': reverse('plainui:landing'), + }) + self.assertRedirects(resp, reverse('plainui:landing')) + self.user.refresh_from_db() + self.assertEqual(self.user.theme, 'distractfree') + self.assertEqual(self.client.session['theme'], 'distractfree') + + # invalid dst redirects to index + resp = self.client.post(reverse('plainui:modify_theme'), { + 'theme': 'distractfree_nobg', + 'next': 'https://www.google.de/', + }) + self.assertRedirects(resp, reverse('plainui:index')) + self.user.refresh_from_db() + self.assertEqual(self.user.theme, 'distractfree_nobg') + self.assertEqual(self.client.session['theme'], 'distractfree_nobg') + + # invalid theme does not change anything, next defaults to index + resp = self.client.post(reverse('plainui:modify_theme'), { + 'theme': 'doesnotexist', + }) + self.assertRedirects(resp, reverse('plainui:index')) + self.user.refresh_from_db() + self.assertEqual(self.user.theme, 'distractfree_nobg') + self.assertEqual(self.client.session['theme'], 'distractfree_nobg') + @override_settings(LANGUAGE_CODE='en', PRETIX_SECRET_KEY='^v^', PRETIX_ISSUER='tickets.events.ccc.de') @freeze_time(datetime(2020, 12, 28, 1, 0, 0, tzinfo=utc)) def test_RedeemTokenView(self): diff --git a/src/plainui/urls.py b/src/plainui/urls.py index a59e255c55a8cf0a8e506fafb4064a346ccacf87..58d162a34b7f7441de8cb8130e3824ceb58fab2e 100644 --- a/src/plainui/urls.py +++ b/src/plainui/urls.py @@ -41,6 +41,7 @@ urlpatterns = [ path('modify_favorites', views.ModifyFavoritesView.as_view(), name='modify_favorites'), path('modify_language', views.ModifyLanguageView.as_view(), name='modify_language'), path('modify_personal_calendar', views.ModifyPersonalCalendarView.as_view(), name='modify_personal_calendar'), + path('modify_theme', views.ModifyThemeView.as_view(), name='modify_theme'), path('index', views.IndexView.as_view(), name='index'), path('pm/inbox', views.PersonalMessageListView.as_view(), name='personal_message'), path('pm/outbox', views.PersonalMessageListView.as_view(sent=True), name='personal_message_outbox'), diff --git a/src/plainui/views.py b/src/plainui/views.py index 0c75f89635a61c68e9152f62f1b53d0e4f53af12..21ed14a56a87b126d4e9f52ae810f797ad6f6d0c 100644 --- a/src/plainui/views.py +++ b/src/plainui/views.py @@ -439,6 +439,28 @@ class ProfileView(ConferenceRequiredMixin, UpdateView): return resp +class ModifyThemeView(ConferenceRequiredMixin, View): + def get(self, request, **kwargs): + return redirect(reverse('plainui:index')) + + def post(self, request): + redirect_to = request.POST.get('next') or reverse('plainui:index') + url_is_safe = url_has_allowed_host_and_scheme( + url=redirect_to, + allowed_hosts=[self.request.get_host()], + require_https=self.request.is_secure(), + ) + if not url_is_safe: + redirect_to = reverse('plainui:index') + + new_theme = request.POST['theme'] + if new_theme in PlatformUser.Theme.values: + self.request.user.theme = new_theme + self.request.user.save(update_fields=['theme']) + self.request.session['theme'] = new_theme + return redirect(redirect_to) + + class ManageBadgeView(ConferenceRequiredMixin, UpdateView): template_name = 'plainui/manage_badges.html' form_class = RedeemBadgeForm