feat: another batch of fixes

This commit is contained in:
Herculino Trotta
2025-11-02 03:03:22 -03:00
parent a63367a772
commit 89b2d0118d
30 changed files with 208 additions and 198 deletions
+1
View File
@@ -318,6 +318,7 @@ DJANGO_VITE_ASSETS_PATH = STATIC_ROOT
DJANGO_VITE_MANIFEST_PATH = DJANGO_VITE_ASSETS_PATH / "manifest.json" DJANGO_VITE_MANIFEST_PATH = DJANGO_VITE_ASSETS_PATH / "manifest.json"
DJANGO_VITE_DEV_MODE = DEBUG DJANGO_VITE_DEV_MODE = DEBUG
DJANGO_VITE_DEV_SERVER_PORT = 5173 DJANGO_VITE_DEV_SERVER_PORT = 5173
DJANGO_VITE_DEV_SERVER_HOST = "100.118.164.62"
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
+2 -2
View File
@@ -154,8 +154,8 @@ class AccountBalanceForm(forms.Form):
self.helper.layout = Layout( self.helper.layout = Layout(
"new_balance", "new_balance",
Row( Row(
Column("category", css_class="md:col-span-6 mb-0"), Column("category"),
Column("tags", css_class="md:col-span-6 mb-0"), Column("tags"),
css_class="form-row", css_class="form-row",
), ),
Field("account_id"), Field("account_id"),
+2 -2
View File
@@ -131,8 +131,8 @@ class ExchangeRateServiceForm(forms.ModelForm):
Switch("singleton"), Switch("singleton"),
"api_key", "api_key",
Row( Row(
Column("interval_type", css_class="md:col-span-6"), Column("interval_type"),
Column("fetch_interval", css_class="md:col-span-6"), Column("fetch_interval"),
), ),
"target_currencies", "target_currencies",
"target_accounts", "target_accounts",
+8 -16
View File
@@ -34,8 +34,8 @@ class DCAStrategyForm(forms.ModelForm):
self.helper.layout = Layout( self.helper.layout = Layout(
"name", "name",
Row( Row(
Column("payment_currency", css_class="md:col-span-6"), Column("payment_currency"),
Column("target_currency", css_class="md:col-span-6"), Column("target_currency"),
), ),
"notes", "notes",
) )
@@ -153,8 +153,8 @@ class DCAEntryForm(forms.ModelForm):
self.helper.layout = Layout( self.helper.layout = Layout(
"date", "date",
Row( Row(
Column("amount_paid", css_class="md:col-span-6"), Column("amount_paid"),
Column("amount_received", css_class="md:col-span-6"), Column("amount_received"),
), ),
"notes", "notes",
BS5Accordion( BS5Accordion(
@@ -166,17 +166,11 @@ class DCAEntryForm(forms.ModelForm):
Row( Row(
Column( Column(
"from_account", "from_account",
css_class="form-group",
), ),
css_class="form-row",
), ),
Row( Row(
Column( Column("from_category"),
"from_category", Column("from_tags"),
css_class="md:col-span-6 mb-0",
),
Column("from_tags", css_class="md:col-span-6 mb-0"),
css_class="form-row",
), ),
), ),
css_class="p-1 mx-1 my-3 border rounded-3", css_class="p-1 mx-1 my-3 border rounded-3",
@@ -188,12 +182,10 @@ class DCAEntryForm(forms.ModelForm):
"to_account", "to_account",
css_class="form-group", css_class="form-group",
), ),
css_class="form-row",
), ),
Row( Row(
Column("to_category", css_class="md:col-span-6 mb-0"), Column("to_category"),
Column("to_tags", css_class="md:col-span-6 mb-0"), Column("to_tags"),
css_class="form-row",
), ),
), ),
css_class="p-1 mx-1 my-3 border rounded-3", css_class="p-1 mx-1 my-3 border rounded-3",
+6 -6
View File
@@ -58,8 +58,8 @@ class MonthRangeForm(forms.Form):
self.helper.layout = Layout( self.helper.layout = Layout(
Row( Row(
Column("month_from", css_class="md:col-span-6"), Column("month_from"),
Column("month_to", css_class="md:col-span-6"), Column("month_to"),
), ),
) )
@@ -81,8 +81,8 @@ class YearRangeForm(forms.Form):
self.helper.layout = Layout( self.helper.layout = Layout(
Row( Row(
Column("year_from", css_class="md:col-span-6"), Column("year_from"),
Column("year_to", css_class="md:col-span-6"), Column("year_to"),
), ),
) )
@@ -104,8 +104,8 @@ class DateRangeForm(forms.Form):
self.helper.layout = Layout( self.helper.layout = Layout(
Row( Row(
Column("date_from", css_class="md:col-span-6"), Column("date_from"),
Column("date_to", css_class="md:col-span-6"), Column("date_to"),
css_class="mb-0", css_class="mb-0",
), ),
) )
+4 -4
View File
@@ -158,13 +158,13 @@ class TransactionsFilter(django_filters.FilterSet):
Field("description"), Field("description"),
Row(Column("date_start"), Column("date_end")), Row(Column("date_start"), Column("date_end")),
Row( Row(
Column("reference_date_start", css_class="md:col-span-6 mb-0"), Column("reference_date_start"),
Column("reference_date_end", css_class="md:col-span-6 mb-0"), Column("reference_date_end"),
css_class="form-row", css_class="form-row",
), ),
Row( Row(
Column("from_amount", css_class="md:col-span-6 mb-0"), Column("from_amount"),
Column("to_amount", css_class="md:col-span-6 mb-0"), Column("to_amount"),
css_class="form-row", css_class="form-row",
), ),
Field("account", size=1), Field("account", size=1),
+39 -49
View File
@@ -133,20 +133,20 @@ class TransactionForm(forms.ModelForm):
), ),
Field("is_paid", template="transactions/widgets/paid_toggle_button.html"), Field("is_paid", template="transactions/widgets/paid_toggle_button.html"),
Row( Row(
Column("account", css_class="md:col-span-6 mb-0"), Column("account"),
Column("entities", css_class="md:col-span-6 mb-0"), Column("entities"),
css_class="form-row", css_class="form-row",
), ),
Row( Row(
Column(Field("date"), css_class="md:col-span-6 mb-0"), Column(Field("date")),
Column(Field("reference_date"), css_class="md:col-span-6 mb-0"), Column(Field("reference_date")),
css_class="form-row", css_class="form-row",
), ),
"description", "description",
Field("amount", inputmode="decimal"), Field("amount", inputmode="decimal"),
Row( Row(
Column("category", css_class="md:col-span-6 mb-0"), Column("category"),
Column("tags", css_class="md:col-span-6 mb-0"), Column("tags"),
css_class="form-row", css_class="form-row",
), ),
"notes", "notes",
@@ -163,8 +163,8 @@ class TransactionForm(forms.ModelForm):
Field("is_paid", template="transactions/widgets/paid_toggle_button.html"), Field("is_paid", template="transactions/widgets/paid_toggle_button.html"),
"account", "account",
Row( Row(
Column(Field("date"), css_class="md:col-span-6 mb-0"), Column(Field("date")),
Column(Field("reference_date"), css_class="md:col-span-6 mb-0"), Column(Field("reference_date")),
css_class="form-row", css_class="form-row",
), ),
"description", "description",
@@ -174,8 +174,8 @@ class TransactionForm(forms.ModelForm):
_("More"), _("More"),
"entities", "entities",
Row( Row(
Column("category", css_class="md:col-span-6 mb-0"), Column("category"),
Column("tags", css_class="md:col-span-6 mb-0"), Column("tags"),
css_class="form-row", css_class="form-row",
), ),
"notes", "notes",
@@ -349,15 +349,15 @@ class QuickTransactionForm(forms.ModelForm):
"name", "name",
HTML("<hr />"), HTML("<hr />"),
Row( Row(
Column("account", css_class="md:col-span-6 mb-0"), Column("account"),
Column("entities", css_class="md:col-span-6 mb-0"), Column("entities"),
css_class="form-row", css_class="form-row",
), ),
"description", "description",
Field("amount", inputmode="decimal"), Field("amount", inputmode="decimal"),
Row( Row(
Column("category", css_class="md:col-span-6 mb-0"), Column("category"),
Column("tags", css_class="md:col-span-6 mb-0"), Column("tags"),
css_class="form-row", css_class="form-row",
), ),
"notes", "notes",
@@ -480,20 +480,20 @@ class BulkEditTransactionForm(forms.Form):
template="transactions/widgets/unselectable_paid_toggle_button.html", template="transactions/widgets/unselectable_paid_toggle_button.html",
), ),
Row( Row(
Column("account", css_class="md:col-span-6 mb-0"), Column("account"),
Column("entities", css_class="md:col-span-6 mb-0"), Column("entities"),
css_class="form-row", css_class="form-row",
), ),
Row( Row(
Column(Field("date"), css_class="md:col-span-6 mb-0"), Column(Field("date")),
Column(Field("reference_date"), css_class="md:col-span-6 mb-0"), Column(Field("reference_date")),
css_class="form-row", css_class="form-row",
), ),
"description", "description",
Field("amount", inputmode="decimal"), Field("amount", inputmode="decimal"),
Row( Row(
Column("category", css_class="md:col-span-6 mb-0"), Column("category"),
Column("tags", css_class="md:col-span-6 mb-0"), Column("tags"),
css_class="form-row", css_class="form-row",
), ),
"notes", "notes",
@@ -599,40 +599,30 @@ class TransferForm(forms.Form):
self.helper.layout = Layout( self.helper.layout = Layout(
Row( Row(
Column(Field("date"), css_class="md:col-span-6 mb-0"), Column(Field("date")),
Column( Column(
Field("reference_date"), Field("reference_date"),
css_class="md:col-span-6 mb-0",
), ),
css_class="form-row",
), ),
Field("description"), Field("description"),
Field("notes"), Field("notes"),
Switch("mute"), Switch("mute"),
Row( Row(
Column( Column("from_account"),
"from_account", Column(Field("from_amount")),
css_class="md:col-span-6", Column("from_category"),
), Column("from_tags"),
Column(
Field("from_amount"),
css_class="md:col-span-6",
),
Column("from_category", css_class="md:col-span-6"),
Column("from_tags", css_class="md:col-span-6"),
css_class="bg-base-200 rounded-box p-4 border-base-content/60 border mb-3", css_class="bg-base-200 rounded-box p-4 border-base-content/60 border mb-3",
), ),
Row( Row(
Column( Column(
"to_account", "to_account",
css_class="md:col-span-6 mb-0",
), ),
Column( Column(
Field("to_amount"), Field("to_amount"),
css_class="md:col-span-6 mb-0",
), ),
Column("to_category", css_class="md:col-span-6 mb-0"), Column("to_category"),
Column("to_tags", css_class="md:col-span-6 mb-0"), Column("to_tags"),
css_class="bg-base-200 rounded-box p-4 border-base-content/60 border mb-3", css_class="bg-base-200 rounded-box p-4 border-base-content/60 border mb-3",
), ),
FormActions( FormActions(
@@ -824,8 +814,8 @@ class InstallmentPlanForm(forms.ModelForm):
template="transactions/widgets/income_expense_toggle_buttons.html", template="transactions/widgets/income_expense_toggle_buttons.html",
), ),
Row( Row(
Column("account", css_class="md:col-span-6 mb-0"), Column("account"),
Column("entities", css_class="md:col-span-6 mb-0"), Column("entities"),
css_class="form-row", css_class="form-row",
), ),
"description", "description",
@@ -833,8 +823,8 @@ class InstallmentPlanForm(forms.ModelForm):
"notes", "notes",
Switch("add_notes_to_transaction"), Switch("add_notes_to_transaction"),
Row( Row(
Column("number_of_installments", css_class="md:col-span-6 mb-0"), Column("number_of_installments"),
Column("installment_start", css_class="md:col-span-6 mb-0"), Column("installment_start"),
css_class="form-row", css_class="form-row",
), ),
Row( Row(
@@ -845,8 +835,8 @@ class InstallmentPlanForm(forms.ModelForm):
), ),
"installment_amount", "installment_amount",
Row( Row(
Column("category", css_class="md:col-span-6 mb-0"), Column("category"),
Column("tags", css_class="md:col-span-6 mb-0"), Column("tags"),
css_class="form-row", css_class="form-row",
), ),
) )
@@ -1086,23 +1076,23 @@ class RecurringTransactionForm(forms.ModelForm):
template="transactions/widgets/income_expense_toggle_buttons.html", template="transactions/widgets/income_expense_toggle_buttons.html",
), ),
Row( Row(
Column("account", css_class="md:col-span-6 mb-0"), Column("account"),
Column("entities", css_class="md:col-span-6 mb-0"), Column("entities"),
css_class="form-row", css_class="form-row",
), ),
"description", "description",
Switch("add_description_to_transaction"), Switch("add_description_to_transaction"),
"amount", "amount",
Row( Row(
Column("category", css_class="md:col-span-6 mb-0"), Column("category"),
Column("tags", css_class="md:col-span-6 mb-0"), Column("tags"),
css_class="form-row", css_class="form-row",
), ),
"notes", "notes",
Switch("add_notes_to_transaction"), Switch("add_notes_to_transaction"),
Row( Row(
Column("start_date", css_class="md:col-span-6 mb-0"), Column("start_date"),
Column("reference_date", css_class="md:col-span-6 mb-0"), Column("reference_date"),
css_class="form-row", css_class="form-row",
), ),
Row( Row(
+5 -5
View File
@@ -53,7 +53,7 @@ class LoginForm(AuthenticationForm):
self.helper.layout = Layout( self.helper.layout = Layout(
"username", "username",
"password", "password",
Submit("Submit", "Login", css_class="btn btn-primary w-100"), Submit("Submit", "Login", css_class="w-full mt-3"),
) )
@@ -199,8 +199,8 @@ class UserUpdateForm(forms.ModelForm):
# Define the layout using Crispy Forms, including the new fields # Define the layout using Crispy Forms, including the new fields
self.helper.layout = Layout( self.helper.layout = Layout(
Row( Row(
Column("first_name", css_class="md:col-span-6"), Column("first_name"),
Column("last_name", css_class="md:col-span-6"), Column("last_name"),
css_class="row", css_class="row",
), ),
Field("email"), Field("email"),
@@ -362,8 +362,8 @@ class UserAddForm(UserCreationForm):
self.helper.layout = Layout( self.helper.layout = Layout(
Field("email"), Field("email"),
Row( Row(
Column("first_name", css_class="md:col-span-6"), Column("first_name"),
Column("last_name", css_class="md:col-span-6"), Column("last_name"),
css_class="row", css_class="row",
), ),
# UserCreationForm provides 'password1' and 'password2' fields # UserCreationForm provides 'password1' and 'password2' fields
@@ -12,7 +12,7 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="container px-md-3 py-3 gap-x-5"> <div class="container px-md-3 py-3 gap-x-5 overflow-x-hidden">
<div class="flex flex-wrap mb-4 gap-x-xl-4 gap-y-3"> <div class="flex flex-wrap mb-4 gap-x-xl-4 gap-y-3">
{# Date picker#} {# Date picker#}
<div class="w-full xl:w-4/12 flex-row items-center flex"> <div class="w-full xl:w-4/12 flex-row items-center flex">
@@ -24,7 +24,7 @@
<i class="fa-solid fa-chevron-left"></i> <i class="fa-solid fa-chevron-left"></i>
</a> </a>
</div> </div>
<div class="text-3xl font-bold font-mono w-full text-center btn btn-ghost" <div class="text-2xl font-bold btn btn-ghost flex-1 text-center whitespace-normal flex-wrap h-auto min-w-0"
hx-get="{% url 'month_year_picker' %}" hx-get="{% url 'month_year_picker' %}"
hx-target="#generic-offcanvas-left" hx-target="#generic-offcanvas-left"
hx-trigger="click, date_picker from:window" hx-trigger="click, date_picker from:window"
+1 -1
View File
@@ -3,7 +3,7 @@
{% if not divless %} {% if not divless %}
<div class="{% if text_end %}text-end{% elif text_start %}text-start{% endif %}"> <div class="{% if text_end %}text-end{% elif text_start %}text-start{% endif %}">
{% endif %} {% endif %}
<span class="amount{% if color == 'grey' or color == "gray" %} text-base-content/70{% elif color == 'green' %} text-success {% elif color == 'red' %} text-error{% endif %} {{ custom_class }}" <span class="amount{% if color == 'grey' or color == "gray" %} text-base-content/50{% elif color == 'green' %} text-success {% elif color == 'red' %} text-error{% endif %} font-medium {{ custom_class }}"
data-original-value="{% currency_display amount=amount prefix=prefix suffix=suffix decimal_places=decimal_places %}" data-original-value="{% currency_display amount=amount prefix=prefix suffix=suffix decimal_places=decimal_places %}"
data-amount="{{ amount|floatformat:"-40u" }}"> data-amount="{{ amount|floatformat:"-40u" }}">
</span><span>{{ slot }}</span> </span><span>{{ slot }}</span>
@@ -2,5 +2,5 @@
hx-trigger="{{ hx_trigger }}" hx-trigger="{{ hx_trigger }}"
hx-target="{{ hx_target }}" hx-target="{{ hx_target }}"
hx-vals='{{ hx_vals }}'> hx-vals='{{ hx_vals }}'>
{{ title }} <span class="bg-neutral/60 text-neutral-content rounded-box p-2">{{ title }}</span>
<button class="btn btn-lg btn-circle btn-{{color}}"><i class="{{ icon }} fa-fw"></i></button></div> <button class="btn btn-lg btn-circle btn-{{color}}"><i class="{{ icon }} fa-fw"></i></button></div>
@@ -1,6 +1,6 @@
<li> <li>
<div class="flex items-center"> <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> <span class="sidebar-menu-header text-base-content/60 text-sm font-bold uppercase mr-3">{{ title }}</span>
<hr class="hr flex-grow"/> <hr class="hr grow"/>
</div> </div>
</li> </li>
@@ -9,6 +9,6 @@
{% endif %}> {% endif %}>
<i class="{{ icon }} fa-fw"></i> <i class="{{ icon }} fa-fw"></i>
<span <span
class="ms-3 font-medium lg:group-hover:truncate lg:group-focus:truncate lg:group-hover:text-ellipsis lg:group-focus:text-ellipsis">{{ title }}</span> class="ms-3 font-medium">{{ title }}</span>
</a> </a>
</li> </li>
@@ -11,6 +11,6 @@
<i class="{{ icon }} fa-fw"></i> <i class="{{ icon }} fa-fw"></i>
<span <span
class="ms-3 font-medium lg:group-hover:truncate lg:group-focus:truncate lg:group-hover:text-ellipsis lg:group-focus:text-ellipsis">{{ title }}</span> class="ms-3 font-medium">{{ title }}</span>
</a> </a>
</li> </li>
@@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
<div class="flex w-full h-4 rounded-full bg-white" <div class="flex w-full h-4 rounded-full bg-white overflow-hidden"
role="group" role="group"
aria-label="{% trans 'Income and Expense Percentages' %}"> aria-label="{% trans 'Income and Expense Percentages' %}">
@@ -1,5 +1,5 @@
<div {% if div.css_id %}id="{{ div.css_id }}"{% endif %} <div {% if div.css_id %}id="{{ div.css_id }}"{% endif %}
class="{% if 'col' in div.css_class %}{{ div.css_class|default:'' }}{% else %}md:col-span-6 {{ div.css_class|default:'' }}{% endif %}" {{ div.flat_attrs }}> class="{% if 'col' in div.css_class %}{{ div.css_class|default:'' }}{% else %}md:col-span-6 col-span-12{{ div.css_class|default:'' }}{% endif %}" {{ div.flat_attrs }}>
{{ fields|safe }} {{ fields|safe }}
</div> </div>
+6 -5
View File
@@ -11,6 +11,7 @@
id="sidebar" id="sidebar"
hx-boost="true" hx-boost="true"
hx-swap="transition: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]"> 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"> <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"> <a href="{% url 'index' %}" class="m-0 hidden lg:flex justify-start p-3 no-underline sidebar-title">
@@ -24,7 +25,7 @@
hx-get="{% url 'toggle_sidebar_status' %}" hx-get="{% url 'toggle_sidebar_status' %}"
_="on click _="on click
toggle .sidebar-floating on #sidebar-container toggle .sidebar-floating on #sidebar-container
toggle .tw\:group on #sidebar-container toggle .group on #sidebar-container
toggle .sidebar-fixed on #sidebar-container toggle .sidebar-fixed on #sidebar-container
end end
" "
@@ -44,7 +45,7 @@
</div> </div>
<hr class="m-0 hr"> <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]" <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"> style="animation-duration: 100ms">
<c-components.sidebar-menu-item <c-components.sidebar-menu-item
@@ -142,7 +143,7 @@
data-bs-target="#collapsible-panel" data-bs-target="#collapsible-panel"
aria-expanded="false" aria-expanded="false"
aria-controls="collapsible-panel" aria-controls="collapsible-panel"
class="sidebar-menu-item text-wrap lg:text-nowrap lg:text-sm flex items-center no-underline p-2 rounded-2xl 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="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" %}">
<i class="fa-solid fa-toolbox fa-fw"></i> <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"> <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' %} {% translate 'Management' %}
@@ -154,7 +155,7 @@
<div class="mt-auto p-2 w-full"> <div class="mt-auto p-2 w-full">
<div id="collapsible-panel" <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="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" %}">
<div class="h-dvh backdrop-blur-3xl flex flex-col"> <div class="h-dvh bg-base-300 flex flex-col">
<div <div
class="justify-between items-center p-4 border-b border-base-content/10 sidebar-submenu-header text-base-content"> class="justify-between items-center p-4 border-b border-base-content/10 sidebar-submenu-header text-base-content">
<h5 class="text-lg font-semibold text-base-content m-0"> <h5 class="text-lg font-semibold text-base-content m-0">
@@ -170,7 +171,7 @@
</button> </button>
</div> </div>
<ul class="list-none p-3 flex flex-col gap-2 lg:group-hover:animate-[disable-pointer-events] flex-1" <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"
style="animation-duration: 100ms"> style="animation-duration: 100ms">
<c-components.sidebar-menu-header title="{% translate 'Transactions' %}"></c-components.sidebar-menu-header> <c-components.sidebar-menu-header title="{% translate 'Transactions' %}"></c-components.sidebar-menu-header>
<c-components.sidebar-menu-item <c-components.sidebar-menu-item
+1 -1
View File
@@ -13,7 +13,7 @@
<div class="mb-2 w-full lg:inline-flex grid gap-2 flex-wrap lg:justify-center" role="group" <div class="mb-2 w-full lg:inline-flex grid gap-2 flex-wrap lg:justify-center" role="group"
_="on change _="on change
set type to event.target.value set type to event.target.value
add .hidden to <#picker-form > div:not(.tw\\:hidden)/> add .hidden to <#picker-form > div:not(.hidden)/>
if type == 'month' if type == 'month'
remove .hidden from #month-form remove .hidden from #month-form
+1 -1
View File
@@ -58,7 +58,7 @@
{% include 'includes/mobile_navbar.html' %} {% include 'includes/mobile_navbar.html' %}
{% include 'includes/sidebar.html' %} {% include 'includes/sidebar.html' %}
<main class="p-4"> <main>
{% settings "DEMO" as demo_mode %} {% settings "DEMO" as demo_mode %}
{% if demo_mode %} {% if demo_mode %}
<div class="px-3 m-0" id="demo-mode-alert" hx-preserve> <div class="px-3 m-0" id="demo-mode-alert" hx-preserve>
+1 -1
View File
@@ -1,7 +1,7 @@
{% load pwa %} {% load pwa %}
{% load title %} {% load title %}
<!doctype html> <!doctype html>
<html lang="en" data-bs-theme="dark"> <html lang="en" data-theme="wygiwyh_dark">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -15,7 +15,7 @@
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
_="on click remove the closest .tw\:card to me then trigger update on #items then call bootstrap.Tooltip.getOrCreateInstance(me).dispose()"> _="on click remove the closest .card to me then trigger update on #items then call bootstrap.Tooltip.getOrCreateInstance(me).dispose()">
<i class="fa-solid fa-trash fa-fw"></i> <i class="fa-solid fa-trash fa-fw"></i>
</button> </button>
</div> </div>
@@ -41,7 +41,7 @@
</div> </div>
</div> </div>
<div id="items" _="on input or update <div id="items" _="on input or update
for card in <tw\\:card /> for card in <.card />
set price to card.querySelector('.item-price').value set price to card.querySelector('.item-price').value
set amount to card.querySelector('.item-amount').value set amount to card.querySelector('.item-amount').value
@@ -57,15 +57,15 @@
// Remove existing highlight classes from all unit prices // Remove existing highlight classes from all unit prices
for unitPriceEl in <.unit-price/> for unitPriceEl in <.unit-price/>
remove .tw\:bg-error from the closest .tw\\:card to unitPriceEl remove .bg-error from the closest .card to unitPriceEl
remove .tw\:bg-error from unitPriceEl's classList remove .bg-error from unitPriceEl's classList
remove .tw\:bg-success from the closest .tw\\:card to unitPriceEl remove .bg-success from the closest .card to unitPriceEl
remove .tw\:bg-success from unitPriceEl's classList remove .bg-success from unitPriceEl's classList
end end
// Get all unit prices and find min/max // Get all unit prices and find min/max
set unitPrices to <.tw\:card\:not(#card-placeholder) .unit-price/> set unitPrices to <card:not(#card-placeholder) .unit-price/>
set unitPricesAmounts to <.tw\:card\:not(#card-placeholder) .unit-price/> @data-amount set unitPricesAmounts to <.tw:card:not(#card-placeholder) .unit-price/> @data-amount
js(unitPricesAmounts) js(unitPricesAmounts)
unitPricesAmounts = unitPricesAmounts.filter(element => element !== '0') unitPricesAmounts = unitPricesAmounts.filter(element => element !== '0')
return Math.min(...unitPricesAmounts) return Math.min(...unitPricesAmounts)
@@ -81,13 +81,13 @@
for unitPriceEl in unitPrices for unitPriceEl in unitPrices
set amount to parseFloat(unitPriceEl.getAttribute('data-amount')) set amount to parseFloat(unitPriceEl.getAttribute('data-amount'))
if amount == minAmount if amount == minAmount
add .tw\:bg-success to the closest .tw\:card to unitPriceEl add .bg-success to the closest .card to unitPriceEl
add .tw\:bg-opacity-20 to the closest .tw\:card to unitPriceEl add .bg-opacity-20 to the closest .card to unitPriceEl
continue continue
end end
if amount == maxAmount if amount == maxAmount
add .tw\:bg-error to the closest .tw\:card to unitPriceEl add .bg-error to the closest .card to unitPriceEl
add .tw\:bg-opacity-20 to the closest .tw\:card to unitPriceEl add .bg-opacity-20 to the closest .card to unitPriceEl
end end
end end
end end
@@ -151,8 +151,8 @@
get #card-placeholder get #card-placeholder
set newCard to it.cloneNode(true) set newCard to it.cloneNode(true)
remove @id from newCard remove @id from newCard
remove .tw\:hidden from newCard then remove .hidden from newCard then
set itemCount to <#items [class='card'] />'s length set itemCount to <#items[class='card'] />'s length
if itemCount < 26 if itemCount < 26
set letter to String.fromCharCode(65 + itemCount) set letter to String.fromCharCode(65 + itemCount)
else else
@@ -169,7 +169,7 @@
<button class="btn btn-outline btn-error w-full" <button class="btn btn-outline btn-error w-full"
_="on click _="on click
for el in <.item-price, .item-amount /> for el in <.item-price, .item-amount />
set card to the closest .\card to el set card to the closest .card to el
set el's value to '' set el's value to ''
end end
trigger update on #items trigger update on #items
@@ -12,45 +12,40 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="container px-3 md:px-3 py-3 gap-5"> <div class="container gap-y-3">
<div class="grid grid-cols-1 xl:grid-cols-12 gap-x-4 gap-y-3 mb-4"> <div class="row ">
{# Date picker#} <div class="col-12 lg:col-4">
<div class="col-span-1 xl:col-span-4 flex flex-row items-center"> {# Date picker#}
<div class="text-base h-full flex items-center btn btn-ghost"> <div class="col-span-1 xl:col-span-4 flex flex-row items-center">
<a role="button" <div class="text-base h-full flex items-center btn btn-ghost">
hx-boost="true" <a role="button"
hx-trigger="click, previous_month from:window" hx-boost="true"
href="{% url 'monthly_overview' month=previous_month year=previous_year %}"><i hx-trigger="click, previous_month from:window"
class="fa-solid fa-chevron-left"></i></a> href="{% url 'monthly_overview' month=previous_month year=previous_year %}"><i
</div> class="fa-solid fa-chevron-left"></i></a>
<div class="text-3xl font-bold btn btn-ghost w-full text-center" </div>
hx-get="{% url 'month_year_picker' %}" <div class="text-2xl font-bold btn btn-ghost flex-1 text-center whitespace-normal flex-wrap h-auto min-w-0"
hx-target="#generic-offcanvas-left" hx-get="{% url 'month_year_picker' %}"
hx-trigger="click, date_picker from:window" hx-target="#generic-offcanvas-left"
hx-vals='{"month": {{ month }}, "year": {{ year }}, "for": "monthly_overview", "field": "reference_date"}' hx-trigger="click, date_picker from:window"
role="button"> hx-vals='{"month": {{ month }}, "year": {{ year }}, "for": "monthly_overview", "field": "reference_date"}'
{{ month|month_name }} {{ year }} role="button">
</div> {{ month|month_name }} {{ year }}
<div class="text-base h-full flex items-center btn btn-ghost"> </div>
<a role="button" <div class="text-base h-full flex items-center btn btn-ghost">
hx-boost="true" <a role="button"
hx-trigger="click, next_month from:window" hx-boost="true"
href="{% url 'monthly_overview' month=next_month year=next_year %}"> hx-trigger="click, next_month from:window"
<i class="fa-solid fa-chevron-right"></i> href="{% url 'monthly_overview' month=next_month year=next_year %}">
</a> <i class="fa-solid fa-chevron-right"></i>
</a>
</div>
</div> </div>
</div> </div>
{# Action buttons#}
{# <div class="col-12 col-xl-8">#}
{# <c-ui.quick-transactions-buttons#}
{# :year="year"#}
{# :month="month"#}
{# ></c-ui.quick-transactions-buttons>#}
{# </div>#}
</div> </div>
{# Monthly summary#} {# Monthly summary#}
<div class="grid grid-cols-1 xl:grid-cols-12 gap-x-4 gap-y-3"> <div class="row gap-y-3">
<div class="col-span-1 xl:col-span-4 lg:order-last! order-first!"> <div class="col-12 lg:col-4 lg:order-last! order-first!">
<div role="tablist" class="tabs tabs-border"> <div role="tablist" class="tabs tabs-border">
<input type="radio" name="monthly_summary_tabs" class="tab" aria-label="{% trans 'Summary' %}" <input type="radio" name="monthly_summary_tabs" class="tab" aria-label="{% trans 'Summary' %}"
role="tab" role="tab"
@@ -93,7 +88,7 @@
</div> </div>
</div> </div>
<div class="col-span-1 xl:col-span-8 lg:order-first! order-last!"> <div class="col-12 lg:col-8 lg:order-first! order-last!">
<div class="my-3"> <div class="my-3">
{# Hidden select to hold the order value and preserve the original update trigger #} {# Hidden select to hold the order value and preserve the original update trigger #}
+30 -28
View File
@@ -31,9 +31,8 @@
</div> </div>
<div class="container px-md-3 py-3" <div class="container px-md-3 py-3"
_="init call initializeAccountChart() then initializeCurrencyChart() then initializeMonthlyDifferenceChart() end"> _="init call initializeAccountChart() then initializeCurrencyChart() then initializeMonthlyDifferenceChart() end">
<div class="flex flex-wrap gap-x-xl-4 gap-y-3 mb-4"> <div class="row gap-y-3">
<div class="w-full xl:w-5/12"> <div class="col lg:col-5">
<div class="grid grid-cols-1 gap-4">
<div> <div>
<c-ui.info-card color="yellow" icon="fa-solid fa-coins" title="{% trans 'By currency' %}" <c-ui.info-card color="yellow" icon="fa-solid fa-coins" title="{% trans 'By currency' %}"
title_css_classes="cursor-pointer" title_css_classes="cursor-pointer"
@@ -41,7 +40,7 @@
{% for currency in currency_net_worth.values %} {% for currency in currency_net_worth.values %}
<div class="flex justify-between mt-2"> <div class="flex justify-between mt-2">
<div class="flex items-baseline w-full"> <div class="flex items-baseline w-full">
<div class="currency-name text-start font-mono text-base-content/60 cursor-pointer" <div class="currency-name text-start font-mono text-base-content cursor-pointer"
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }}')"> _="on click showOnlyCurrencyDataset('{{ currency.currency.name }}')">
{{ currency.currency.name }} {{ currency.currency.name }}
</div> </div>
@@ -87,30 +86,32 @@
{% endfor %} {% endfor %}
</c-ui.info-card> </c-ui.info-card>
</div> </div>
</div>
</div> </div>
<div class="w-full xl:w-7/12"> <div class="col lg:col-7">
<div role="tablist" class="tabs tabs-bordered w-full" id="myTab"> <div class="card bg-base-100">
<input type="radio" name="networth_tabs" role="tab" class="tab" aria-label="{% trans 'Evolution' %}" id="tab-evolution" checked="checked" /> <div class="card-body">
<div role="tabpanel" class="tab-content p-4" id="evolution-tab-pane"> <div role="tablist" class="tabs tabs-border w-full" id="myTab">
<div class="chart-container relative min-h-[40vh] h-full w-full"> <input type="radio" name="networth_tabs" role="tab" class="tab" aria-label="{% trans 'Evolution' %}" id="tab-evolution" checked="checked" />
<canvas id="currencyBalanceChart"></canvas> <div role="tabpanel" class="tab-content p-4" id="evolution-tab-pane">
</div> <div class="chart-container relative min-h-[40vh] h-full w-full">
</div> <canvas id="currencyBalanceChart"></canvas>
</div>
</div>
<input type="radio" name="networth_tabs" role="tab" class="tab" aria-label="{% trans 'Difference' %}" id="tab-diff" /> <input type="radio" name="networth_tabs" role="tab" class="tab" aria-label="{% trans 'Difference' %}" id="tab-diff" />
<div role="tabpanel" class="tab-content p-4" id="diff-tab-pane"> <div role="tabpanel" class="tab-content p-4" id="diff-tab-pane">
<div class="chart-container relative min-h-[40vh] h-full w-full"> <div class="chart-container relative min-h-[40vh] h-full w-full">
<canvas id="monthlyDifferenceChart"></canvas> <canvas id="monthlyDifferenceChart"></canvas>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<hr class="text-base-content/60"> <hr class="hr my-6">
<div class="flex flex-wrap gap-x-xl-4 gap-y-3 mt-4"> <div class="row gap-y-3">
<div class="w-full xl:w-5/12"> <div class="col lg:col-5">
<div class="grid grid-cols-1 gap-4">
<div> <div>
<c-ui.info-card color="blue" icon="fa-solid fa-wallet" title="{% trans 'By account' %}" <c-ui.info-card color="blue" icon="fa-solid fa-wallet" title="{% trans 'By account' %}"
title_css_classes="cursor-pointer" title_css_classes="cursor-pointer"
@@ -120,14 +121,14 @@
{% if data.grouper %} {% if data.grouper %}
<div class="flex justify-between mt-2"> <div class="flex justify-between mt-2">
<div class="flex items-baseline w-full"> <div class="flex items-baseline w-full">
<div class="text-start font-mono text-base-content/60"><span class="badge badge-primary"> <div class="text-start font-mono text-base-content"><span class="badge badge-primary">
{{ data.grouper }}</span></div> {{ data.grouper }}</span></div>
</div> </div>
</div> </div>
{% for account in data.list %} {% for account in data.list %}
<div class="flex justify-between mt-2"> <div class="flex justify-between mt-2">
<div class="flex items-baseline w-full"> <div class="flex items-baseline w-full">
<div class="account-name text-start font-mono text-base-content/60 cursor-pointer" <div class="account-name text-start font-mono text-base-content cursor-pointer"
_="on click showOnlyAccountDataset('{{ account.account.name }}')"> _="on click showOnlyAccountDataset('{{ account.account.name }}')">
<span class="hierarchy-line-icon"></span>{{ account.account.name }}</div> <span class="hierarchy-line-icon"></span>{{ account.account.name }}</div>
<div class="dotted-line flex-grow"></div> <div class="dotted-line flex-grow"></div>
@@ -155,7 +156,7 @@
{% for account in data.list %} {% for account in data.list %}
<div class="flex justify-between mt-2"> <div class="flex justify-between mt-2">
<div class="flex items-baseline w-full"> <div class="flex items-baseline w-full">
<div class="account-name text-start font-mono text-base-content/60 cursor-pointer" <div class="account-name text-start font-mono text-base-content cursor-pointer"
_="on click showOnlyAccountDataset('{{ account.account.name }}')"> _="on click showOnlyAccountDataset('{{ account.account.name }}')">
{{ account.account.name }} {{ account.account.name }}
</div> </div>
@@ -184,11 +185,12 @@
{% endfor %} {% endfor %}
</c-ui.info-card> </c-ui.info-card>
</div> </div>
</div>
</div> </div>
<div class="w-full xl:w-7/12"> <div class="col lg:col-7">
<div class="chart-container relative min-h-[40vh] h-full"> <div class="chart-container relative min-h-[40vh] h-full card bg-base-100">
<canvas id="accountBalanceChart"></canvas> <div class="card-body">
<canvas id="accountBalanceChart"></canvas>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -5,7 +5,7 @@
{% block title %}{% translate 'Transactions' %}{% endblock %} {% block title %}{% translate 'Transactions' %}{% endblock %}
{% block content %} {% block content %}
<div class="container px-md-3 py-3 column-gap-5"> <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="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="w-full xl:w-8/12 order-2 xl:order-1">
<div class="mb-3"> <div class="mb-3">
+2 -6
View File
@@ -7,10 +7,8 @@
{% block title %}Login{% endblock %} {% block title %}Login{% endblock %}
{% block content %} {% block content %}
<div> <div class="min-h-screen flex items-center justify-center p-4">
<div class="container"> <div class="w-full max-w-md">
<div class="grid h-dvh flex justify-center items-center">
<div class="col-span-12 md:col-span-6 xl:col-span-4">
{% settings "DEMO" as demo_mode %} {% settings "DEMO" as demo_mode %}
{% if demo_mode %} {% if demo_mode %}
<div class="card bg-base-100 shadow-xl mb-3"> <div class="card bg-base-100 shadow-xl mb-3">
@@ -47,7 +45,5 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}
@@ -22,7 +22,7 @@
</a> </a>
</div> </div>
</div> </div>
<div class="container px-md-3 py-3 gap-x-5" id="yearly-content"> <div class="container px-md-3 py-3 gap-x-5 overflow-x-hidden" id="yearly-content">
<div class="flex flex-wrap mb-4 gap-x-xl-4 gap-y-3"> <div class="flex flex-wrap mb-4 gap-x-xl-4 gap-y-3">
{# Date picker#} {# Date picker#}
<div class="w-full xl:w-auto flex-row items-center flex"> <div class="w-full xl:w-auto flex-row items-center flex">
@@ -33,7 +33,7 @@
href="{% block previous_year_url %}{% endblock %}"> href="{% block previous_year_url %}{% endblock %}">
<i class="fa-solid fa-chevron-left"></i></a> <i class="fa-solid fa-chevron-left"></i></a>
</div> </div>
<div class="text-3xl font-bold font-mono w-full text-center"> <div class="text-2xl font-bold btn btn-ghost flex-1 text-center whitespace-normal flex-wrap h-auto min-w-0">
{{ year }} {{ year }}
</div> </div>
<div class="text-base mx-2 h-full items-center flex btn btn-ghost"> <div class="text-base mx-2 h-full items-center flex btn btn-ghost">
+14 -1
View File
@@ -9,7 +9,6 @@ window.TomSelect = function createDynamicTomSelect(element) {
const config = { const config = {
plugins: {}, plugins: {},
maxOptions: null, maxOptions: null,
dropdownParent: 'body',
// Extract 'create' option from data attribute // Extract 'create' option from data attribute
create: element.dataset.create === 'true', create: element.dataset.create === 'true',
@@ -25,8 +24,12 @@ window.TomSelect = function createDynamicTomSelect(element) {
}, },
onInitialize: function () { onInitialize: function () {
// Move dropdown to body to escape stacking context issues
document.body.appendChild(this.dropdown);
this.popper = Popper.createPopper(this.control, this.dropdown, { this.popper = Popper.createPopper(this.control, this.dropdown, {
placement: "bottom-start", placement: "bottom-start",
strategy: "fixed",
modifiers: [ modifiers: [
{ {
name: "sameWidth", name: "sameWidth",
@@ -43,6 +46,13 @@ window.TomSelect = function createDynamicTomSelect(element) {
fallbackPlacements: ['top-start'], fallbackPlacements: ['top-start'],
}, },
}, },
{
name: 'preventOverflow',
options: {
boundary: 'viewport',
padding: 8,
},
},
] ]
}); });
@@ -50,6 +60,9 @@ window.TomSelect = function createDynamicTomSelect(element) {
}, },
onDropdownOpen: function () { onDropdownOpen: function () {
this.popper.update(); this.popper.update();
},
onDropdownClose: function () {
// Optional: move back to wrapper to keep DOM clean, but not necessary
} }
}; };
+4 -4
View File
@@ -195,12 +195,12 @@
/* Dropdown */ /* Dropdown */
.ts-dropdown { .ts-dropdown {
position: absolute; position: fixed;
top: 100%; top: 0;
left: 0; left: 0;
width: 100%; width: auto;
z-index: 1100; z-index: 1100;
margin: 0.25rem 0 0; margin: 0;
/* DaisyUI dropdown styling */ /* DaisyUI dropdown styling */
background-color: var(--color-base-100); background-color: var(--color-base-100);
+21 -2
View File
@@ -119,7 +119,7 @@
@layer components { @layer components {
/* === Sidebar styles === */ /* === Sidebar styles === */
.sidebar-active { .sidebar-active {
@apply text-primary-content bg-primary; @apply text-primary-content bg-primary rounded-box;
} }
.sidebar-item:not(.sidebar-active) { .sidebar-item:not(.sidebar-active) {
@@ -145,9 +145,28 @@
@apply lg:ml-16 transition-all duration-100; @apply lg:ml-16 transition-all duration-100;
} }
.sidebar-floating .sidebar-item span { .sidebar-floating .sidebar-item {
/* Maintains consistent height when collapsed */
@apply lg:min-h-[2.3rem];
}
.sidebar-floating .sidebar-item i {
/* Centers icon when collapsed by adding auto margins */
@apply lg:mx-auto lg:group-hover:mx-0;
}
.sidebar-floating .sidebar-item span,
.sidebar-floating .sidebar-item i:not(:first-child) {
/* Hides the text labels and reveals them only on hover */ /* Hides the text labels and reveals them only on hover */
@apply lg:invisible lg:group-hover:visible; @apply lg:invisible lg:group-hover:visible;
/* Position absolute to remove from layout when invisible */
@apply lg:absolute lg:group-hover:static;
}
.htmx-swapping .sidebar-floating,
.htmx-settling .sidebar-floating {
pointer-events: none;
@apply lg:w-16!;
} }
.sidebar-floating .sidebar-invisible { .sidebar-floating .sidebar-invisible {
+2 -1
View File
@@ -42,7 +42,8 @@ export default defineConfig({
usePolling: true, usePolling: true,
disableGlobbing: false, disableGlobbing: false,
}, },
origin: 'http://localhost:5173' cors: true,
origin: 'http://100.118.164.62:5173'
}, },
resolve: { resolve: {