diff --git a/member_group_size_calc/templates/member_group_size_calc/index.html b/member_group_size_calc/templates/member_group_size_calc/index.html index e55e4c7d0551ac5f038631432f0f7c1a6d6f5724..d13dfd92f6c5a61bfd7d21177a0c8f87853ea527 100644 --- a/member_group_size_calc/templates/member_group_size_calc/index.html +++ b/member_group_size_calc/templates/member_group_size_calc/index.html @@ -1,8 +1,117 @@ -{% extends "shared/base.html" %} +{% extends "shared/base.html" %} + +{% load render_bundle from webpack_loader %} {% block name %}Kalkulačka velikosti skupiny členů{% endblock %} {% block description %}TODO - Description.{% endblock %} +{% block head %} + {% render_bundle "member_group_size_calc" %} +{% endblock %} + {% block content %} - aaa + <main class="p-10"> + <h1 class="text-6xl font-bebas mb-5">Kalkulačka výpočtu skupiny členů</h1> + + <div class="bg-amber-100 p-4 flex flex-row items-center gap-4 mb-4 lg:w-[768px] md:w-full"> + <i class="fa-solid fa-lightbulb text-3xl text-amber-800"></i> + <div class="text-amber-800"> + Tato kalkulačka slouží pro výpočet skupiny členů podle <a + class="underline text-amber-900" + href="https://wiki.pirati.cz/rules/jdr" + >Jednacího řádu</a>. + </div> + </div> + + <div class="bg-gray-100 p-4 flex flex-row items-start gap-4 mb-4 lg:w-[768px] md:w-full"> + <i class="fa-solid fa-circle-info text-3xl text-gray-800"></i> + <div class="text-gray-800"> + <h2 class="text-lg font-bold mb-3">Jednací řád celostátního fóra</h2> + + <div class="mb-3"> + <strong>§ 5 Skupina členů</strong> + </div> + + <p> + <strong>Skupinou členů</strong> se rozumí jen taková skupina, která čítá aspoň stanovený <a + class="underline text-gray-900" + href="https://lide.pirati.cz/" + >počet členů strany</a>, kteří podpořili určitý návrh. Počet členů se stanoví u návrhu na zahájení jednání jako dvojnásobek druhé odmocniny z počtu přítomných členů, nejméně však jedna setina a nejvýše jedna pětina z počtu přítomných členů. U návrhu na již zahájeném jednání se takto stanovený počet snižuje na polovinu. + </p> + </div> + </div> + + <div class="text-lg mb-4"> + Počet členů sdružení či orgánu: + <input + id="member-count" + class="w-[7ch]" + type="number" + value="0" + ><button + id="calculate" + class="ml-3 px-4 py-2 bg-black text-white duration-100 font-bebas hover:bg-white hover:text-black" + >OK</button> + </div> + + <div class="mb-4 flex gap-3 items-start"> + <table class="inline-block table-auto"> + <thead> + <tr> + <th + class="px-3 py-2 bg-black text-white text-center text-xl font-bebas border border-black" + colspan="2" + >Počty členů</th> + </tr> + </thead> + <tbody> + <tr class="border border-black"> + <th class="font-bold text-left px-4 py-2">Setina</th> + <th class="font-normal px-4 py-2" id="hundredth">0</th> + </tr> + <tr class="border border-black"> + <th class="font-bold text-left px-4 py-2">Desetina</th> + <th class="font-normal px-4 py-2" id="tenth">0</th> + </tr> + <tr class="border border-black"> + <th class="font-bold text-left px-4 py-2">Pětina</th> + <th class="font-normal px-4 py-2" id="fifth">0</th> + </tr> + <tr class="border border-black"> + <th class="font-bold text-left px-4 py-2">2x odmocnina</th> + <th class="font-normal px-4 py-2" id="two-square-roots">0</th> + </tr> + </tbody> + </table> + + <table class="inline-block table-auto"> + <thead> + <tr> + <th + class="px-3 py-2 bg-black text-white text-center text-xl font-bebas border border-black" + colspan="2" + >Hodnoty podle jednacího řádu</th> + </tr> + </thead> + <tbody> + <tr class="border border-black"> + <th class="font-bold text-left px-4 py-2">Rozeslání členského podnětu</th> + <th class="font-normal px-4 py-2" id="member-motion">0</th> + </tr> + <tr class="border border-black"> + <th class="font-bold text-left px-4 py-2">Zařazení na běžící jednání</th> + <th class="font-normal px-4 py-2" id="ongoing-motion">0</th> + </tr> + <tr class="border border-black"> + <th class="font-bold text-left px-4 py-2">Svolání jednání</th> + <th class="font-normal px-4 py-2" id="motion-start">0</th> + </tr> + </tbody> + </table> + </div> + + <p class="font-light"> + <i>Vypočtené hodnoty jsou zaokrouhleny na celé číslo nahoru.</i> + </p> + </main> {% endblock %} diff --git a/package.json b/package.json index 25d4280aef2cb45a47de1ef7004579293fa5fb8e..62c00d323ff51eff9b20b58024cac987df959a84 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,9 @@ "description": "", "private": true, "dependencies": { + "@fortawesome/fontawesome-free": "^6.2.1", "css-loader": "^6.7.3", + "jquery": "^3.6.3", "style-loader": "^3.3.1", "tailwindcss": "^3.2.4", "webpack": "^5.75.0", diff --git a/rybicka/settings/base.py b/rybicka/settings/base.py index 6750d6c1bd890b519360826820b2c544e5e3538d..92b18225f8d28effdb5f8d8921b931e7c8bb071f 100644 --- a/rybicka/settings/base.py +++ b/rybicka/settings/base.py @@ -39,8 +39,6 @@ STATIC_ROOT = os.environ.get( # Application definition INSTALLED_APPS = [ - "django.contrib.admin", - "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", @@ -57,7 +55,6 @@ MIDDLEWARE = [ "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] @@ -73,7 +70,6 @@ TEMPLATES = [ "context_processors": [ "django.template.context_processors.debug", "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], }, @@ -90,26 +86,6 @@ DATABASES = { "default": dj_database_url.config(conn_max_age=600) } - -# Password validation -# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - - # Internationalization # https://docs.djangoproject.com/en/4.1/topics/i18n/ diff --git a/rybicka/urls.py b/rybicka/urls.py index 54f14a81014ad463e165cffe312f494311d44b92..75edfc43b017332f5fbae7052f57e71800b2a297 100644 --- a/rybicka/urls.py +++ b/rybicka/urls.py @@ -13,10 +13,8 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ -from django.contrib import admin from django.urls import include, path urlpatterns = [ - path("", include("member_group_size_calc.urls")), - path('admin/', admin.site.urls), + path("vypocet-skupiny-clenu", include("member_group_size_calc.urls")), ] diff --git a/shared/static/shared/style.css b/shared/static/shared/style.css index d51d6123a965e071c3d71ebb41d6448331d75671..7f9ffed091c55388c1180be20ca522404990ad1c 100644 --- a/shared/static/shared/style.css +++ b/shared/static/shared/style.css @@ -517,8 +517,218 @@ html { --tw-backdrop-sepia: ; } +.static { + position: static; +} + +.mb-5 { + margin-bottom: 1.25rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.ml-3 { + margin-left: 0.75rem; +} + +.block { + display: block; +} + +.inline-block { + display: inline-block; +} + +.flex { + display: flex; +} + +.table { + display: table; +} + +.w-\[7ch\] { + width: 7ch; +} + +.table-auto { + table-layout: auto; +} + +.flex-row { + flex-direction: row; +} + +.items-start { + align-items: flex-start; +} + +.items-center { + align-items: center; +} + +.gap-4 { + gap: 1rem; +} + +.gap-3 { + gap: 0.75rem; +} + +.border { + border-width: 1px; +} + +.border-black { + --tw-border-opacity: 1; + border-color: rgb(0 0 0 / var(--tw-border-opacity)); +} + +.bg-amber-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 243 199 / var(--tw-bg-opacity)); +} + +.bg-gray-100 { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + +.p-10 { + padding: 2.5rem; +} + +.p-4 { + padding: 1rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +.text-left { + text-align: left; +} + +.text-center { + text-align: center; +} + +.font-bebas { + font-family: Bebas Neue, ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; +} + +.text-6xl { + font-size: 3.75rem; + line-height: 1; +} + +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + +.font-bold { + font-weight: 700; +} + +.font-normal { + font-weight: 400; +} + +.font-light { + font-weight: 300; +} + +.text-amber-800 { + --tw-text-opacity: 1; + color: rgb(146 64 14 / var(--tw-text-opacity)); +} + +.text-amber-900 { + --tw-text-opacity: 1; + color: rgb(120 53 15 / var(--tw-text-opacity)); +} + +.text-gray-800 { + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity)); +} + +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.underline { + text-decoration-line: underline; +} + +.duration-100 { + transition-duration: 100ms; +} + @layer typography { .font-bebas { font-family: "Bebas Neue"; } } + +.hover\:bg-white:hover { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.hover\:text-black:hover { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); +} + +@media (min-width: 768px) { + .md\:w-full { + width: 100%; + } +} + +@media (min-width: 1024px) { + .lg\:w-\[768px\] { + width: 768px; + } +} diff --git a/shared/templates/shared/base.html b/shared/templates/shared/base.html index 314d68363062096e775c30f071cb2dd2549a71d2..dcadafc96b347be7cb2f250aea90b11a621bd000 100644 --- a/shared/templates/shared/base.html +++ b/shared/templates/shared/base.html @@ -1,4 +1,5 @@ {% load render_bundle from webpack_loader %} +{% load static %} <!DOCTYPE html> <html lang="cs"> @@ -9,7 +10,23 @@ <title>{% block name %}{% endblock %}</title> <meta name="description" content="{% block description %}{% endblock %}"> - {% render_bundle "main" %} + <link + rel="stylesheet" + type="text/css" + href="{% static "shared/style.css" %}" + > + <link + rel="stylesheet" + href="https://gfonts.pirati.cz/css2?family=Bebas+Neue&family=Roboto+Condensed:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&display=swap" + > + + <link rel="shortcut icon" type="image/png" href="https://www.pirati.cz/static/shared/favicon/favicon-196.png" sizes="196x196"> + <link rel="shortcut icon" type="image/png" href="https://www.pirati.cz/static/shared/favicon/favicon-128.png" sizes="128x128"> + <link rel="shortcut icon" type="image/png" href="https://www.pirati.cz/static/shared/favicon/favicon-96.png" sizes="96x96"> + <link rel="shortcut icon" type="image/png" href="https://www.pirati.cz/static/shared/favicon/favicon-32.png" sizes="32x32"> + <link rel="shortcut icon" type="image/png" href="https://www.pirati.cz/static/shared/favicon/favicon-16.png" sizes="16x16"> + + {% render_bundle "base" %} {% block head %}{% endblock %} </head> diff --git a/static_src/member_group_size_calc.js b/static_src/member_group_size_calc.js new file mode 100644 index 0000000000000000000000000000000000000000..85bf1402d8aafe5adeba5d3f6dccdbaa4a273ca5 --- /dev/null +++ b/static_src/member_group_size_calc.js @@ -0,0 +1,46 @@ +import $ from "jquery"; + +import "@fortawesome/fontawesome-free/js/fontawesome"; +import "@fortawesome/fontawesome-free/js/solid"; +import "@fortawesome/fontawesome-free/js/regular"; + +$(window).ready( + () => { + $("#member-count").on( + "keypress", + event => { + if (event.key === "Enter") { + $("#calculate").click(); + } + } + ) + $("#calculate").on( + "click", + event => { + const memberCount = Number($("#member-count").val()); + + if (isNaN(memberCount) || memberCount === 0) { + alert("Prosím, zadej skutečný počet členů."); + return; + } + + const hundredth = Math.ceil(memberCount / 100); + const fifth = Math.ceil(memberCount / 5); + const twoSquareRoots = Math.ceil(2 * Math.sqrt(memberCount)); + + $("#hundredth").html(hundredth); + $("#tenth").html(Math.ceil(memberCount / 10)); + $("#fifth").html(fifth); + $("#two-square-roots").html(twoSquareRoots); + + const motionStart = Math.max( + Math.min(fifth, twoSquareRoots), hundredth + ); + const motion = Math.ceil(motionStart / 2); + + $("#member-motion,#ongoing-motion").html(motion); + $("#motion-start").html(motionStart); + } + ); + } +) diff --git a/webpack.config.js b/webpack.config.js index 43801f48bfd685582b5861359c60ce8d298285cc..bb38e048355512ab66e1552d8d8e44d2ab37c14e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,7 +4,10 @@ const BundleTracker = require('webpack-bundle-tracker'); module.exports = { mode: "production", context: __dirname, - entry: path.resolve("static_src", "base.js"), + entry: { + base: path.resolve("static_src", "base.js"), + member_group_size_calc: path.resolve("static_src", "member_group_size_calc.js"), + }, output: { path: path.resolve(__dirname, "shared", "static", "shared"), filename: "[name]-[fullhash].js",