feat: another batch

This commit is contained in:
Herculino Trotta
2025-11-03 01:40:13 -03:00
parent 89b2d0118d
commit 9ade58a003
49 changed files with 822 additions and 493 deletions

View File

@@ -4,4 +4,5 @@
"*.css": "tailwindcss"
},
"tailwindCSS.experimental.configFile": "frontend/src/styles/tailwind.css",
"djlint.profile": "django",
}

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Account Groups' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'account_group_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
@@ -32,15 +31,13 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'account_group_edit' pk=account_group.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'account_group_delete' pk=account_group.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
@@ -51,8 +48,7 @@
{% if not account_group.owner %}
<a class="btn btn-secondary btn-sm join-item text-warning"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
data-tippy-content="{% translate "Take ownership" %}"
hx-get="{% url 'account_group_take_ownership' pk=account_group.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
@@ -61,8 +57,7 @@
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
data-tippy-content="{% translate "Share" %}"
hx-get="{% url 'account_group_share_settings' pk=account_group.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Accounts' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'account_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
@@ -37,15 +36,13 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'account_edit' pk=account.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'account_delete' pk=account.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
@@ -56,8 +53,7 @@
{% if not account.owner %}
<a class="btn btn-secondary btn-sm join-item text-primary"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
data-tippy-content="{% translate "Take ownership" %}"
hx-get="{% url 'account_take_ownership' pk=account.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
@@ -66,16 +62,14 @@
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
data-tippy-content="{% translate "Share" %}"
hx-get="{% url 'account_share_settings' pk=account.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
<a class="btn btn-secondary btn-sm join-item"
role="button"
hx-get="{% url 'account_toggle_untracked' pk=account.id %}"
data-bs-toggle="tooltip"
data-bs-title="{% if account.is_untracked_by %}{% translate "Track" %}{% else %}{% translate "Untrack" %}{% endif %}">
data-tippy-content="{% if account.is_untracked_by %}{% translate "Track" %}{% else %}{% translate "Untrack" %}{% endif %}">
{% if account.is_untracked_by %}
<i class="fa-solid fa-eye fa-fw"></i>
{% else %}

View File

@@ -39,23 +39,23 @@
{% for transaction in date.transactions %}
{% if transaction.is_paid %}
{% if transaction.type == "IN" and not transaction.account.is_asset %}
<i class="fa-solid fa-circle-check text-success" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
<i class="fa-solid fa-circle-check text-success" data-tippy-content="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
{% elif transaction.type == "IN" and transaction.account.is_asset %}
<i class="fa-solid fa-circle-check text-success/80" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
<i class="fa-solid fa-circle-check text-success/80" data-tippy-content="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
{% elif transaction.type == "EX" and not transaction.account.is_asset %}
<i class="fa-solid fa-circle-check text-error" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
<i class="fa-solid fa-circle-check text-error" data-tippy-content="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
{% elif transaction.type == "EX" and transaction.account.is_asset %}
<i class="fa-solid fa-circle-check text-error/80" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
<i class="fa-solid fa-circle-check text-error/80" data-tippy-content="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
{% endif %}
{% else %}
{% if transaction.type == "IN" and not transaction.account.is_asset %}
<i class="fa-regular fa-circle text-success" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
<i class="fa-regular fa-circle text-success" data-tippy-content="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
{% elif transaction.type == "IN" and transaction.account.is_asset %}
<i class="fa-regular fa-circle text-success/80" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
<i class="fa-regular fa-circle text-success/80" data-tippy-content="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Income' %}{% endif %}"></i>
{% elif transaction.type == "EX" and not transaction.account.is_asset %}
<i class="fa-regular fa-circle text-error" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
<i class="fa-regular fa-circle text-error" data-tippy-content="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
{% elif transaction.type == "EX" and transaction.account.is_asset %}
<i class="fa-regular fa-circle text-error/80" data-bs-toggle="tooltip" data-bs-title="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
<i class="fa-regular fa-circle text-error/80" data-tippy-content="{% if transaction.description %}{{ transaction.description }}{% else %}{% trans 'Expense' %}{% endif %}"></i>
{% endif %}
{% endif %}
{% endfor %}

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Categories' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'category_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>

View File

@@ -24,16 +24,14 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
hx-swap="innerHTML"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'category_edit' category_id=category.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'category_delete' category_id=category.id %}"
hx-trigger='confirmed'
hx-swap="innerHTML"
@@ -45,8 +43,7 @@
{% if not category.owner %}
<a class="btn btn-secondary btn-sm join-item text-primary"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
data-tippy-content="{% translate "Take ownership" %}"
hx-get="{% url 'category_take_ownership' category_id=category.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
@@ -55,8 +52,7 @@
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
data-tippy-content="{% translate "Share" %}"
hx-get="{% url 'category_share_settings' pk=category.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}

View File

@@ -3,9 +3,8 @@
<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" %}"
{% if tooltip %}
data-bs-placement="right"
data-bs-toggle="tooltip"
data-bs-title="{{ tooltip }}"
data-tippy-placement="right"
data-tippy-content="{{ tooltip }}"
{% endif %}>
<i class="{{ icon }} fa-fw"></i>
<span

View File

@@ -4,9 +4,8 @@
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" %}"
{% if tooltip %}
data-bs-placement="right"
data-bs-toggle="tooltip"
data-bs-title="{{ tooltip }}"
data-tippy-placement="right"
data-tippy-content="{{ tooltip }}"
{% endif %}>
<i class="{{ icon }} fa-fw"></i>

View File

@@ -1,7 +1,7 @@
{% load markdown %}
{% load i18n %}
<div
class="transaction {% if transaction.type == "EX" %}expense{% else %}income{% endif %} group/transaction relative hover:z-10">
class="transaction {% if transaction.type == "EX" %}expense{% else %}income{% endif %} group/transaction relative group-hover/transaction:z-50 hover:z-50">
<div class="flex my-1">
{% if not disable_selection or not dummy %}
<label class="px-3 flex! items-center justify-center">
@@ -135,36 +135,33 @@
</div>
</div>
{% if not dummy %}
<div>
<div class="z-1000">
{# Item actions#}
<div
class="transaction-actions absolute! left-1/2 top-0 -translate-x-1/2 -translate-y-1/2 invisible group-hover/transaction:visible! flex flex-row card bg-base-300">
class="card transaction-actions absolute! left-1/2 -translate-x-1/2 -translate-y-1/2 top-0 invisible group-hover/transaction:visible! flex flex-row bg-base-300">
<div class="card-body p-1 shadow-lg flex flex-row gap-1">
{% if not transaction.deleted %}
<div class="tooltip" data-tip="{% translate "Edit" %}">
<a class="btn btn-neutral btn-sm transaction-action"
role="button"
hx-get="{% url 'transaction_edit' transaction_id=transaction.id %}"
hx-target="#generic-offcanvas" hx-swap="innerHTML">
<i class="fa-solid fa-pencil fa-fw"></i></a>
</div>
<div class="tooltip" data-tip="{% translate "Delete" %}">
<a class="btn btn-neutral btn-sm transaction-action"
role="button"
hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw text-red-500"></i>
</a>
</div>
<div class="dropdown dropdown-end">
<button type="button" tabindex="0" role="button" class="btn btn-neutral btn-sm transaction-action">
<a class="btn btn-neutral btn-sm transaction-action"
role="button"
hx-get="{% url 'transaction_edit' transaction_id=transaction.id %}"
hx-target="#generic-offcanvas" hx-swap="innerHTML"
data-tippy-content="{% translate "Edit" %}">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-neutral btn-sm transaction-action"
role="button"
hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}"
hx-trigger='confirmed'
data-tippy-content="{% translate "Delete" %}"
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw text-error"></i>
</a>
<button class="btn btn-neutral btn-sm transaction-action" data-bs-toggle="dropdown" data-bs-container="body" aria-expanded="false">
<i class="fa-solid fa-ellipsis fa-fw"></i>
</button>
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-200 rounded-box w-72 z-[1]">
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-md-start menu w-max">
{% if transaction.account.is_untracked_by %}
<li>
<a class="disabled flex items-center" aria-disabled="true">
@@ -218,7 +215,6 @@
hx-get="{% url 'transaction_clone' transaction_id=transaction.id %}"><i
class="fa-solid fa-clone fa-fw mr-2"></i>{% translate 'Duplicate' %}</a></li>
</ul>
</div>
{% else %}
<div class="tooltip" data-tip="{% translate "Restore" %}">
<a class="btn btn-secondary btn-sm transaction-action"

