diff --git a/multigranja/apps/core/context_processors.py b/multigranja/apps/core/context_processors.py index ba35f29..20ad500 100644 --- a/multigranja/apps/core/context_processors.py +++ b/multigranja/apps/core/context_processors.py @@ -3,20 +3,20 @@ from entities.models import Farm # Injects the selected farm and the list of farms into the template context for authenticated users. def selected_farm_processor(request): selected_farm = None - farms = None - + farms = Farm.objects.none() + if request.user.is_authenticated: - farms = request.user.farms.only("id", "name") + farms = request.user.farms.filter(is_active=True).only("id", "name") + + farm_id = request.session.get("selected_farm_id") - farm_id = request.session.get('selected_farm_id') - if farm_id: - try: - selected_farm = farms.get(id=farm_id) - except Farm.DoesNotExist: - request.session.pop('selected_farm_id', None) + selected_farm = farms.filter(id=farm_id).first() + + if selected_farm is None: + request.session.pop("selected_farm_id", None) return { - 'SELECTED_FARM': selected_farm, - 'farms': farms + "SELECTED_FARM": selected_farm, + "farms": farms, } \ No newline at end of file diff --git a/multigranja/apps/core/static/core/css/components/buttons.css b/multigranja/apps/core/static/core/css/components/buttons.css index eabce2b..a39155a 100644 --- a/multigranja/apps/core/static/core/css/components/buttons.css +++ b/multigranja/apps/core/static/core/css/components/buttons.css @@ -7,35 +7,35 @@ /* BUTTON STYLES */ .btn-simple { - color: var(--color-text-dark); + color: var(--color-plus-btn); padding: 0 var(--space-xs); border-radius: var(--border-radius-sm); } .btn-simple:hover { - color: var(--color-text-light); + color: var(--color-plus-btn-hover); background-color: var(--color-bg-dark); transition: all var(--transition-speed) ease; } /* PRIMARY BUTTON (Main Action) */ .btn-primary { - background-color: var(--color-primary); + background-color: var(--color-plus-btn); + color: var(--color-text-light); /* White text */ padding: var(--space-sm); border-radius: var(--border-radius-sm); - color: var(--color-text-light); /* White text */ } .btn-primary:hover { - background-color: #0056b3; /* Darker blue on hover (a specific dark value often works best) */ + background-color: var(--color-plus-btn-hover); /* Darker blue on hover (a specific dark value often works best) */ } /* SECONDARY BUTTON (Neutral Action) */ .btn-secondary { background-color: var(--color-secondary); + color: var(--color-text-light); padding: var(--space-sm); border-radius: var(--border-radius-sm); - color: var(--color-text-light); } .btn-secondary:hover { @@ -44,12 +44,12 @@ /* SUCCESS/DANGER BUTTONS */ .btn-success { - background-color: var(--color-success); + background-color: var(--color-plus-btn); color: var(--color-text-light); } .btn-danger { - background-color: var(--color-danger); + background-color: var(--color-danger-btn); color: var(--color-text-light); } diff --git a/multigranja/apps/core/static/core/css/components/confirmation_popup.css b/multigranja/apps/core/static/core/css/components/confirmation_popup.css index 6ee7400..bda7b50 100644 --- a/multigranja/apps/core/static/core/css/components/confirmation_popup.css +++ b/multigranja/apps/core/static/core/css/components/confirmation_popup.css @@ -9,13 +9,14 @@ /* Title */ .confirmation-container h1 { - font-size: 1.5rem; + font-size: 22px; text-align: center; } /* Description */ .confirmation-description { text-align: end; + margin: 10px 0 15px 0; } /* Actions */ @@ -26,11 +27,13 @@ } /* Both buttons */ -.confirmation-container form .confirm, .negate { +.confirmation-container form .confirm, +.confirmation-container form .negate { display: flex; align-items: center; justify-content: center; - min-width: 120px; + min-width: 100px; + max-height: 30px; padding: var(--space-sm) var(--space-sm); border: none; border-radius: var(--border-radius-sm); @@ -41,30 +44,22 @@ /* Confirm button */ .confirmation-container form .confirm { - background-color: #dc3545; + background-color: var(--color-danger-btn); color: white; } .confirmation-container form .confirm:hover { - filter: brightness(0.92); -} - -.confirmation-container form .confirm:active { - transform: scale(0.98); + background-color: var(--color-danger-btn-hover); } /* Negate button */ .confirmation-container form .negate { - background-color: var(--color-secondary); + background-color: var(--color-neutral-btn); color: var(--color-text-light); } .confirmation-container form .negate:hover { - filter: brightness(0.92); -} - -.confirmation-container form .negate:active { - transform: scale(0.90); + background-color: var(--color-neutral-btn-hover); } @media (max-width: 600px) { diff --git a/multigranja/apps/core/static/core/css/components/form.css b/multigranja/apps/core/static/core/css/components/form.css new file mode 100644 index 0000000..1220b5d --- /dev/null +++ b/multigranja/apps/core/static/core/css/components/form.css @@ -0,0 +1,169 @@ +/* Container do formulário */ +.generic-form { + padding: 2rem; + background: var(--color-bg-form); + border-radius: 12px; +} + +/* Labels */ +.generic-form label { + display: block; + margin-bottom: 0.4rem; + font-weight: 600; + color: var(--color-form-label); +} + +/* Campos */ +.generic-form input, +.generic-form select, +.generic-form textarea { + width: 100%; + padding: 0.75rem 1rem; + margin-bottom: 1rem; + border: 1px solid var(--color-input-border); + border-radius: 8px; + font-size: 1rem; + box-sizing: border-box; + transition: all 0.2s ease; +} + +/* Foco */ +.generic-form input:focus, +.generic-form select:focus, +.generic-form textarea:focus { + outline: none; + border-color: var(--color-input-focus-border); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15); +} + +/* Checkbox e radio */ +.generic-form input[type="checkbox"], +.generic-form input[type="radio"] { + width: auto; + margin-right: 0.5rem; +} + +/* Mensagens de erro */ +.errorlist { + list-style: none; + padding: 0.75rem; + margin-bottom: 1rem; + background: var(--color-bg-error); + color: var(--color-text-error); + border-radius: 8px; +} + +/* Texto de ajuda */ +.helptext { + display: block; + margin-top: -0.5rem; + margin-bottom: 1rem; + font-size: 0.85rem; + color: var(--color-text-help); +} + +/* Área dos botões */ +.form-actions { + display: flex; + gap: 1rem; + margin-top: 1.5rem; + justify-content: flex-end; +} + +/* Botão principal */ +.btn-primary { + display: inline-block; + padding: 0.8rem 1.4rem; + background-color: var(--color-plus-btn); + color: var(--color-text-light); /* White text */ + text-decoration: none; + border: none; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + transition: 0.2s; +} + +.btn-primary:hover { + background-color: var(--color-plus-btn-hover); +} + +/* Botão cancelar */ +.btn-secondary { + display: inline-block; + padding: 0.8rem 1.2rem; + background-color: var(--color-neutral-btn); + color: var(--color-text-light); + text-decoration: none; + border-radius: 8px; + font-weight: 600; + transition: 0.2s; +} + +.btn-secondary:hover { + background: var(--color-neutral-btn-hover); +} + +/* Tom Select - campo */ +.generic-form .ts-wrapper { + width: 100%; + margin-bottom: 1rem; +} + +/* Caixa principal */ +.generic-form .ts-control { + width: 100%; + min-height: 46px; + padding: 0.65rem 1rem; + border: 1px solid var(--color-input-border); + border-radius: 8px; + background: white; + box-sizing: border-box; + font-size: 1rem; + transition: all 0.2s ease; +} + +/* Input interno */ +.generic-form .ts-control input { + margin: 0; + padding: 0; + border: none; + box-shadow: none; +} + +/* Foco */ +.generic-form .ts-wrapper.focus .ts-control { + outline: none; + border-color: var(--color-input-focus-border); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15); +} + +/* Tags selecionadas (multi select) */ +.generic-form .item { + background: var(--color-plus-btn); + color: var(--color-text-light); + border-radius: 6px; + padding: 0.25rem 0.5rem; +} + +/* Botão remover tag */ +.generic-form .remove { + color: white; +} + +/* Dropdown */ +.generic-form .ts-dropdown { + border-radius: 8px; + border: 1px solid var(--color-input-border); + box-shadow: 0 4px 12px rgba(0,0,0,.1); +} + +/* Opções */ +.generic-form .option { + padding: .6rem 1rem; +} + +.generic-form .option.active { + background: var(--color-plus-btn-hover); + color: var(--color-text-light); +} \ No newline at end of file diff --git a/multigranja/apps/core/static/core/css/components/form_modal.css b/multigranja/apps/core/static/core/css/components/form_modal.css new file mode 100644 index 0000000..4dcee6d --- /dev/null +++ b/multigranja/apps/core/static/core/css/components/form_modal.css @@ -0,0 +1,5 @@ +.form-modal-title { + font-size: 22px; + margin-top: 10px; + margin-left: 10px; +} \ No newline at end of file diff --git a/multigranja/apps/core/static/core/css/global.css b/multigranja/apps/core/static/core/css/global.css index 5872348..9e3267d 100644 --- a/multigranja/apps/core/static/core/css/global.css +++ b/multigranja/apps/core/static/core/css/global.css @@ -25,6 +25,7 @@ a { overflow-x: hidden; z-index: 150; box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1); + scrollbar-width: none; } .sidebar-brand { @@ -110,29 +111,106 @@ body.sidebar-collapsed .main-content { cursor: pointer; } -/* Inicio do css do seletor antigo */ -.navbar-farm-selector { - display: flex; - flex-direction: column; - align-items: center; - cursor: default; - opacity: 0.75; - transition: all var(--transition-speed) ease; +/* Farm Selection */ +.ts-wrapper { + width: clamp(200px, 25vw, 300px); + margin: 0 auto; } -.navbar-farm-selector:hover { - opacity: 1; +.ts-wrapper.single .ts-control { + position: relative; + width: 100%; + padding: 4px 20px 4px 6px; + border: none; + border-radius: 6px; + background: transparent; + box-shadow: none; + font-size: 16px; + justify-content: center; + cursor: pointer; + transition: none; + font-weight: 600; + color: var(--color-primary); } -.farm-name { - font-size: var(--font-md); - font-weight: 500; - margin: 0; +.ts-wrapper.single .ts-control:hover { + box-shadow: none; +} + +.ts-wrapper.focus .ts-control { + box-shadow: none; + width: 100%; +} + +.ts-wrapper.single .ts-control::after { + content: ""; + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid #666; + pointer-events: none; + transition: transform .2s ease; +} + +.ts-wrapper.single.dropdown-active .ts-control::after { + transform: translateY(-50%) rotate(180deg); +} + +.ts-dropdown { + width: 100%; + margin-top: 2px; + border: none; + border-radius: 6px; + background: #f5f5f5; + box-shadow: 2px 2px 6px rgba(0,0,0,.12); + overflow: hidden; +} + +.ts-dropdown .option { + padding: 4px 6px; + font-size: 16px; + text-align: center; + cursor: pointer; + font-weight: 600; + color: var(--color-primary); +} + +.ts-dropdown .option:hover { + background: #ececec; +} + +.ts-dropdown .active { + background: #e0e0e0; +} + +.ts-control input { + display: none; +} + +.ts-control .item { + overflow: hidden; + text-overflow: ellipsis; white-space: nowrap; } -/* Fim do css do seletor antigo */ -.navbar-user-info { +.ts-dropdown .option.see-all { + color: var(--color-primary); + background: transparent; + font-weight: 500; + border-top: 1px solid #ddd; +} + +.ts-dropdown .option.see-all:hover, +.ts-dropdown .option.see-all.active { + cursor: pointer; +} + +/* NAV BAR RIGHT */ +.navbar-user-info, +.navbar-user-info-farm-select { display: flex; justify-content: flex-end; gap: var(--space-sm); @@ -157,33 +235,44 @@ body.sidebar-collapsed .main-content { /* BASE MODAL */ .modal-base { - position: fixed; - inset: 0; - z-index: 200; - display: flex; - align-items: center; - justify-content: center; - background-color: rgba(0, 0, 0, 0.6); + position: fixed; + inset: 0; + z-index: 200; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(0, 0, 0, 0.4); } .modal-content { - background-color: var(--color-bg-light); - padding: var(--space-lg); - border-radius: var(--space-sm); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + background-color: var(--color-bg-light); + padding: var(--space-md); + border-radius: var(--space-sm); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } -@media screen and (max-width: 768px) { - .navbar-farm-selector, - .navbar-user-info { - transition: opacity var(--transition-speed) ease; - } - +@view-transition { + navigation: auto; +} + +::view-transition-old(root), +::view-transition-new(root) { + animation-duration: 0.3s; + animation-timing-function: ease; +} + +@media screen and (max-width: 768px) { body:not(.sidebar-collapsed) .navbar-farm-selector, body:not(.sidebar-collapsed) .navbar-user-info { display: none; } + body:not(.sidebar-collapsed) .main-content { + transform: translateX(0); + width: 100%; + overflow: hidden; + } + .navbar { padding: 0 var(--space-sm); } diff --git a/multigranja/apps/core/static/core/css/layouts/base_modal.css b/multigranja/apps/core/static/core/css/layouts/base_modal.css new file mode 100644 index 0000000..99326c3 --- /dev/null +++ b/multigranja/apps/core/static/core/css/layouts/base_modal.css @@ -0,0 +1,11 @@ +.modal-content { + min-width: 50vw; + max-width: 85vw; + max-height: 90vh; + overflow-y: scroll; + scrollbar-width: none; +} + +.modal-content:has(.confirmation-container) { + min-width: 0; +} \ No newline at end of file diff --git a/multigranja/apps/core/static/core/css/variables.css b/multigranja/apps/core/static/core/css/variables.css index ec510f0..6915a9e 100644 --- a/multigranja/apps/core/static/core/css/variables.css +++ b/multigranja/apps/core/static/core/css/variables.css @@ -1,34 +1,45 @@ :root { /* SPECIFIC COLORS */ - --login-background-primary: #343a40; - --login-background-secondary: #6b7480; - --color-login-button: #343a40; - --color-login-button-focus: #6b7480; - --color-farm-select-hover: #343a40; + --login-background-primary: #244238; + --login-background-secondary: #396a5a; + --color-login-button: #396a5a; + --color-login-button-focus: #76948a; + --color-farm-select-hover: #244238; --color-farm-select-info: #6d6d6d; - --color-new-farm-button: #343a40; - --color-new-farm-hover: #6b7480; + --color-new-farm-button: #396a5a; + --color-new-farm-hover: #244238; + --color-plus-btn: #396a5a; + --color-plus-btn-hover: #76948a; + --color-danger-btn: #8b3d3d; + --color-danger-btn-hover: #b37a7a; + --color-neutral-btn: #5f6b67; + --color-neutral-btn-hover: #97a39f; + --color-input-border: #5f6b67; + --color-bg-filter: #76948a; + --color-text-filter: #f5faf5; /* GENERIC COLORS */ --color-simple-light-gray: #ccc; --color-border-subtle: #ccc; /* PRIMARY COLORS */ - --color-primary: #007bff; + --color-primary: #244238; --color-secondary: #6c757d; --color-success: #28a745; - --color-danger: #dc3545; - --color-danger-light: #f8d7da; + --color-danger: #8b3d3d; + --color-danger-light: #b37a7a; --color-warn: #dca235; /* BACKGROUND/TEXT COLORS */ - --color-bg-light: #f0f0f0; + --color-bg-light: #f5f7f5; --color-bg-white: #fafafa; - --color-bg-dark: #343a40; - --color-bg-sidebar: #343a40; + --color-bg-form: #fafafa; + --color-bg-dark: #244238; + --color-bg-sidebar: #244238; --color-text-dark: #151422; + --color-form-label: #151422; --color-text-light: #f8f9fa; - + /* SPACING DIMENSIONS */ --space-xs: 8px; --space-sm: 12px; diff --git a/multigranja/apps/core/static/core/js/tomselect.js b/multigranja/apps/core/static/core/js/tomselect.js new file mode 100644 index 0000000..be0ab1c --- /dev/null +++ b/multigranja/apps/core/static/core/js/tomselect.js @@ -0,0 +1,33 @@ +// Creates TomSelect Selects when loading a page +document.addEventListener("DOMContentLoaded", () => { + new TomSelect("#farm_selection_select", { + create: false, + sortField: { + field: "text", + direction: "asc" + }, + controlInput: null, + + render: { + option: function(data, escape) { + return ` +
+ ${escape(data.text)} +
+ `; + } + } + }); +}); + +// Creates TomSelect Selects when an htmx swap is detected +document.addEventListener("htmx:afterSwap", function(event) { + const animals = document.querySelector("#id_animals"); + + if (animals && !animals.tomselect) { + new TomSelect("#id_animals", { + plugins: ['remove_button'], + create: false, + }); + } +}); \ No newline at end of file diff --git a/multigranja/apps/core/templates/components/form.html b/multigranja/apps/core/templates/components/form.html index bddcab0..ed0a11f 100644 --- a/multigranja/apps/core/templates/components/form.html +++ b/multigranja/apps/core/templates/components/form.html @@ -1,6 +1,30 @@ -
+ {% csrf_token %} - {{ form }} - - Cancelar + + {% for field in form %} +
+ {{ field.label_tag }} + {{ field }} + + {% if field.help_text %} + {{ field.help_text }} + {% endif %} + + {{ field.errors }} +
+ {% endfor %} + +
+ + + + Cancelar + +
\ No newline at end of file diff --git a/multigranja/apps/core/templates/components/form_modal.html b/multigranja/apps/core/templates/components/form_modal.html new file mode 100644 index 0000000..702bfbb --- /dev/null +++ b/multigranja/apps/core/templates/components/form_modal.html @@ -0,0 +1,7 @@ +{% extends 'layouts/base_modal.html' %} +{% load static %} + +{% block content %} +

{{ modal_title }}

+ {% include 'components/form.html' %} +{% endblock %} \ No newline at end of file diff --git a/multigranja/apps/core/templates/components/navbar.html b/multigranja/apps/core/templates/components/navbar.html index e3a965f..911b58b 100644 --- a/multigranja/apps/core/templates/components/navbar.html +++ b/multigranja/apps/core/templates/components/navbar.html @@ -3,18 +3,14 @@ - {% comment %} {% endcomment %} -