feat: more changes and fixes

This commit is contained in:
Herculino Trotta
2025-11-08 14:06:01 -03:00
parent a878af28f1
commit cd54df6f2d
45 changed files with 412 additions and 476 deletions
@@ -11,17 +11,23 @@
{{ form.management_form }}
<div class="space-y-2" id="balanceAccordionFlush">
{% for form in form.forms %}
<details class="collapse collapse-arrow bg-base-100 border-base-300 border overflow-visible show">
<summary class="collapse-title font-medium text-sm">
{% if form.account_group %}<span class="badge badge-primary me-2">{{ form.account_group.name }}</span>{% endif %}{{ form.account_name }}
</summary>
<div class="collapse-content">
<div class="collapse collapse-arrow bg-base-100 border-base-300 border overflow-visible">
<input type="checkbox" />
<div class="collapse-title font-medium text-sm">
{% if form.account_group %}<span class="badge badge-primary badge-outline me-2">{{ form.account_group.name }}</span>{% endif %}{{ form.account_name }}
</div>
<div class="collapse-content bg-base-200">
<div class="fieldset">
<span class="fieldset-legend">{% translate 'Current balance' %}</span>
<div data-amount="{{ form.current_balance|floatformat:"-40u" }}"
data-decimal-places="{{ form.currency_decimal_places }}"
id="amount-{{ forloop.counter0 }}" class="text-base">
{% currency_display amount=form.current_balance prefix=form.currency_prefix suffix=form.currency_suffix decimal_places=form.currency_decimal_places %}
<c-amount.display
:amount="form.current_balance"
:prefix="form.currency_prefix"
:suffix="form.currency_suffix"
:decimal_places="form.currency_decimal_places"
color="auto"></c-amount.display>
</div>
</div>
<div>
@@ -52,7 +58,7 @@
put '-' into me">-</div>
</div>
</div>
</details>
</div>
{% endfor %}
</div>
<div class="mt-3">
+1
View File
@@ -14,6 +14,7 @@
<div class="md:col-span-10"></div>
<div class="md:col-span-11"></div>
<div class="md:col-span-12"></div>
<div class="col-span-12"></div>
<div class="alert-error"></div>
<div class="alert-info"></div>
<div class="alert-success"></div>
+9 -1
View File
@@ -5,7 +5,15 @@
{% if not divless %}
<div class="{% if text_end %}text-end{% elif text_start %}text-start{% endif %}">
{% endif %}
<span class="amount{% if color == 'grey' or color == "gray" %} text-exchange-rate{% elif color == 'green' %} text-income {% elif color == 'red' %} text-expense{% endif %} font-medium {{ custom_class }}"
<span class="amount
{% if color == 'grey' or color == "gray" %} text-exchange-rate
{% elif color == 'green' %} text-income {% elif color == 'red' %} text-expense
{% elif color == 'auto' %}
{% if amount > 0 %} text-income
{% elif amount < 0 %} text-expense
{% else %} text-base-content {% endif %}
{% endif %}
font-medium {{ custom_class }}"
data-original-sign="{{ formatted_amount.sign }}"
data-original-prefix="{{ formatted_amount.prefix }}"
data-original-amount="{{ formatted_amount.amount }}"
@@ -1,6 +1,6 @@
<li>
<div class="flex items-center min-h-[1.25rem]">
<span class="sidebar-menu-header text-base-content/60 text-sm font-bold uppercase mr-3">{{ title }}</span>
<div class="flex items-center min-h-6">
<span class="sidebar-menu-header text-base-content/60 text-xs font-bold uppercase mr-3">{{ title }}</span>
<hr class="hr grow"/>
</div>
</li>
@@ -1,7 +1,7 @@
{% load active_link %}
<li>
<a href="{% url url %}"
class="lg:text-sm flex items-center no-underline p-2 rounded-box sidebar-item {% active_link views=active css_class="sidebar-active" %}"
class="lg:text-sm flex items-center no-underline ps-3 p-2 rounded-box sidebar-item {% active_link views=active css_class="sidebar-active" %}"
{% if tooltip %}
data-tippy-placement="right"
data-tippy-content="{{ tooltip }}"
@@ -2,7 +2,7 @@
<li>
<a href="{{ url }}"
hx-boost="false"
class="lg:text-sm flex items-center no-underline p-2 rounded-3xl sidebar-item {% active_link views=active css_class="sidebar-active" %}"
class="lg:text-sm flex items-center no-underline ps-3 p-2 rounded-3xl sidebar-item {% active_link views=active css_class="sidebar-active" %}"
{% if tooltip %}
data-tippy-placement="right"
data-tippy-content="{{ tooltip }}"
@@ -23,7 +23,7 @@
<div class="font-bold text-md ms-2" id="selected-count">0</div>
<div class="divider divider-horizontal m-0"></div>
<div class="dropdown dropdown-top dropdown-end">
<button tabindex="0" role="button" class="btn btn-secondary btn-sm" type="button">
<button tabindex="0" role="button" class="btn btn-secondary btn-soft btn-sm" type="button">
<i class="fa-regular fa-square-check fa-fw"></i>
<i class="fa-solid fa-chevron-down fa-xs"></i>
</button>
@@ -44,7 +44,7 @@
</div>
<div class="divider divider-horizontal m-0"></div>
<div class="join">
<button class="btn btn-secondary join-item btn-sm"
<button class="btn btn-secondary btn-soft join-item btn-sm"
hx-get="{% url 'transactions_bulk_edit' %}"
hx-target="#generic-offcanvas"
hx-include=".transaction"
@@ -1,4 +1,4 @@
<div {% if buttonholder.css_id %}id="{{ buttonholder.css_id }}"{% endif %}
class="flex gap-2{% if buttonholder.css_class %} {{ buttonholder.css_class }}{% endif %}">
class="flex flex-col gap-2{% if buttonholder.css_class %} {{ buttonholder.css_class }}{% endif %}">
{{ fields_output|safe }}
</div>
@@ -1,11 +1,10 @@
<div
{% if formactions.flat_attrs %}{{ formactions.flat_attrs }}{% endif %}
class="flex gap-2 {{ formactions.css_class|default:'' }} {{ field_class }}"
class="flex flex-col gap-2 mt-3 {{ formactions.css_class|default:'' }} {{ field_class }}"
{% if formactions.id %} id="{{ formactions.id }}"{% endif %}>
{% if label_class %}
<div class="aab {{ label_class }}"></div>
{% endif %}
<div class="{{ field_class }}">
{{ fields_output|safe }}
</div>
{{ fields_output|safe }}
</div>
@@ -1,7 +1,7 @@
{% if field.help_text %}
{% if help_text_inline %}
<span id="{{ field.auto_id }}_helptext" class="text-sm text-base-content/60">{{ field.help_text|safe}}</span>
<span id="{{ field.auto_id }}_helptext" class="text-xs text-base-content/60 text-wrap">{{ field.help_text|safe}}</span>
{% else %}
<div {% if field.auto_id %}id="{{ field.auto_id }}_helptext" {% endif %}class="text-sm text-base-content/60 mt-1">{{ field.help_text|safe }}</div>
<div {% if field.auto_id %}id="{{ field.auto_id }}_helptext" {% endif %}class="text-xs text-base-content/60 mt-1 text-wrap">{{ field.help_text|safe }}</div>
{% endif %}
{% endif %}
@@ -5,46 +5,48 @@
{% else %}
<div id="div_{{ field.auto_id }}" class="{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_group_wrapper_class %} {{ form_group_wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}" class="label{{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<span class="label-text">{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}</span>
</label>
{% endif %}
<fieldset class="fieldset{% if field_class %} {{ field_class }}{% endif %}">
{% if field.label and form_show_labels %}
<legend class="fieldset-legend{{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</legend>
{% endif %}
<div {% if field_class %}class="{{ field_class }}"{% endif %}>
<label class="input input-bordered flex items-center gap-2{% if input_size %} {{ input_size }}{% endif %}{% if field.errors %} input-error{% endif %}">
<label class="input w-full {% if input_size %} {{ input_size }}{% endif %}{% if field.errors %} input-error{% endif %}">
{# prepend #}
{% if crispy_prepended_text %}
<span>{{ crispy_prepended_text }}</span>
{{ crispy_prepended_text }}
{% endif %}
{# input #}
{% if field|is_select %}
{% if field.errors %}
{% crispy_field field 'class' 'select-error' %}
{% crispy_field field 'class' 'select-error grow' %}
{% else %}
{% crispy_field field 'class' '' %}
{% crispy_field field 'class' 'grow' %}
{% endif %}
{% elif field.errors %}
{% crispy_field field 'class' 'grow' %}
{% else %}
{% crispy_field field 'class' 'grow' %}
{% endif %}
{# append #}
{% if crispy_appended_text %}
<span>{{ crispy_appended_text }}</span>
{{ crispy_appended_text }}
{% endif %}
</label>
{% if error_text_inline %}
{% include 'crispy-daisyui/layout/field_errors.html' %}
{% else %}
{% include 'crispy-daisyui/layout/field_errors_block.html' %}
{% endif %}
{% if not help_text_inline %}
{% include 'crispy-daisyui/layout/help_text.html' %}
{% endif %}
</div>
{# help text as label paragraph #}
{% if not help_text_inline %}
{% include 'crispy-daisyui/layout/help_text.html' %}
{% endif %}
{# errors #}
{% if error_text_inline %}
{% include 'crispy-daisyui/layout/field_errors.html' %}
{% else %}
{% include 'crispy-daisyui/layout/field_errors_block.html' %}
{% endif %}
</fieldset>
</div>
{% endif %}
+1 -1
View File
@@ -1,3 +1,3 @@
<div {% if div.css_id %}id="{{ div.css_id }}"{% endif %} class="grid grid-cols-12 gap-4 {{ div.css_class|default:'' }}" {{ div.flat_attrs }}>
<div {% if div.css_id %}id="{{ div.css_id }}"{% endif %} class="grid grid-cols-12 gap-x-4 {{ div.css_class|default:'' }}" {{ div.flat_attrs }}>
{{ fields|safe }}
</div>
@@ -3,15 +3,19 @@
{% if field.is_hidden %}
{{ field }}
{% else %}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="form-control{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<label class="label cursor-pointer justify-start gap-2">
<span class="label-text">{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}</span>
<{% if tag %}{{ tag }}{% else %}fieldset{% endif %} id="div_{{ field.auto_id }}" class="fieldset mt-2 {% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<label class="label flex flex-row gap-3">
<div>
{% if field.errors %}
{% crispy_field field 'class' 'toggle toggle-error' 'role' 'switch' %}
{% crispy_field field 'class' 'toggle toggle-error toggle-sm' %}
{% else %}
{% crispy_field field 'class' 'toggle' 'role' 'switch' %}
{% crispy_field field 'class' 'toggle toggle-sm' %}
{% endif %}
</div>
<div>
{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
{% include 'crispy-daisyui/layout/help_text_and_errors.html' %}
</div>
</label>
{% include 'crispy-daisyui/layout/help_text_and_errors.html' %}
</{% if tag %}{{ tag }}{% else %}div{% endif %}>
</{% if tag %}{{ tag }}{% else %}fieldset{% endif %}>
{% endif %}
+1 -1
View File
@@ -1,5 +1,5 @@
{% load i18n %}
<div class="offcanvas-header flex justify-between items-center">
<div class="offcanvas-header flex justify-between items-center border-b border-base-content/10">
<h5 class="offcanvas-title font-medium text-xl">{% block title %}{% endblock %}</h5>
<button type="button" class="btn btn-ghost btn-sm btn-circle" aria-label="{% trans 'Close' %}" data-bs-dismiss="offcanvas"><i class="fa-solid fa-xmark"></i></button>
</div>
+2 -2
View File
@@ -3,10 +3,10 @@
{% load static %}
{% load i18n %}
{% load active_link %}
<nav class="navbar border-b border-base-300 bg-base-200 flex lg:hidden" hx-boost="true">
<nav class="navbar border-b-2 border-base-100 bg-base-200 flex lg:hidden shadow-lg" hx-boost="true">
<div class="container mx-auto px-4 flex justify-between items-center w-full">
<a class="text-xl font-bold text-primary" href="{% url 'index' %}">
<img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="40" width="40" title="WYGIWYH"/>
<div class="logo mobile"></div>
</a>
<button class="btn btn-ghost lg:hidden" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebar"
aria-controls="sidebar" aria-label={% translate "Toggle navigation" %}>
+19 -1
View File
@@ -1,10 +1,28 @@
{% load settings %}
{% load i18n %}
<label class="swap swap-rotate btn btn-secondary btn-sm" data-tippy-content="{% translate 'Toggle theme' %}">
<input type="checkbox"
_="on load
if <html/>'s @data-theme is 'wygiwyh_dark' set my.checked to true end
end
on change
if my.checked set <html/>'s @data-theme to 'wygiwyh_dark'
else set <html/>'s @data-theme to 'wygiwyh_light'
then fetch {% url 'toggle_theme' %}
end
end"
/>
<i class="fa-regular fa-sun swap-off"></i>
<i class="fa-regular fa-moon swap-on"></i>
</label>
<div class="dropdown dropdown-top dropdown-end">
<div tabindex="0" role="button" class="btn btn-secondary btn-sm">
<i class="fa-solid fa-cog"></i>
</div>
<ul tabindex="0" class="dropdown-content menu bg-base-100 rounded-box z-[1] w-52 p-2 shadow">
<ul tabindex="0" class="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow">
<li><a
hx-get="{% url 'user_settings' %}"
hx-target="#generic-offcanvas"
+21 -18
View File
@@ -12,10 +12,10 @@
hx-boost="true"
hx-swap="transition:true"
data-bs-scroll="true"
class="offcanvas-lg offcanvas-start lg:flex flex-col fixed top-0 left-0 h-full bg-base-300! shadow-sm z-[1045]">
<div data-theme="wygiwyh_dark" class="hidden lg:flex items-center justify-between pr-4 border-b border-base-content/10 sidebar-submenu-header bg-base-300">
<a href="{% url 'index' %}" class="m-0 hidden lg:flex justify-start p-3 no-underline sidebar-title">
<img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="30" width="30" title="WYGIWYH"/>
class="offcanvas-lg offcanvas-start lg:flex flex-col fixed top-0 left-0 h-full bg-base-300! border-e-2 border-base-100 lg:group-hover:shadow-[5px_0px_10px_-2px_rgba(0,0,0,0.2)] z-1045">
<div class="hidden lg:flex items-center justify-between border-b border-base-content/10 sidebar-submenu-header">
<a href="{% url 'index' %}" class="m-0 hidden lg:flex justify-start p-4 no-underline sidebar-title">
<div class="logo"></div>
<span class="text-2xl font-bold ml-3">WYGIWYH</span>
</a>
@@ -37,13 +37,12 @@
<div class="lg:hidden flex justify-between items-center p-4 text-base-content">
<a href="{% url 'index' %}" class="flex justify-start no-underline">
<img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="30" width="30" title="WYGIWYH"/>
<div class="logo"></div>
<span class="text-2xl font-bold ml-3">WYGIWYH</span>
</a>
<button type="button" class="btn btn-ghost btn-sm btn-circle" data-bs-target="#sidebar" data-bs-dismiss="offcanvas"
aria-label={% translate 'Close' %}><i class="fa-solid fa-xmark"></i></button>
</div>
<hr class="m-0 hr">
<ul class="list-none p-3 flex flex-col gap-1 whitespace-nowrap lg:group-hover:animate-[disable-pointer-events] overflow-y-auto overflow-x-hidden"
style="animation-duration: 100ms">
@@ -143,7 +142,7 @@
data-bs-target="#collapsible-panel"
aria-expanded="false"
aria-controls="collapsible-panel"
class="sidebar-item text-wrap lg:text-nowrap lg:text-sm flex items-center no-underline p-2 cursor-pointer sidebar-item {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index||users_index' css_class="sidebar-active" %}">
class="lg:text-sm flex items-center no-underline ps-3 p-2 rounded-box sidebar-item cursor-pointer {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index||users_index' css_class="sidebar-active" %}">
<i class="fa-solid fa-toolbox fa-fw"></i>
<span class="ml-3 font-medium lg:group-hover:truncate lg:group-focus:truncate lg:group-hover:text-ellipsis lg:group-focus:text-ellipsis">
{% translate 'Management' %}
@@ -154,7 +153,7 @@
<div class="mt-auto p-2 w-full">
<div id="collapsible-panel"
class="p-0 collapse absolute bottom-0 left-0 w-full z-30 max-h-dvh {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index||users_index' css_class="show" %}">
class="bs collapse p-0 absolute bottom-0 left-0 w-full z-30 max-h-dvh {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index||users_index' css_class="show" %}">
<div class="h-dvh bg-base-300 flex flex-col">
<div
class="justify-between items-center p-4 border-b border-base-content/10 sidebar-submenu-header text-base-content">
@@ -171,7 +170,7 @@
</button>
</div>
<ul class="list-none p-3 flex flex-col gap-2 lg:group-hover:animate-[disable-pointer-events] flex-1 overflow-y-auto overflow-x-hidden"
<ul class="list-none p-3 flex flex-col gap-1 whitespace-nowrap lg:group-hover:animate-[disable-pointer-events] overflow-y-auto overflow-x-hidden"
style="animation-duration: 100ms">
<c-components.sidebar-menu-header title="{% translate 'Transactions' %}"></c-components.sidebar-menu-header>
<c-components.sidebar-menu-item
@@ -270,10 +269,10 @@
{% get_update_check as update_check %}
{% if update_check.update_available %}
<div class="my-3">
<a class="px-3 badge badge-primary no-underline cursor-pointer w-full !text-xs"
<a class="btn btn-primary btn-soft btn-sm w-full sidebar-item"
href="https://github.com/eitchtee/WYGIWYH/releases/latest" target="_blank"><i
class="fa-solid fa-circle-exclamation fa-fw mr-2"></i><span
class="lg:invisible lg:group-hover:visible">v.{{ update_check.latest_version }} {% translate 'is available' %}!</span></a>
class="fa-solid fa-circle-exclamation fa-fw lg:group-hover:me-2"></i><span
class="lg:hidden lg:group-hover:block">v.{{ update_check.latest_version }} {% translate 'is available' %}!</span></a>
</div>
{% endif %}
@@ -286,19 +285,23 @@
</div>
<div>
<hr class="my-1 border-base-300">
<hr class="hr my-1">
<div
class="ps-4 pe-2 py-2 flex items-center no-underline justify-between">
class="ps-6 pe-2 py-2 flex items-center no-underline justify-between">
<div class="flex items-center" style="min-width: 0;">
<i class="fa-solid fa-circle-user text-base-content/60"></i>
<i class="fa-solid fa-circle-user text-subtle"></i>
<strong class="mx-2 text-base-content/60 truncate sidebar-invisible">
{{ user.email }}
<strong class="mx-2 text-subtle truncate sidebar-invisible">
{% if user.first_name and user.last_name %}
{{ user.first_name }} {{ user.last_name }}
{% else %}
{{ user.email }}
{% endif %}
</strong>
</div>
<div class="sidebar-invisible">
<div class="sidebar-invisible flex flex-row gap-2">
{% include 'includes/navbar/user_menu.html' %}
</div>
@@ -6,11 +6,11 @@
<div class="join join-vertical w-full" id="emergency-fund-accordion">
{% for id, data in data.items %}
{% if data.average %}
<div class="collapse collapse-arrow join-item border-base-300 border">
<input type="radio" name="emergency-fund-accordion" />
<div class="collapse collapse-arrow join-item bg-base-100 border-base-200 border">
<input type="checkbox" />
<div class="collapse-title text-base font-medium">
<span>
<span class="text-base-content/60">{% trans "You've spent an average of" %}</span>
<span class="text-subtle">{% trans "You've spent an average of" %}</span>
<c-amount.display
:amount="data.average"
:prefix="data.currency.prefix"
@@ -18,15 +18,15 @@
:decimal_places="data.currency.decimal_places"
custom_class="text-3xl"
divless></c-amount.display>
<span class="text-base-content/60">{% trans 'on the last 12 months, at this rate you could go by' %}</span>
<span class="text-subtle">{% trans 'on the last 12 months, at this rate you could go by' %}</span>
<span class="text-3xl">{{ data.months }}</span>
<span class="text-base-content/60">{% trans 'months without any income.' %}</span>
<span class="text-subtle">{% trans 'months without any income.' %}</span>
</span>
</div>
<div class="collapse-content">
<div class="collapse-content bg-base-200">
<div class="flex justify-between items-baseline mt-2">
<div class="text-end font-mono">
<div class="text-base-content/60">{% translate 'average expenses' %}</div>
<div class="text-subtle">{% translate 'average expenses' %}</div>
</div>
<div class="dotted-line flex-grow"></div>
<div class="text-end font-mono">
@@ -40,7 +40,7 @@
</div>
<div class="flex justify-between items-baseline mt-2">
<div class="text-end font-mono">
<div class="text-base-content/60">{% translate 'liquid total' %}</div>
<div class="text-subtle">{% translate 'liquid total' %}</div>
</div>
<div class="dotted-line flex-grow"></div>
<div class="text-end font-mono">
@@ -54,7 +54,7 @@
</div>
<div class="flex justify-between items-baseline mt-2">
<div class="text-end font-mono">
<div class="text-base-content/60">{% translate 'months left' %}</div>
<div class="text-subtle">{% translate 'months left' %}</div>
</div>
<div class="dotted-line flex-grow"></div>
<div class="text-end font-mono">
+2 -21
View File
@@ -4,7 +4,8 @@
{% load i18n %}
{% load title %}
<!DOCTYPE html>
<html lang="en" data-theme="wygiwyh_dark">
<html lang="en"
data-theme="{% if request.session.theme == 'wygiwyh_light' %}wygiwyh_light{% else %}wygiwyh_dark{% endif %}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -22,26 +23,6 @@
{% block extra_js_head %}{% endblock %}
</head>
<body class="font-mono">
<div class="fixed top-4 right-4 z-50">
<label class="swap swap-rotate">
<!-- this hidden checkbox controls the state -->
<input type="checkbox"
class="theme-controller text-base-content text-sm"
value="wygiwyh_light" />
<!-- sun icon -->
<svg class="swap-off h-10 w-10 fill-current"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24">
<path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
</svg>
<!-- moon icon -->
<svg class="swap-on h-10 w-10 fill-current"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24">
<path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
</svg>
</label>
</div>
<div _="install hide_amounts install htmx_error_handler
{% block body_hyperscript %}{% endblock %}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
@@ -6,7 +6,7 @@
{% for x in transactions_by_date %}
<div id="{{ x.grouper|slugify }}" class="transactions-divider"
_="on htmx:afterSwap from #transactions if sessionStorage.getItem(my id) is null then sessionStorage.setItem(my id, 'true')">
<div class="mt-3 mb-1 w-full border-b border-b-base-content/30 transactions-divider-title">
<div class="mt-3 mb-1 w-full border-b border-b-base-content/30 transactions-divider-title cursor-pointer">
<a class="no-underline inline-block w-full"
role="button"
data-bs-toggle="collapse"
@@ -17,7 +17,7 @@
{{ x.grouper }}
</a>
</div>
<div class="collapse transactions-divider-collapse overflow-visible isolation-auto" id="c-{{ x.grouper|slugify }}-collapse"
<div class="bs collapse transactions-divider-collapse overflow-visible isolation-auto" id="c-{{ x.grouper|slugify }}-collapse"
_="on shown.bs.collapse sessionStorage.setItem(the closest parent @id, 'true')
on hidden.bs.collapse sessionStorage.setItem(the closest parent @id, 'false')
on htmx:afterSettle from #transactions or toggle
@@ -192,7 +192,7 @@
{% endfor %}
</div>
</div>
<div class="flex justify-between mt-3">
<div class="flex justify-between">
<div class="text-right font-mono">
<div class="text-subtle">{% translate 'projected' %}</div>
</div>
@@ -132,7 +132,7 @@
title="{% translate 'Order by' %}">
<i class="fa-solid fa-sort fa-fw"></i>
</button>
<ul tabindex="0" class="dropdown-content menu bg-base-300 rounded-box z-[1] w-52 p-2 shadow-md mt-1">
<ul tabindex="0" class="dropdown-content menu bg-base-300 rounded-box z-1 w-62 p-2 shadow-md mt-1">
<li>
<button class="{% if order == 'default' %}menu-active{% endif %}" type="button"
_="on click remove .menu-active from <li > button/> in the closest <ul/>
@@ -165,7 +165,7 @@
</div>
{# Filter transactions form #}
<div class="collapse overflow-visible" id="collapse-filter" hx-preserve>
<div class="bs collapse overflow-visible" id="collapse-filter" hx-preserve>
<div class="card card-body bg-base-200 mt-2">
<div class="text-right">
<button class="btn btn-outline btn-error btn-sm w-fit"
@@ -1,13 +1,12 @@
{% load natural %}
{% load i18n %}
{% regroup page_obj by date|customnaturaldate as transactions_by_date %}
<div id="transactions-list">
<div id="transactions-list" class="show-loading">
{% for x in transactions_by_date %}
<div id="{{ x.grouper|slugify }}" class="transactions-divider"
_="on htmx:afterSwap from #transactions if sessionStorage.getItem(my id) is null then sessionStorage.setItem(my id, 'true')">
<div class="mt-3 mb-1 w-full text-base border-b border-base-300 bg-base-100 transactions-divider-title">
<div class="mt-3 mb-1 w-full border-b border-b-base-content/30 transactions-divider-title cursor-pointer">
<a class="no-underline inline-block w-full"
role="button"
data-bs-toggle="collapse"
@@ -18,7 +17,7 @@
{{ x.grouper }}
</a>
</div>
<div class="collapse transactions-divider-collapse overflow-visible isolation-auto" id="c-{{ x.grouper|slugify }}-collapse"
<div class="bs collapse transactions-divider-collapse overflow-visible isolation-auto" id="c-{{ x.grouper|slugify }}-collapse"
_="on shown.bs.collapse sessionStorage.setItem(the closest parent @id, 'true')
on hidden.bs.collapse sessionStorage.setItem(the closest parent @id, 'false')
on htmx:afterSettle from #transactions or toggle
@@ -41,14 +40,18 @@
</div>
</div>
</div>
{% empty %}
<c-msg.empty
title="{% translate "No transactions found" %}"
subtitle="{% translate "Try adding one" %}"></c-msg.empty>
{% endfor %}
{# Floating bar #}
<c-ui.transactions-action-bar></c-ui.transactions-action-bar>
{% if page_obj.has_other_pages %}
<div class="mt-auto">
<div class="my-3">
<input value="{{ page_obj.number }}" name="page" type="hidden" id="page">
<nav aria-label="{% translate 'Page navigation' %}">
@@ -86,7 +89,8 @@
hx-vals='{"page": {{ page_number }}}'
hx-include="#filter, #order"
hx-target="#transactions-list"
hx-swap="show:top">
hx-swap="outerHTML show:top"
hx-indicator="#transactions-list">
{{ page_number }}
</a>
</li>
@@ -102,10 +106,12 @@
</li>
<li>
<a class="join-item btn btn-sm"
hx-get="{% url 'transactions_all_list' %}" hx-target="#transactions-list"
hx-get="{% url 'transactions_all_list' %}"
hx-target="#transactions-list"
hx-vals='{"page": {{ page_obj.paginator.num_pages }}}'
hx-include="#filter, #order"
hx-swap="show:top"
hx-swap="outerHTML show:top"
hx-indicator="#transactions-list"
aria-label="Última página">
<span aria-hidden="true">{{ page_obj.paginator.num_pages }}</span>
</a>
@@ -116,8 +122,9 @@
hx-get="{% if page_obj.has_next %}{% url 'transactions_all_list' %}{% endif %}"
hx-vals='{"page": {{ page_obj.paginator.num_pages }}}'
hx-include="#filter, #order"
hx-swap="show:top"
hx-swap="outerHTML show:top"
hx-target="#transactions-list"
hx-indicator="#transactions-list"
aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
@@ -126,7 +133,4 @@
</nav>
</div>
{% endif %}
{# Floating bar#}
<c-ui.transactions-action-bar></c-ui.transactions-action-bar>
</div>
@@ -1,47 +1,30 @@
{% load tools %}
{% load i18n %}
{% load currency_display %}
<ul class="nav nav-tabs" id="all-trasactions-tab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="currency-tab" data-bs-toggle="tab" data-bs-target="#currency-tab-pane"
type="button" role="tab" aria-controls="currency-tab-pane"
aria-selected="true">{% trans 'Currencies' %}</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="account-tab" data-bs-toggle="tab" data-bs-target="#account-tab-pane" type="button"
role="tab" aria-controls="account-tab-pane" aria-selected="false">{% trans 'Accounts' %}</button>
</li>
</ul>
<div class="tab-content" id="all-transactions-content">
<div class="tab-pane fade show active" id="currency-tab-pane" role="tabpanel" aria-labelledby="currency-tab"
tabindex="0">
<div class="row row-cols-1 g-4 mt-2">
{% for currency_id, currency in currency_data.items %}
<div class="col">
<c-ui.currency_card :currency="currency" :currency_id="currency_id"
:percentages="currency_percentages"></c-ui.currency_card>
</div>
{% empty %}
<div class="col">
<c-msg.empty
title="{% translate "No information to display" %}"></c-msg.empty>
{% endfor %}
</div>
<div class="grid grid-cols-1 gap-4 mt-1 mb-3">
{% for currency_id, currency in currency_data.items %}
<div>
<c-ui.currency_card :currency="currency" :currency_id="currency_id"
:percentages="currency_percentages"></c-ui.currency_card>
</div>
</div>
<div class="tab-pane fade" id="account-tab-pane" role="tabpanel" aria-labelledby="account-tab" tabindex="0">
<div class="row row-cols-1 g-4 mt-2">
{% for account_id, account in account_data.items %}
<div class="col">
<c-ui.account_card :account="account" :account_id="account_id"
:percentages="account_percentages"></c-ui.account_card>
</div>
{% empty %}
<div class="col">
<c-msg.empty
title="{% translate "No information to display" %}"></c-msg.empty>
{% endfor %}
</div>
{% empty %}
<div>
<c-msg.empty
title="{% translate "No information to display" %}"></c-msg.empty>
</div>
{% endfor %}
</div>
<div class="grid grid-cols-1 gap-4 mt-1 mb-3">
{% for account_id, account in account_data.items %}
<div>
<c-ui.account_card :account="account" :account_id="account_id"
:percentages="account_percentages"></c-ui.account_card>
</div>
{% empty %}
<div>
<c-msg.empty
title="{% translate "No information to display" %}"></c-msg.empty>
{% endfor %}
</div>
</div>
@@ -5,12 +5,45 @@
{% block title %}{% translate 'Transactions' %}{% endblock %}
{% block content %}
<div class="container px-md-3 py-3 column-gap-5 overflow-x-hidden">
<div class="flex flex-wrap gap-x-xl-4 gap-y-3">
<div class="w-full xl:w-8/12 order-2 xl:order-1">
<div class="mb-3">
<div class="container gap-y-3">
<div class="row gap-y-3">
<div class="col-12 lg:col-4 lg:order-last! order-first!">
<div role="tablist" class="tabs tabs-border">
<input type="radio" name="all-transactions-summary" class="tab" aria-label="{% trans 'Currencies' %}"
role="tab"
{% if summary_tab == 'currency' %}checked="checked"{% endif %}
_="on click fetch {% url 'transaction_all_summary_select' selected='currency' %}"
aria-controls="currency-tab-pane" />
<div class="tab-content" id="currency-tab-pane" role="tabpanel">
<div id="currency-summary"
hx-get="{% url 'transaction_all_currency_summary' %}"
class="show-loading"
hx-trigger="load, selective_update from:window, updated from:window, change from:#filter, submit from:#filter, search from:#filter"
hx-include="#filter">
</div>
</div>
<input type="radio" name="all-transactions-summary" class="tab" aria-label="{% trans 'Accounts' %}"
role="tab"
{% if summary_tab == 'account' %}checked="checked"{% endif %}
_="on click fetch {% url 'transaction_all_summary_select' selected='account' %}"
aria-controls="account-tab-pane" />
<div class="tab-content" id="account-tab-pane" role="tabpanel">
<div id="account-summary"
hx-get="{% url 'transaction_all_account_summary' %}"
class="show-loading"
hx-trigger="load, selective_update from:window, updated from:window, change from:#filter, submit from:#filter, search from:#filter"
hx-include="#filter">
</div>
</div>
</div>
</div>
<div class="col-12 lg:col-8 lg:order-first! order-last!">
<div>
{# Hidden select to hold the order value and preserve the original update trigger #}
<select name="order" id="order" class="hidden" _="on change trigger updated on window">
<select name="order" id="order" class="d-none" _="on change trigger updated on window">
<option value="default" {% if order == 'default' %}selected{% endif %}>{% translate 'Default' %}</option>
<option value="older" {% if order == 'older' %}selected{% endif %}>{% translate 'Oldest first' %}</option>
<option value="newer" {% if order == 'newer' %}selected{% endif %}>{% translate 'Newest first' %}</option>
@@ -19,7 +52,7 @@
{# Main control bar with filter, search, and ordering #}
<div class="join w-full">
<button class="btn btn-secondary join-item" type="button"
<button class="btn btn-secondary join-item relative" type="button"
data-bs-toggle="collapse" data-bs-target="#collapse-filter"
aria-expanded="false" aria-controls="collapse-filter" id="filter-button" hx-preserve
title="{% translate 'Filter transactions' %}">
@@ -27,10 +60,10 @@
</button>
{# Search box #}
<label for="quick-search" class="join-item flex-grow">
<label for="quick-search" class="hidden">
</label>
<input type="search"
class="input input-bordered join-item flex-grow"
class="input input-bordered join-item flex-1"
placeholder="{% translate 'Search' %}"
hx-preserve
id="quick-search"
@@ -46,34 +79,33 @@
{# Order by icon dropdown #}
<div class="dropdown dropdown-end">
<button class="btn btn-secondary join-item" type="button"
tabindex="0" role="button"
<button tabindex="0" class="btn btn-secondary join-item" type="button"
title="{% translate 'Order by' %}">
<i class="fa-solid fa-sort fa-fw"></i>
</button>
<ul class="dropdown-content menu bg-base-100 rounded-box z-[1] w-52 p-2 shadow" tabindex="0">
<ul tabindex="0" class="dropdown-content menu bg-base-300 rounded-box z-1 w-62 p-2 shadow-md mt-1">
<li>
<button class="{% if order == 'default' %}active{% endif %}" type="button"
_="on click remove .active from <button/> in the closest <ul/>
then add .active to me
<button class="{% if order == 'default' %}menu-active{% endif %}" type="button"
_="on click remove .menu-active from <li > button/> in the closest <ul/>
then add .menu-active to me
then set the value of #order to 'default'
then trigger change on #order">
{% translate 'Default' %}
</button>
</li>
<li>
<button class="{% if order == 'older' %}active{% endif %}" type="button"
_="on click remove .active from <button/> in the closest <ul/>
then add .active to me
<button class="{% if order == 'older' %}menu-active{% endif %}" type="button"
_="on click remove .menu-active from <li > button/> in the closest <ul/>
then add .menu-active to me
then set the value of #order to 'older'
then trigger change on #order">
{% translate 'Oldest first' %}
</button>
</li>
<li>
<button class="{% if order == 'newer' %}active{% endif %}" type="button"
_="on click remove .active from <button/> in the closest <ul/>
then add .active to me
<button class="{% if order == 'newer' %}menu-active{% endif %}" type="button"
_="on click remove .menu-active from <li > button/> in the closest <ul/>
then add .menu-active to me
then set the value of #order to 'newer'
then trigger change on #order">
{% translate 'Newest first' %}
@@ -84,9 +116,9 @@
</div>
{# Filter transactions form #}
<div class="collapse" id="collapse-filter" hx-preserve>
<div class="card card-body bg-base-100 shadow-xl">
<div class="text-end">
<div class="bs collapse overflow-visible" id="collapse-filter" hx-preserve>
<div class="card card-body bg-base-200 mt-2">
<div class="text-right">
<button class="btn btn-outline btn-error btn-sm w-fit"
_="on click call #filter.reset() then trigger change on #filter">{% translate 'Clear' %}</button>
</div>
@@ -98,46 +130,20 @@
{% crispy filter.form %}
</form>
<div class="text-end">
<div class="text-right">
<button class="btn btn-outline btn-error btn-sm w-fit"
_="on click call #filter.reset() then trigger change on #filter">{% translate 'Clear' %}</button>
</div>
</div>
</div>
</div>
{# Transactions list#}
<div id="transactions"
class="show-loading"
hx-get="{% url 'transactions_all_list' %}"
hx-trigger="load, updated from:window" hx-include="#filter, #page, #order">
</div>
</div>
<div class="w-full xl:w-4/12 order-1 xl:order-2">
<div role="tablist" class="tabs tabs-lifted">
<input type="radio" name="all-transactions-summary" role="tab" class="tab" aria-label="{% trans 'Currencies' %}"
{% if summary_tab == 'currency' %}checked="checked"{% endif %}
_="on change fetch {% url 'transaction_all_summary_select' selected='currency' %}" />
<div role="tabpanel" class="tab-content border-base-300 rounded-box p-6">
<div id="currency-summary"
hx-get="{% url 'transaction_all_currency_summary' %}"
class="show-loading"
hx-trigger="load, selective_update from:window, updated from:window, change from:#filter, submit from:#filter, search from:#filter"
hx-include="#filter">
</div>
</div>
<input type="radio" name="all-transactions-summary" role="tab" class="tab" aria-label="{% trans 'Accounts' %}"
{% if summary_tab == 'account' %}checked="checked"{% endif %}
_="on change fetch {% url 'transaction_all_summary_select' selected='account' %}" />
<div role="tabpanel" class="tab-content border-base-300 rounded-box p-6">
<div id="account-summary"
hx-get="{% url 'transaction_all_account_summary' %}"
class="show-loading"
hx-trigger="load, selective_update from:window, updated from:window, change from:#filter, submit from:#filter, search from:#filter"
hx-include="#filter">
</div>
</div>
</div>
</div>
</div>
</div>
<c-ui.transactions_fab></c-ui.transactions_fab>