View File

@@ -43,16 +43,14 @@
<button class="btn btn-secondary btn-sm"
hx-get="{% url 'transactions_bulk_undelete' %}"
hx-include=".transaction"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Restore' %}">
data-tippy-content="{% translate 'Restore' %}">
<i class="fa-solid fa-trash-arrow-up fa-fw"></i>
</button>
<button class="btn btn-secondary btn-sm"
hx-get="{% url 'transactions_bulk_delete' %}"
hx-include=".transaction"
hx-trigger="confirmed"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Delete' %}"
data-tippy-content="{% translate 'Delete' %}"
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"

View File

@@ -48,8 +48,7 @@
hx-get="{% url 'transactions_bulk_edit' %}"
hx-target="#generic-offcanvas"
hx-include=".transaction"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Edit' %}">
data-tippy-content="{% translate 'Edit' %}">
<i class="fa-solid fa-pencil"></i>
</button>
<div class="dropdown dropdown-top dropdown-end">
@@ -78,16 +77,14 @@
<button class="btn btn-secondary btn-sm"
hx-get="{% url 'transactions_bulk_clone' %}"
hx-include=".transaction"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Duplicate' %}">
data-tippy-content="{% translate 'Duplicate' %}">
<i class="fa-solid fa-clone fa-fw"></i>
</button>
<button class="btn btn-secondary btn-sm"
hx-get="{% url 'transactions_bulk_delete' %}"
hx-include=".transaction"
hx-trigger="confirmed"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Delete' %}"
data-tippy-content="{% translate 'Delete' %}"
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Currencies' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'currency_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
@@ -34,15 +33,13 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'currency_edit' pk=currency.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'currency_delete' pk=currency.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"

View File

@@ -33,8 +33,7 @@
<div class="card-title text-xl">{% trans "Entries" %}<span>
<a class="no-underline p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'dca_entry_add' strategy_id=strategy.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i>
@@ -63,16 +62,14 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'dca_entry_edit' entry_id=entry.id strategy_id=entry.strategy.id %}"
hx-target="#generic-offcanvas"
hx-swap="innerHTML">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'dca_entry_delete' entry_id=entry.id strategy_id=entry.strategy.id %}"
hx-trigger='confirmed'
hx-swap="innerHTML"

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Dollar Cost Average Strategies' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'dca_strategy_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
@@ -32,16 +31,14 @@
<div class="card-footer bg-base-200 p-4 text-right">
<a class="no-underline text-base-content/60 p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'dca_strategy_edit' strategy_id=strategy.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i>
</a>
<a class="text-error no-underline p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'dca_strategy_delete' strategy_id=strategy.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
@@ -54,8 +51,7 @@
{% if not strategy.owner %}
<a class="text-primary no-underline p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
data-tippy-content="{% translate "Take ownership" %}"
hx-get="{% url 'dca_strategy_take_ownership' strategy_id=strategy.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
@@ -63,8 +59,7 @@
<a class="text-primary no-underline p-1"
role="button"
hx-target="#generic-offcanvas"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
data-tippy-content="{% translate "Share" %}"
hx-get="{% url 'dca_strategy_share_settings' pk=strategy.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Entities' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'entity_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>

View File

@@ -24,16 +24,14 @@
<a class="btn btn-secondary btn-sm join-item"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'entity_edit' entity_id=entity.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'entity_delete' entity_id=entity.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
@@ -44,8 +42,7 @@
{% if not entity.owner %}
<a class="btn btn-secondary btn-sm join-item text-warning"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
data-tippy-content="{% translate "Take ownership" %}"
hx-get="{% url 'entity_take_ownership' entity_id=entity.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
@@ -54,8 +51,7 @@
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
data-tippy-content="{% translate "Share" %}"
hx-get="{% url 'entity_share_settings' pk=entity.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}

View File

@@ -6,8 +6,7 @@
<div>{% translate 'Exchange Rates' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'exchange_rate_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>

View File

@@ -19,16 +19,14 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'exchange_rate_edit' pk=exchange_rate.id %}"
hx-target="#generic-offcanvas"
hx-swap="innerHTML">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'exchange_rate_delete' pk=exchange_rate.id %}"
hx-trigger='confirmed'
hx-swap="innerHTML"

View File

@@ -6,8 +6,7 @@
<div>{% translate 'Automatic Exchange Rates' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'automatic_exchange_rate_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
@@ -42,15 +41,13 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'automatic_exchange_rate_edit' pk=service.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'automatic_exchange_rate_delete' pk=service.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"

View File

@@ -19,16 +19,14 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'exchange_rate_edit' pk=exchange_rate.id %}"
hx-target="#generic-offcanvas"
hx-swap="innerHTML">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'exchange_rate_delete' pk=exchange_rate.id %}"
hx-trigger='confirmed'
hx-swap="innerHTML"

View File

@@ -3,8 +3,7 @@
<div class="text-3xl font-bold font-mono w-full mb-3">
{% spaceless %}
<div>{% translate 'Import Profiles' %}<span>
<span class="dropdown" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}">
<span class="dropdown" data-tippy-content="{% translate "Add" %}">
<a class="no-underline text-2xl p-1" role="button"
data-bs-toggle="dropdown"
data-bs-title="{% translate "Add" %}" aria-expanded="false">
@@ -42,29 +41,25 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'import_profile_edit' profile_id=profile.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-success"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Runs" %}"
data-tippy-content="{% translate "Runs" %}"
hx-get="{% url 'import_profile_runs_list' profile_id=profile.id %}"
hx-target="#persistent-generic-offcanvas-left">
<i class="fa-solid fa-person-running fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-primary"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Import" %}"
data-tippy-content="{% translate "Import" %}"
hx-get="{% url 'import_run_add' profile_id=profile.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-file-import fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'import_profile_delete' profile_id=profile.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"

View File

@@ -92,14 +92,12 @@
<div class="card-footer bg-base-200 p-4 text-base-content/70">
<a class="no-underline text-info"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Logs" %}"
data-tippy-content="{% translate "Logs" %}"
hx-get="{% url 'import_run_log' profile_id=profile.id run_id=run.id %}"
hx-target="#generic-offcanvas"><i class="fa-solid fa-file-lines"></i></a>
<a class="no-underline text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'import_run_delete' profile_id=profile.id run_id=run.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"

View File

@@ -152,9 +152,8 @@
<a class="dropdown-item"
href="{% url 'admin:index' %}"
hx-boost="false"
data-bs-placement="right"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Only use this if you know what you're doing" %}">
data-tippy-placement="right"
data-tippy-content="{% translate "Only use this if you know what you're doing" %}">
{% translate 'Django Admin' %}
</a>
</li>
@@ -171,7 +170,7 @@
{% endif %}
<li class="nav-item">
<div class="nav-link lg:text-2xl! cursor-pointer"
data-bs-toggle="tooltip" data-bs-placement="left" data-bs-title="{% trans "Calculator" %}"
data-tippy-placement="left" data-tippy-content="{% trans "Calculator" %}"
_="on click trigger show on #calculator">
<i class="fa-solid fa-calculator"></i>
<span class="d-lg-none d-inline">{% trans "Calculator" %}</span>

View File

@@ -1,17 +1,17 @@
<div id="persistent-generic-offcanvas" class="offcanvas offcanvas-end offcanvas-size-xl z-1100!"
data-bs-backdrop="static"
tabindex="-1"
_="on htmx:afterSettle call bootstrap.Offcanvas.getOrCreateInstance(me).show() end
on htmx:beforeOnLoad[detail.boosted] call bootstrap.Offcanvas.getOrCreateInstance(me).hide()
on force_hide_offcanvas call bootstrap.Offcanvas.getOrCreateInstance(me).hide() end
_="on htmx:afterSettle call Offcanvas.getOrCreateInstance(me).show() end
on htmx:beforeOnLoad[detail.boosted] call Offcanvas.getOrCreateInstance(me).hide()
on force_hide_offcanvas call Offcanvas.getOrCreateInstance(me).hide() end
on hidden.bs.offcanvas set my innerHTML to '' end">
</div>
<div id="persistent-generic-offcanvas-left" class="offcanvas offcanvas-start offcanvas-size-xl z-1100!"
data-bs-backdrop="static"
tabindex="-1"
_="on htmx:afterSettle call bootstrap.Offcanvas.getOrCreateInstance(me).show() end
on htmx:beforeOnLoad[detail.boosted] call bootstrap.Offcanvas.getOrCreateInstance(me).hide()
on force_hide_offcanvas call bootstrap.Offcanvas.getOrCreateInstance(me).hide() end
_="on htmx:afterSettle call Offcanvas.getOrCreateInstance(me).show() end
on htmx:beforeOnLoad[detail.boosted] call Offcanvas.getOrCreateInstance(me).hide()
on force_hide_offcanvas call Offcanvas.getOrCreateInstance(me).hide() end
on hidden.bs.offcanvas set my innerHTML to '' end">
</div>
@@ -19,16 +19,16 @@
<div id="generic-offcanvas" class="offcanvas offcanvas-end offcanvas-size-xl z-1100!"
data-bs-backdrop="static"
tabindex="-1"
_="on htmx:afterSettle call bootstrap.Offcanvas.getOrCreateInstance(me).show() end
on hide_offcanvas call bootstrap.Offcanvas.getOrCreateInstance(me).hide() end
on htmx:beforeOnLoad[detail.boosted] call bootstrap.Offcanvas.getOrCreateInstance(me).hide()
_="on htmx:afterSettle call Offcanvas.getOrCreateInstance(me).show() end
on hide_offcanvas call Offcanvas.getOrCreateInstance(me).hide() end
on htmx:beforeOnLoad[detail.boosted] call Offcanvas.getOrCreateInstance(me).hide()
on hidden.bs.offcanvas set my innerHTML to '' end">
</div>
<div id="generic-offcanvas-left" class="offcanvas offcanvas-start offcanvas-size-xl z-1100!"
data-bs-backdrop="static"
tabindex="-1"
_="on htmx:afterSettle call bootstrap.Offcanvas.getOrCreateInstance(me).show() end
on hide_offcanvas call bootstrap.Offcanvas.getOrCreateInstance(me).hide() end
on htmx:beforeOnLoad[detail.boosted] call bootstrap.Offcanvas.getOrCreateInstance(me).hide()
_="on htmx:afterSettle call Offcanvas.getOrCreateInstance(me).show() end
on hide_offcanvas call Offcanvas.getOrCreateInstance(me).hide() end
on htmx:beforeOnLoad[detail.boosted] call Offcanvas.getOrCreateInstance(me).hide()
on hidden.bs.offcanvas set my innerHTML to '' end">
</div>

View File

@@ -1,20 +1,13 @@
<script type="text/hyperscript">
def initTooltips(t)
-- Initialize new tooltips
for tooltipTriggerEl in <[data-bs-toggle="tooltip"]/> in t
call bootstrap.Tooltip.getOrCreateInstance(tooltipTriggerEl)
end
end
init
call initTooltips(body)
call initiateTooltips()
end
on htmx:afterSettle
call initTooltips(body)
call initiateTooltips()
end
on tooltips
call initTooltips(body)
call initiateTooltips()
end
</script>

View File

@@ -278,8 +278,7 @@
{% endif %}
<div class="btn-group w-full sidebar-item" role="group">
<button type="button" class="btn btn-secondary btn-sm w-full" data-bs-toggle="tooltip"
data-bs-title="{% trans "Calculator" %}"
<button type="button" class="btn btn-secondary btn-sm w-full" data-tippy-content="{% trans "Calculator" %}"
_="on click trigger show on #calculator">
<i class="fa-solid fa-calculator fa-fw"></i>
</button>

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Installment Plans' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'installment_plan_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>

View File

@@ -25,24 +25,21 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'installment_plan_edit' installment_plan_id=installment_plan.id %}"
hx-swap="innerHTML"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Installments" %}"
data-tippy-content="{% translate "Installments" %}"
hx-get="{% url 'installment_plan_transactions' installment_plan_id=installment_plan.id %}"
hx-swap="innerHTML"
hx-target="#persistent-generic-offcanvas-left">
<i class="fa-solid fa-eye fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-info"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Refresh" %}"
data-tippy-content="{% translate "Refresh" %}"
hx-get="{% url 'installment_plan_refresh' installment_plan_id=installment_plan.id %}"
hx-target="#generic-offcanvas"
hx-trigger='confirmed'
@@ -54,8 +51,7 @@
<i class="fa-solid fa-arrows-rotate fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'installment_plan_delete' installment_plan_id=installment_plan.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"

View File

@@ -3,83 +3,73 @@
{% load formats %}
{% load i18n %}
{% load title %}
<!doctype html>
<!DOCTYPE html>
<html lang="en" data-theme="wygiwyh_dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
{% filter site_title %}
{% block title %}
{% endblock title %}
{% endfilter %}
</title>
{% include 'includes/head/favicons.html' %}
{% progressive_web_app_meta %}
{# {% include 'includes/styles.html' %}#}
{% block extra_styles %}{% endblock %}
{% include 'includes/scripts.html' %}
{% 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 }}"}'>
{% include 'includes/mobile_navbar.html' %}
{% include 'includes/sidebar.html' %}
<main>
{% settings "DEMO" as demo_mode %}
{% if demo_mode %}
<div class="px-3 m-0" id="demo-mode-alert" hx-preserve>
<div class="alert alert-warning my-3" role="alert">
<strong>{% trans 'This is a demo!' %}</strong> {% trans 'Any data you add here will be wiped in 24hrs or less' %}
<button type="button" class="btn btn-sm btn-ghost absolute right-2 top-2" onclick="this.parentElement.style.display='none'" aria-label="Close"></button>
</div>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>
{% filter site_title %}
{% block title %}
{% endblock title %}
{% endfilter %}
</title>
{% include 'includes/head/favicons.html' %}
{% progressive_web_app_meta %}
{# {% include 'includes/styles.html' %}#}
{% block extra_styles %}{% endblock %}
{% include 'includes/scripts.html' %}
{% 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>
{% endif %}
<div id="content">
{% block content %}{% endblock %}
<div _="install hide_amounts install htmx_error_handler
{% block body_hyperscript %}{% endblock %}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
{% include 'includes/mobile_navbar.html' %}
{% include 'includes/sidebar.html' %}
<main class="my-4 px-3">
{% settings "DEMO" as demo_mode %}
{% if demo_mode %}
<div class="px-3 m-0" id="demo-mode-alert" hx-preserve>
<div class="alert alert-warning my-3" role="alert">
<strong>{% trans "This is a demo!" %}</strong> {% trans "Any data you add here will be wiped in 24hrs or less" %}
<button type="button"
class="btn btn-sm btn-ghost absolute right-2 top-2"
onclick="this.parentElement.style.display='none'"
aria-label="Close"></button>
</div>
</div>
{% endif %}
<div id="content">
{% block content %}
{% endblock content %}
</div>
{% include "includes/offcanvas.html" %}
{% include "includes/toasts.html" %}
</main>
</div>
{% include 'includes/offcanvas.html' %}
{% include 'includes/toasts.html' %}
</main>
</div>
{% include 'includes/tools/calculator.html' %}
{% block extra_js_body %}{% endblock %}
</body>
{% include "includes/tools/calculator.html" %}
{% block extra_js_body %}
{% endblock extra_js_body %}
</body>
</html>

View File

@@ -13,9 +13,8 @@
<h5 class="title flex-grow"></h5>
<button class="btn btn-secondary btn-sm text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
_="on click remove the closest .card to me then trigger update on #items then call bootstrap.Tooltip.getOrCreateInstance(me).dispose()">
data-tippy-content="{% translate "Delete" %}"
_="on click remove the closest .card to me then trigger update on #items then trigger tooltips on body">
<i class="fa-solid fa-trash fa-fw"></i>
</button>
</div>
@@ -56,16 +55,14 @@
then
// Remove existing highlight classes from all unit prices
for unitPriceEl in <.unit-price/>
remove .bg-error from the closest .card to unitPriceEl
remove .bg-error from unitPriceEl's classList
remove .bg-success from the closest .card to unitPriceEl
remove .bg-success from unitPriceEl's classList
for unitPriceEl in <*.unit-price/>
remove .bg-error\/20 from the closest .card to unitPriceEl
remove .bg-success\/20 from the closest .card to unitPriceEl
end
// Get all unit prices and find min/max
set unitPrices to <card:not(#card-placeholder) .unit-price/>
set unitPricesAmounts to <.tw:card:not(#card-placeholder) .unit-price/> @data-amount
set unitPrices to <.card:not(#card-placeholder) .unit-price/>
set unitPricesAmounts to <.card:not(#card-placeholder) .unit-price/> @data-amount
js(unitPricesAmounts)
unitPricesAmounts = unitPricesAmounts.filter(element => element !== '0')
return Math.min(...unitPricesAmounts)
@@ -81,12 +78,12 @@
for unitPriceEl in unitPrices
set amount to parseFloat(unitPriceEl.getAttribute('data-amount'))
if amount == minAmount
add .bg-success to the closest .card to unitPriceEl
add .bg-success\/20 to the closest .card to unitPriceEl
add .bg-opacity-20 to the closest .card to unitPriceEl
continue
end
if amount == maxAmount
add .bg-error to the closest .card to unitPriceEl
add .bg-error\/20 to the closest .card to unitPriceEl
add .bg-opacity-20 to the closest .card to unitPriceEl
end
end
@@ -146,13 +143,13 @@
<div class="grid lg:grid-cols-[2fr_1fr] gap-3 mt-3">
<div>
<button class="btn btn-outline btn-primary w-full"
<button class="btn btn-primary w-full"
_="on click
get #card-placeholder
set newCard to it.cloneNode(true)
remove @id from newCard
remove .hidden from newCard then
set itemCount to <#items[class='card'] />'s length
set itemCount to <#items .card />'s length
if itemCount < 26
set letter to String.fromCharCode(65 + itemCount)
else
@@ -160,13 +157,13 @@
end
set newCard.querySelector('.title').innerHTML to `{% trans "Item" %} ${letter}`
put newCard as HTML at the end of #items
trigger tooltips on body
trigger tooltips on body
end">
{% trans 'Add' %}
</button>
</div>
<div>
<button class="btn btn-outline btn-error w-full"
<button class="btn btn-error w-full"
_="on click
for el in <.item-price, .item-amount />
set card to the closest .card to el

View File

@@ -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 text-base 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">
<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" id="c-{{ x.grouper|slugify }}-collapse"
<div class="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

View File

@@ -13,10 +13,10 @@
{% block content %}
<div class="container gap-y-3">
<div class="row ">
<div class="row mt-7 mb-5">
<div class="col-12 lg:col-4">
{# Date picker#}
<div class="col-span-1 xl:col-span-4 flex flex-row items-center">
<div class="flex flex-row items-center">
<div class="text-base h-full flex items-center btn btn-ghost">
<a role="button"
hx-boost="true"

View File

@@ -4,101 +4,121 @@
{% load i18n %}
{% load month_name %}
{% load static %}
{% block title %}{% if type == "current" %}{% translate 'Current Net Worth' %}{% else %}{% translate 'Projected Net Worth' %}{% endif %}{% endblock %}
{% block title %}
{% if type == "current" %}
{% translate "Current Net Worth" %}
{% else %}
{% translate "Projected Net Worth" %}
{% endif %}
{% endblock title %}
{% block content %}
<div hx-trigger="every 60m, updated from:window" hx-include="#view-type" class="show-loading" hx-get=""
<div hx-trigger="every 60m, updated from:window"
hx-include="#view-type"
class="show-loading"
hx-get=""
hx-target="body">
<div class="h-full text-center mb-4 pt-2">
<div class="join" role="group" id="view-type" _="on change trigger updated">
<div class="h-full text-center mb-4 pt-2 w-full">
<div class="tabs tabs-box mx-auto w-fit"
id="view-type"
_="on change trigger updated">
<input type="radio"
class="join-item btn btn-outline btn-primary rounded-full"
name="view_type"
aria-label="{% trans 'Current' %}"
autocomplete="off"
class="tab"
aria-label="{% trans "Current" %}"
value="current"
{% if type == "current" %}checked{% endif %}>
{% if type == "current" %}checked{% endif %} />
<input type="radio"
class="join-item btn btn-outline btn-primary rounded-full"
name="view_type"
aria-label="{% trans 'Projected' %}"
autocomplete="off"
class="tab"
aria-label="{% trans "Projected" %}"
value="projected"
{% if type == "projected" %}checked{% endif %}>
{% if type == "projected" %}checked{% endif %} />
</div>
{% comment %} <div class="gap-3" role="group" id="view-type" _="on change trigger updated">
<input type="radio" class="btn btn-outline btn-primary rounded-full" name="view_type" aria-label="{% trans "Current" %}" autocomplete="off" value="current" {% if type == "current" %}checked{% endif %} />
<i class="fa-solid fa-circle-plus fa-fw"></i>{% trans "Current" %}
</input />
<input type="radio" class="btn btn-outline btn-primary rounded-full" name="view_type" aria-label="{% trans "Projected" %}" autocomplete="off" value="projected" {% if type == "projected" %}checked{% endif %} />
</div> {% endcomment %}
</div>
<div class="container px-md-3 py-3"
_="init call initializeAccountChart() then initializeCurrencyChart() then initializeMonthlyDifferenceChart() end">
<div class="row gap-y-3">
<div class="col lg:col-5">
<div>
<c-ui.info-card color="yellow" icon="fa-solid fa-coins" title="{% trans 'By currency' %}"
title_css_classes="cursor-pointer"
_="on click showAllDatasetsCurrency()">
{% for currency in currency_net_worth.values %}
<div class="flex justify-between mt-2">
<div class="flex items-baseline w-full">
<div class="currency-name text-start font-mono text-base-content cursor-pointer"
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }}')">
{{ currency.currency.name }}
</div>
<div class="dotted-line flex-grow"></div>
<div>
<c-amount.display
:amount="currency.total_final"
:prefix="currency.currency.prefix"
:suffix="currency.currency.suffix"
:decimal_places="currency.currency.decimal_places"
color="{% if currency.total_final > 0 %}green{% elif currency.total_final < 0 %}red{% endif %}"
text-end></c-amount.display>
</div>
</div>
</div>
{% if currency.exchanged and currency.exchanged.total_final %}
<div>
<c-amount.display
:amount="currency.exchanged.total_final"
:prefix="currency.exchanged.currency.prefix"
:suffix="currency.exchanged.currency.suffix"
:decimal_places="currency.exchanged.currency.decimal_places"
text-end
color="grey"></c-amount.display>
</div>
{% endif %}
<div>
<c-ui.info-card color="yellow" icon="fa-solid fa-coins" title="{% trans "By currency" %}" title_css_classes="cursor-pointer" _="on click showAllDatasetsCurrency()">
<ul class="menu bg-base-100 w-full rounded-box">
{% for currency in currency_net_worth.values %}
<li>
{% if currency.consolidated and currency.consolidated.total_final != currency.total_final %}
<div class="flex items-baseline w-full">
<div class="account-name text-start font-mono text-base-content/60">
<span class="hierarchy-line-icon"></span>{% trans 'Consolidated' %}</div>
<div class="dotted-line flex-grow"></div>
<div class="">
<c-amount.display
:amount="currency.consolidated.total_final"
:prefix="currency.consolidated.currency.prefix"
:suffix="currency.consolidated.currency.suffix"
:decimal_places="currency.consolidated.currency.decimal_places"
color="{% if currency.consolidated.total_final > 0 %}green{% elif currency.consolidated.total_final < 0 %}red{% endif %}"
text-end></c-amount.display>
</div>
</div>
<a class="cursor-pointer flex justify-between items-center w-full"
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }}')">
<span class="currency-name text-start font-mono flex-shrink text-ellipsis">{{ currency.currency.name }}</span>
<span class="text-end flex-shrink-0">
<div>
<c-amount.display :amount="currency.total_final" :prefix="currency.currency.prefix" :suffix="currency.currency.suffix" :decimal_places="currency.currency.decimal_places" color="{% if currency.total_final > 0 %}green{% elif currency.total_final < 0 %}red{% endif %}" text-end></c-amount.display>
</div>
{% if currency.exchanged and currency.exchanged.total_final %}
<div>
<c-amount.display :amount="currency.exchanged.total_final" :prefix="currency.exchanged.currency.prefix" :suffix="currency.exchanged.currency.suffix" :decimal_places="currency.exchanged.currency.decimal_places" text-end color="grey"></c-amount.display>
</div>
{% endif %}
</span>
</a>
<ul>
<li>
<a class="text-base-content/60">
<span class="text-start font-mono flex-shrink">{% trans "Consolidated" %}</span>
<span class="text-end flex-shrink-0">
<c-amount.display :amount="currency.consolidated.total_final" :prefix="currency.consolidated.currency.prefix" :suffix="currency.consolidated.currency.suffix" :decimal_places="currency.consolidated.currency.decimal_places" color="{% if currency.consolidated.total_final > 0 %}green{% elif currency.consolidated.total_final < 0 %}red{% endif %}" text-end></c-amount.display>
</span>
</a>
</li>
</ul>
{% else %}
<a class="cursor-pointer flex justify-between items-center w-full"
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }}')">
<span class="currency-name text-start font-mono flex-shrink">{{ currency.currency.name }}</span>
<span class="text-end flex-shrink-0">
<div>
<c-amount.display :amount="currency.total_final" :prefix="currency.currency.prefix" :suffix="currency.currency.suffix" :decimal_places="currency.currency.decimal_places" color="{% if currency.total_final > 0 %}green{% elif currency.total_final < 0 %}red{% endif %}" text-end></c-amount.display>
</div>
{% if currency.exchanged and currency.exchanged.total_final %}
<div>
<c-amount.display :amount="currency.exchanged.total_final" :prefix="currency.exchanged.currency.prefix" :suffix="currency.exchanged.currency.suffix" :decimal_places="currency.exchanged.currency.decimal_places" text-end color="grey"></c-amount.display>
</div>
{% endif %}
</span>
</a>
{% endif %}
{% endfor %}
</c-ui.info-card>
</div>
</li>
{% endfor %}
</ul>
</c-ui.info-card>
</div>
</div>
<div class="col lg:col-7">
<div class="card bg-base-100">
<div class="card-body">
<div role="tablist" class="tabs tabs-border w-full" id="myTab">
<input type="radio" name="networth_tabs" role="tab" class="tab" aria-label="{% trans 'Evolution' %}" id="tab-evolution" checked="checked" />
<input type="radio"
name="networth_tabs"
role="tab"
class="tab"
aria-label="{% trans 'Evolution' %}"
id="tab-evolution"
checked="checked" />
<div role="tabpanel" class="tab-content p-4" id="evolution-tab-pane">
<div class="chart-container relative min-h-[40vh] h-full w-full">
<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 class="chart-container relative min-h-[40vh] h-full w-full">
<canvas id="monthlyDifferenceChart"></canvas>
@@ -109,82 +129,66 @@
</div>
</div>
</div>
<hr class="hr my-6">
<hr class="hr my-6" />
<div class="row gap-y-3">
<div class="col lg:col-5">
<div>
<c-ui.info-card color="blue" icon="fa-solid fa-wallet" title="{% trans 'By account' %}"
title_css_classes="cursor-pointer"
_="on click showAllDatasetsAccount()">
{% regroup account_net_worth.values by account.group as account_data %}
{% for data in account_data %}
{% if data.grouper %}
<div class="flex justify-between mt-2">
<div class="flex items-baseline w-full">
<div class="text-start font-mono text-base-content"><span class="badge badge-primary">
{{ data.grouper }}</span></div>
</div>
</div>
{% for account in data.list %}
<div class="flex justify-between mt-2">
<div class="flex items-baseline w-full">
<div class="account-name text-start font-mono text-base-content cursor-pointer"
<div>
<c-ui.info-card color="blue" icon="fa-solid fa-wallet" title="{% trans "By account" %}" title_css_classes="cursor-pointer" _="on click showAllDatasetsAccount()">
<ul class="menu bg-base-100 w-full rounded-box">
{% regroup account_net_worth.values by account.group as account_data %}
{% for data in account_data %}
{% if data.grouper %}
<li>
<details open>
<summary class="font-mono">
<span class="badge badge-primary">{{ data.grouper }}</span>
</summary>
<ul>
{% for account in data.list %}
<li>
<a class="cursor-pointer flex justify-between items-center w-full"
_="on click showOnlyAccountDataset('{{ account.account.name }}')">
<span class="hierarchy-line-icon"></span>{{ account.account.name }}</div>
<div class="dotted-line flex-grow"></div>
<div class="">
<c-amount.display
:amount="account.total_final"
:prefix="account.currency.prefix"
:suffix="account.currency.suffix"
:decimal_places="account.currency.decimal_places"
color="{% if account.total_final > 0 %}green{% elif account.total_final < 0 %}red{% endif %}"></c-amount.display>
</div>
</div>
</div>
{% if account.exchanged and account.exchanged.total_final %}
<c-amount.display
:amount="account.exchanged.total_final"
:prefix="account.exchanged.currency.prefix"
:suffix="account.exchanged.currency.suffix"
:decimal_places="account.exchanged.currency.decimal_places"
color="grey"
text-end></c-amount.display>
{% endif %}
{% endfor %}
{% else %}
{% for account in data.list %}
<div class="flex justify-between mt-2">
<div class="flex items-baseline w-full">
<div class="account-name text-start font-mono text-base-content cursor-pointer"
_="on click showOnlyAccountDataset('{{ account.account.name }}')">
{{ account.account.name }}
</div>
<div class="dotted-line flex-grow"></div>
<span class="account-name text-start font-mono flex-shrink text-ellipsis">{{ account.account.name }}</span>
<span class="text-end flex-shrink-0">
<div>
<c-amount.display :amount="account.total_final" :prefix="account.currency.prefix" :suffix="account.currency.suffix" :decimal_places="account.currency.decimal_places" color="{% if account.total_final > 0 %}green{% elif account.total_final < 0 %}red{% endif %}"></c-amount.display>
</div>
{% if account.exchanged and account.exchanged.total_final %}
<div>
<c-amount.display :amount="account.exchanged.total_final" :prefix="account.exchanged.currency.prefix" :suffix="account.exchanged.currency.suffix" :decimal_places="account.exchanged.currency.decimal_places" color="grey" text-end></c-amount.display>
</div>
{% endif %}
</span>
</a>
</li>
{% endfor %}
</ul>
</details>
</li>
{% else %}
{% for account in data.list %}
<li>
<a class="cursor-pointer flex justify-between items-center w-full"
_="on click showOnlyAccountDataset('{{ account.account.name }}')">
<span class="account-name text-start font-mono flex-shrink">{{ account.account.name }}</span>
<span class="text-end flex-shrink-0">
<div>
<c-amount.display
:amount="account.total_final"
:prefix="account.currency.prefix"
:suffix="account.currency.suffix"
:decimal_places="account.currency.decimal_places"
color="{% if account.total_final > 0 %}green{% elif account.total_final < 0 %}red{% endif %}"></c-amount.display>
<c-amount.display :amount="account.total_final" :prefix="account.currency.prefix" :suffix="account.currency.suffix" :decimal_places="account.currency.decimal_places" color="{% if account.total_final > 0 %}green{% elif account.total_final < 0 %}red{% endif %}"></c-amount.display>
</div>
</div>
</div>
{% if account.exchanged and account.exchanged.total_final %}
<c-amount.display
:amount="account.exchanged.total_final"
:prefix="account.exchanged.currency.prefix"
:suffix="account.exchanged.currency.suffix"
:decimal_places="account.exchanged.currency.decimal_places"
color="grey"
text-end></c-amount.display>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</c-ui.info-card>
</div>
{% if account.exchanged and account.exchanged.total_final %}
<div>
<c-amount.display :amount="account.exchanged.total_final" :prefix="account.exchanged.currency.prefix" :suffix="account.exchanged.currency.suffix" :decimal_places="account.exchanged.currency.decimal_places" color="grey" text-end></c-amount.display>
</div>
{% endif %}
</span>
</a>
</li>
{% endfor %}
{% endif %}
{% endfor %}
</ul>
</c-ui.info-card>
</div>
</div>
<div class="col lg:col-7">
<div class="chart-container relative min-h-[40vh] h-full card bg-base-100">
@@ -195,7 +199,6 @@
</div>
</div>
</div>
<script>
var currencyChart;
@@ -258,7 +261,6 @@
});
}
</script>
<script id="accountBalanceChartScript">
var accountChart;
@@ -323,7 +325,6 @@
});
}
</script>
<script id="monthlyDifferenceChartScript">
var monthlyDifferenceChart;
@@ -363,7 +364,10 @@
stacked: true,
ticks: {
display: false,
format: {maximumFractionDigits: 40, minimumFractionDigits: 0}
format: {
maximumFractionDigits: 40,
minimumFractionDigits: 0
}
},
}
}
@@ -371,7 +375,6 @@
});
}
</script>
<script type="text/hyperscript">
def showOnlyAccountDataset(datasetName)
for dataset in accountChart.data.datasets
@@ -416,4 +419,4 @@
</script>
</div>
<c-ui.transactions_fab></c-ui.transactions_fab>
{% endblock %}
{% endblock content %}

View File

@@ -22,16 +22,14 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'quick_transaction_edit' quick_transaction_id=qt.id %}"
hx-swap="innerHTML"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'quick_transaction_delete' quick_transaction_id=qt.id %}"
hx-trigger='confirmed'
hx-swap="innerHTML"

View File

@@ -11,8 +11,7 @@
<div>{% translate 'Quick Transactions' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'quick_transaction_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Recurring Transactions' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'recurring_transaction_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>

View File

@@ -27,16 +27,14 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'recurring_transaction_edit' recurring_transaction_id=recurring_transaction.id %}"
hx-swap="innerHTML"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Transactions" %}"
data-tippy-content="{% translate "Transactions" %}"
hx-get="{% url 'recurring_transaction_transactions' recurring_transaction_id=recurring_transaction.id %}"
hx-swap="innerHTML"
hx-target="#persistent-generic-offcanvas-left">
@@ -45,8 +43,7 @@
{% if recurring_transaction.is_paused %}
<a class="btn btn-secondary btn-sm join-item text-info"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Unpause" %}"
data-tippy-content="{% translate "Unpause" %}"
hx-get="{% url 'recurring_transaction_toggle_pause' recurring_transaction_id=recurring_transaction.id %}"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
@@ -59,8 +56,7 @@
{% else %}
<a class="btn btn-secondary btn-sm join-item text-info"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Pause" %}"
data-tippy-content="{% translate "Pause" %}"
hx-get="{% url 'recurring_transaction_toggle_pause' recurring_transaction_id=recurring_transaction.id %}"
hx-target="#generic-offcanvas"
hx-trigger='confirmed'
@@ -74,8 +70,7 @@
{% endif %}
<a class="btn btn-secondary btn-sm join-item text-info"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Finish" %}"
data-tippy-content="{% translate "Finish" %}"
hx-get="{% url 'recurring_transaction_finish' recurring_transaction_id=recurring_transaction.id %}"
hx-target="#generic-offcanvas"
hx-trigger='confirmed'
@@ -89,8 +84,7 @@
{% endif %}
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'recurring_transaction_delete' recurring_transaction_id=recurring_transaction.id %}"
hx-trigger='confirmed'
hx-swap="innerHTML"

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Rules' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'transaction_rule_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
@@ -34,15 +33,13 @@
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "View" %}"
data-tippy-content="{% translate "View" %}"
hx-get="{% url 'transaction_rule_view' transaction_rule_id=rule.id %}"
hx-target="#persistent-generic-offcanvas-left">
<i class="fa-solid fa-eye fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'transaction_rule_delete' transaction_rule_id=rule.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
@@ -53,8 +50,7 @@
{% if not rule.owner %}
<a class="btn btn-secondary btn-sm join-item text-warning"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
data-tippy-content="{% translate "Take ownership" %}"
hx-get="{% url 'transaction_rule_take_ownership' transaction_rule_id=rule.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
@@ -63,8 +59,7 @@
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
data-tippy-content="{% translate "Share" %}"
hx-get="{% url 'transaction_rule_share_settings' pk=rule.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
@@ -73,8 +68,7 @@
<td class="w-auto">
<a class="no-underline"
role="button"
data-bs-toggle="tooltip"
data-bs-title="
data-tippy-content="
{% if rule.active %}{% translate "Deactivate" %}{% else %}{% translate "Activate" %}{% endif %}"
hx-get="{% url 'transaction_rule_toggle_activity' transaction_rule_id=rule.id %}">
{% if rule.active %}<i class="fa-solid fa-toggle-on text-green-400"></i>{% else %}

View File

@@ -19,8 +19,7 @@
<div class="card-footer text-end">
<a class="no-underline text-gray-400 p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'transaction_rule_edit' transaction_rule_id=transaction_rule.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
@@ -49,16 +48,14 @@
<div class="card-footer text-end">
<a class="no-underline text-gray-400 p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Edit' %}"
data-tippy-content="{% translate 'Edit' %}"
hx-get="{% url 'transaction_rule_action_edit' transaction_rule_action_id=action.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i>
</a>
<a class="text-error no-underline p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Delete' %}"
data-tippy-content="{% translate 'Delete' %}"
hx-delete="{% url 'transaction_rule_action_delete' transaction_rule_action_id=action.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
@@ -84,16 +81,14 @@
<div class="card-footer text-end">
<a class="no-underline text-gray-400 p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Edit' %}"
data-tippy-content="{% translate 'Edit' %}"
hx-get="{% url 'update_or_create_transaction_rule_action_edit' pk=action.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i>
</a>
<a class="text-error no-underline p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate 'Delete' %}"
data-tippy-content="{% translate 'Delete' %}"
hx-delete="{% url 'update_or_create_transaction_rule_action_delete' pk=action.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"

View File

@@ -5,8 +5,7 @@
<div>{% translate 'Tags' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'tag_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>

View File

@@ -24,16 +24,14 @@
<a class="btn btn-secondary btn-sm join-item"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'tag_edit' tag_id=tag.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm join-item text-error"
role="button"
data-bs-toggle="tooltip"
hx-swap="innerHTML"
data-bs-title="{% translate "Delete" %}"
data-tippy-content="{% translate "Delete" %}"
hx-delete="{% url 'tag_delete' tag_id=tag.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
@@ -44,8 +42,7 @@
{% if not tag.owner %}
<a class="btn btn-secondary btn-sm join-item text-warning"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
data-tippy-content="{% translate "Take ownership" %}"
hx-get="{% url 'tag_take_ownership' tag_id=tag.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
@@ -54,8 +51,7 @@
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
data-tippy-content="{% translate "Share" %}"
hx-get="{% url 'tag_share_settings' pk=tag.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}

View File

@@ -18,7 +18,7 @@
{{ x.grouper }}
</a>
</div>
<div class="collapse transactions-divider-collapse overflow-visible" id="c-{{ x.grouper|slugify }}-collapse"
<div class="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

View File

@@ -6,8 +6,7 @@
<div>{% translate 'Users' %}<span>
<a class="no-underline text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
data-tippy-content="{% translate "Add" %}"
hx-get="{% url 'user_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
@@ -39,16 +38,14 @@
<a class="btn btn-secondary btn-sm join-item"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
data-tippy-content="{% translate "Edit" %}"
hx-get="{% url 'user_edit' pk=user.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
{% if request.user|can_hijack:user and request.user != user %}
<a class="btn btn-info btn-sm join-item"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Impersonate" %}"
data-tippy-content="{% translate "Impersonate" %}"
hx-post="{% url 'hijack:acquire' %}"
hx-vals='{"user_pk":"{{user.id}}"}'
hx-swap="none"

View File

@@ -31,6 +31,7 @@
"sass": "^1.93.3",
"sweetalert2": "^11.26.3",
"tailwindcss": "^4.1.16",
"tippy.js": "^6.3.7",
"tom-select": "^2.4.3",
"tw-bootstrap-grid": "^1.3.1",
"vite": "7.1.12"
@@ -1574,6 +1575,15 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/tippy.js": {
"version": "6.3.7",
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
"license": "MIT",
"dependencies": {
"@popperjs/core": "^2.9.0"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"license": "MIT",

View File

@@ -38,6 +38,7 @@
"sass": "^1.93.3",
"sweetalert2": "^11.26.3",
"tailwindcss": "^4.1.16",
"tippy.js": "^6.3.7",
"tom-select": "^2.4.3",
"tw-bootstrap-grid": "^1.3.1",
"vite": "7.1.12"

View File

@@ -1,10 +1,16 @@
// Import all of Bootstrap's JS
import * as bootstrap from 'bootstrap'; // eslint-disable-line no-unused-vars
window.bootstrap = bootstrap;
import './js/_tooltip.js';
import 'bootstrap/js/dist/dropdown';
import Toast from 'bootstrap/js/dist/toast';
import 'bootstrap/js/dist/dropdown';
import 'bootstrap/js/dist/collapse';
import Offcanvas from 'bootstrap/js/dist/offcanvas';
window.Offcanvas = Offcanvas;
function initiateToasts() {
const toastElList = document.querySelectorAll('.toasty');
const toastList = [...toastElList].map(toastEl => new bootstrap.Toast(toastEl)); // eslint-disable-line no-undef
const toastList = [...toastElList].map(toastEl => new Toast(toastEl)); // eslint-disable-line no-undef
for (let i = 0; i < toastList.length; i++) {
if (toastList[i].isShown() === false) {

View File

@@ -0,0 +1,21 @@
import tippy from 'tippy.js';
import 'tippy.js/dist/tippy.css';
import 'tippy.js/themes/light-border.css';
function initiateTooltips() {
const currentDataTheme = document.documentElement.getAttribute('data-theme') || '';
let theme;
if (currentDataTheme.endsWith('_dark')) {
theme = 'light-border';
} else if (currentDataTheme.endsWith('_light')) {
theme = 'dark';
}
tippy('[data-tippy-content]', {
theme: theme
});
}
window.initiateTooltips = initiateTooltips;

View File

@@ -4,10 +4,9 @@
// Standalone component implementations
@use "offcanvas";
@use "dropdown";
@use "transitions";
// Bootstrap utilities (if needed)
// @import "bootstrap/scss/bootstrap-utilities";
// Bootstrap-specific utility classes
.dropdown-toggle.dropdown-toggle-no-icon::after {

View File

@@ -0,0 +1,402 @@
// Dropdown component - Standalone implementation
// Decoupled from Bootstrap 5, integrated with DaisyUI colors
@use "sass:list";
@use "sass:map";
// Variables
$dropdown-min-width: 10rem !default;
$dropdown-padding-x: 0.5rem !default;
$dropdown-padding-y: 0.5rem !default;
$dropdown-spacer: 0.125rem !default;
$dropdown-font-size: 1rem !default;
$dropdown-border-radius: 0.375rem !default;
$dropdown-border-width: 1px !default;
$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default;
$dropdown-divider-margin-y: 0.5rem !default;
$dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !default;
$dropdown-item-padding-y: 0.25rem !default;
$dropdown-item-padding-x: 1rem !default;
$dropdown-header-padding-x: 1rem !default;
$dropdown-header-padding-y: 0.5rem !default;
$dropdown-z-index: 1000 !default;
// Caret variables
$caret-width: 0.3em !default;
$caret-vertical-align: 0.255em !default;
$caret-spacing: 0.255em !default;
$enable-caret: true !default;
// Font
$font-weight-normal: 400 !default;
$font-size-sm: 0.875rem !default;
// Breakpoints
$breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px) !default;
// Mixins
@mixin media-breakpoint-up($name) {
$min: map.get($breakpoints, $name
);
@if $min and $min >0 {
@media (min-width: $min) {
@content;
}
}
@else {
@content;
}
}
// Caret mixins
@mixin caret-down($width: $caret-width) {
border-top: $width solid;
border-right: $width solid transparent;
border-bottom: 0;
border-left: $width solid transparent;
}
@mixin caret-up($width: $caret-width) {
border-top: 0;
border-right: $width solid transparent;
border-bottom: $width solid;
border-left: $width solid transparent;
}
@mixin caret-end($width: $caret-width) {
border-top: $width solid transparent;
border-right: 0;
border-bottom: $width solid transparent;
border-left: $width solid;
}
@mixin caret-start($width: $caret-width) {
border-top: $width solid transparent;
border-right: $width solid;
border-bottom: $width solid transparent;
}
@mixin caret($direction: down,
$width: $caret-width,
$spacing: $caret-spacing,
$vertical-align: $caret-vertical-align) {
@if $enable-caret {
&::after {
display: inline-block;
margin-left: $spacing;
vertical-align: $vertical-align;
content: "";
@if $direction ==down {
@include caret-down($width);
}
@else if $direction ==up {
@include caret-up($width);
}
@else if $direction ==end {
@include caret-end($width);
}
}
@if $direction ==start {
&::after {
display: none;
}
&::before {
display: inline-block;
margin-right: $spacing;
vertical-align: $vertical-align;
content: "";
@include caret-start($width);
}
}
&:empty::after {
margin-left: 0;
}
}
}
@mixin border-radius($radius: $dropdown-border-radius) {
border-radius: $radius;
}
@mixin border-top-radius($radius) {
border-top-left-radius: $radius;
border-top-right-radius: $radius;
}
@mixin border-bottom-radius($radius) {
border-bottom-left-radius: $radius;
border-bottom-right-radius: $radius;
}
@mixin gradient-bg($color) {
background-color: $color;
}
@mixin box-shadow($shadow) {
box-shadow: $shadow;
}
@mixin font-size($size) {
font-size: $size;
}
// Breakpoint infix function
@function breakpoint-infix($name, $breakpoints) {
@if $name ==xs {
@return "";
}
@return "-#{$name}";
}
// The dropdown wrapper (`<div>`)
.dropup,
.dropend,
.dropdown,
.dropstart,
.dropup-center,
.dropdown-center {
position: relative;
}
.dropdown-toggle {
white-space: nowrap;
// Generate the caret automatically
@include caret();
}
// The dropdown menu
.dropdown-menu {
// CSS variables using DaisyUI colors
--dropdown-z-index: #{$dropdown-z-index};
--dropdown-min-width: #{$dropdown-min-width};
--dropdown-padding-x: #{$dropdown-padding-x};
--dropdown-padding-y: #{$dropdown-padding-y};
--dropdown-spacer: #{$dropdown-spacer};
--dropdown-font-size: #{$dropdown-font-size};
--dropdown-color: var(--color-base-content);
--dropdown-bg: var(--color-base-300);
--dropdown-border-color: var(--color-base-300);
--dropdown-border-radius: #{$dropdown-border-radius};
--dropdown-border-width: #{$dropdown-border-width};
--dropdown-inner-border-radius: #{$dropdown-inner-border-radius};
--dropdown-divider-bg: var(--color-base-300);
--dropdown-divider-margin-y: #{$dropdown-divider-margin-y};
--dropdown-box-shadow: #{$dropdown-box-shadow};
--dropdown-link-color: var(--color-base-content);
--dropdown-link-hover-color: var(--color-base-content);
--dropdown-link-hover-bg: var(--color-base-200);
--dropdown-link-active-color: var(--color-primary-content);
--dropdown-link-active-bg: var(--color-primary);
--dropdown-link-disabled-color: var(--color-base-content, #adb5bd);
--dropdown-item-padding-x: #{$dropdown-item-padding-x};
--dropdown-item-padding-y: #{$dropdown-item-padding-y};
--dropdown-header-color: var(--color-base-content);
--dropdown-header-padding-x: #{$dropdown-header-padding-x};
--dropdown-header-padding-y: #{$dropdown-header-padding-y};
position: absolute;
z-index: var(--dropdown-z-index);
display: none; // none by default, but block on "open" of the menu
min-width: var(--dropdown-min-width);
padding: var(--dropdown-padding-y) var(--dropdown-padding-x);
margin: 0; // Override default margin of ul
color: var(--dropdown-color);
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
list-style: none;
background-color: var(--dropdown-bg);
background-clip: padding-box;
border: var(--dropdown-border-width) solid var(--dropdown-border-color);
@include border-radius(var(--dropdown-border-radius));
@include box-shadow(var(--dropdown-box-shadow));
&[data-bs-popper] {
top: 100%;
left: 0;
margin-top: var(--dropdown-spacer);
}
@if $dropdown-padding-y ==0 {
>.dropdown-item:first-child,
>li:first-child .dropdown-item {
@include border-top-radius(var(--dropdown-inner-border-radius));
}
>.dropdown-item:last-child,
>li:last-child .dropdown-item {
@include border-bottom-radius(var(--dropdown-inner-border-radius));
}
}
}
// Responsive positioning
@each $breakpoint in map.keys($breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $breakpoints);
.dropdown-menu#{$infix}-start {
--bs-position: start;
&[data-bs-popper] {
right: auto;
left: 0;
}
}
.dropdown-menu#{$infix}-end {
--bs-position: end;
&[data-bs-popper] {
right: 0;
left: auto;
}
}
}
}
// Allow for dropdowns to go bottom up (aka, dropup-menu)
.dropup {
.dropdown-menu[data-bs-popper] {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: var(--dropdown-spacer);
}
.dropdown-toggle {
@include caret(up);
}
}
.dropend {
.dropdown-menu[data-bs-popper] {
top: 0;
right: auto;
left: 100%;
margin-top: 0;
margin-left: var(--dropdown-spacer);
}
.dropdown-toggle {
@include caret(end);
&::after {
vertical-align: 0;
}
}
}
.dropstart {
.dropdown-menu[data-bs-popper] {
top: 0;
right: 100%;
left: auto;
margin-top: 0;
margin-right: var(--dropdown-spacer);
}
.dropdown-toggle {
@include caret(start);
&::before {
vertical-align: 0;
}
}
}
// Dividers (basically an `<hr>`) within the dropdown
.dropdown-divider {
height: 0;
margin: var(--dropdown-divider-margin-y) 0;
overflow: hidden;
border-top: 1px solid var(--dropdown-divider-bg);
opacity: 1;
}
// Links, buttons, and more within the dropdown menu
.dropdown-item {
display: block;
width: 100%; // For `<button>`s
padding: var(--dropdown-item-padding-y) var(--dropdown-item-padding-x);
clear: both;
font-weight: $font-weight-normal;
color: var(--dropdown-link-color);
text-align: inherit; // For `<button>`s
text-decoration: none;
white-space: nowrap; // prevent links from randomly breaking onto new lines
background-color: transparent; // For `<button>`s
border: 0; // For `<button>`s
@include border-radius(0);
&:hover,
&:focus {
color: var(--dropdown-link-hover-color);
@include gradient-bg(var(--dropdown-link-hover-bg));
}
&.active,
&:active {
color: var(--dropdown-link-active-color);
text-decoration: none;
@include gradient-bg(var(--dropdown-link-active-bg));
}
&.disabled,
&:disabled {
color: var(--dropdown-link-disabled-color);
pointer-events: none;
background-color: transparent;
}
}
.dropdown-menu.show {
display: block;
}
// Dropdown section headers
.dropdown-header {
display: block;
padding: var(--dropdown-header-padding-y) var(--dropdown-header-padding-x);
margin-bottom: 0; // for use with heading elements
color: var(--dropdown-header-color);
white-space: nowrap; // as with > li > a
}
// Dropdown text
.dropdown-item-text {
display: block;
padding: var(--dropdown-item-padding-y) var(--dropdown-item-padding-x);
color: var(--dropdown-link-color);
}
// Dark dropdowns
.dropdown-menu-dark {
--dropdown-color: #dee2e6;
--dropdown-bg: #343a40;
--dropdown-border-color: var(--color-base-300);
--dropdown-box-shadow: #{$dropdown-box-shadow};
--dropdown-link-color: #dee2e6;
--dropdown-link-hover-color: #fff;
--dropdown-divider-bg: var(--color-base-300);
--dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);
--dropdown-link-active-color: var(--color-primary-content);
--dropdown-link-active-bg: var(--color-primary);
--dropdown-link-disabled-color: #adb5bd;
--dropdown-header-color: #adb5bd;
}