mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-01-11 20:00:26 +01:00
feat: more changes and fixes
This commit is contained in:
@@ -3,7 +3,6 @@ from decimal import Decimal
|
||||
from django import template
|
||||
from django.utils.formats import number_format
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@@ -13,13 +12,24 @@ def _format_string(prefix, amount, decimal_places, suffix):
|
||||
value=abs(amount), decimal_pos=decimal_places, force_grouping=True
|
||||
)
|
||||
if amount < 0:
|
||||
return "-", prefix, formatted_amount, suffix
|
||||
return f"-{prefix}{formatted_amount}{suffix}"
|
||||
else:
|
||||
return "", prefix, formatted_amount, suffix
|
||||
return f"{prefix}{formatted_amount}{suffix}"
|
||||
else:
|
||||
return "ERR"
|
||||
return "", "", "ERR", ""
|
||||
|
||||
|
||||
@register.simple_tag(name="currency_display")
|
||||
def currency_display(amount, prefix, suffix, decimal_places):
|
||||
return _format_string(prefix, amount, decimal_places, suffix)
|
||||
sign, prefix, amount, suffix = _format_string(
|
||||
prefix, amount, decimal_places, suffix
|
||||
)
|
||||
|
||||
return {
|
||||
"sign": sign,
|
||||
"prefix": prefix,
|
||||
"amount": amount,
|
||||
"suffix": suffix,
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
{% load currency_display %}
|
||||
|
||||
{% currency_display amount=amount prefix=prefix suffix=suffix decimal_places=decimal_places as formatted_amount %}
|
||||
|
||||
{% if not divless %}
|
||||
<div class="{% if text_end %}text-end{% elif text_start %}text-start{% endif %}">
|
||||
{% endif %}
|
||||
<span class="amount{% if color == 'grey' or color == "gray" %} text-exchange-rate{% elif color == 'green' %} text-income {% elif color == 'red' %} text-expense{% endif %} font-medium {{ custom_class }}"
|
||||
data-original-value="{% currency_display amount=amount prefix=prefix suffix=suffix decimal_places=decimal_places %}"
|
||||
data-original-sign="{{ formatted_amount.sign }}"
|
||||
data-original-prefix="{{ formatted_amount.prefix }}"
|
||||
data-original-amount="{{ formatted_amount.amount }}"
|
||||
data-original-suffix="{{ formatted_amount.suffix }}"
|
||||
data-amount="{{ amount|floatformat:"-40u" }}">
|
||||
</span><span>{{ slot }}</span>
|
||||
{% if not divless %}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="text-center">
|
||||
<i class="{% if icon %}{{ icon }}{% else %}fa-solid fa-circle-xmark{% endif %} text-6xl"></i>
|
||||
<p class="text-lg mt-4 mb-0">{{ title }}</p>
|
||||
<p class="text-gray-500">{{ subtitle }}</p>
|
||||
<p class="text-subtle">{{ subtitle }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% load markdown %}
|
||||
{% load i18n %}
|
||||
<div
|
||||
class="transaction {% if transaction.type == "EX" %}expense{% else %}income{% endif %} group/transaction relative group-hover/transaction:z-50 hover:z-50">
|
||||
class="transaction {% if transaction.type == "EX" %}expense{% else %}income{% endif %} group/transaction relative">
|
||||
<div class="flex my-1">
|
||||
{% if not disable_selection or not dummy %}
|
||||
<label class="px-3 flex! items-center justify-center">
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="flex flex-wrap font-mono text-sm items-center">
|
||||
<div class="lg:w-auto w-full flex items-center text-2xl lg:text-xl lg:text-center text-center p-0 cursor-pointer">
|
||||
{% if not transaction.deleted %}
|
||||
<a class="no-underline p-3 text-gray-500!"
|
||||
<a class="no-underline p-3 text-base-content/50"
|
||||
title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}"
|
||||
role="button"
|
||||
{% if not dummy %}
|
||||
@@ -27,7 +27,7 @@
|
||||
class="fa-regular fa-circle"></i>{% endif %}
|
||||
</a>
|
||||
{% else %}
|
||||
<div class="no-underline p-3 text-gray-500!"
|
||||
<div class="no-underline p-3 text-base-content/50"
|
||||
title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}">
|
||||
{% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i
|
||||
class="fa-regular fa-circle"></i>{% endif %}
|
||||
@@ -138,16 +138,16 @@
|
||||
<div class="z-1000">
|
||||
{# Item actions#}
|
||||
<div
|
||||
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">
|
||||
class="card card-border-base-100 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-200">
|
||||
<div class="card-body p-1 shadow-lg flex flex-row gap-1">
|
||||
{% if not transaction.deleted %}
|
||||
<a class="btn btn-neutral btn-sm transaction-action"
|
||||
<a class="btn btn-soft 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"
|
||||
<a class="btn btn-error btn-soft btn-sm transaction-action"
|
||||
role="button"
|
||||
hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}"
|
||||
hx-trigger='confirmed'
|
||||
@@ -156,32 +156,32 @@
|
||||
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>
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i>
|
||||
</a>
|
||||
<button class="btn btn-neutral btn-sm transaction-action" data-bs-toggle="dropdown" data-bs-container="body" aria-expanded="false">
|
||||
<button class="btn btn-soft 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 class="dropdown-menu dropdown-menu-end dropdown-menu-md-start menu w-max relative">
|
||||
<div class="absolute inset-[0rem_-3rem_-3rem_-3rem] pointer-events-auto -z-10"></div>
|
||||
{% if transaction.account.is_untracked_by %}
|
||||
<li>
|
||||
<a class="disabled flex items-center" aria-disabled="true">
|
||||
<li class="menu-disabled" aria-disabled="true">
|
||||
<a class="flex items-center">
|
||||
<i class="fa-solid fa-eye fa-fw mr-2"></i>
|
||||
<div>
|
||||
{% translate 'Show on summaries' %}
|
||||
<div
|
||||
class="block text-gray-500 text-xs font-medium">{% translate 'Controlled by account' %}</div>
|
||||
class="block text-base-content/60 text-xs font-medium">{% translate 'Controlled by account' %}</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{% elif transaction.category.mute %}
|
||||
<li>
|
||||
<a class="disabled flex items-center" aria-disabled="true">
|
||||
<li class="menu-disabled" aria-disabled="true">
|
||||
<a class="flex items-center">
|
||||
<i class="fa-solid fa-eye fa-fw mr-2"></i>
|
||||
<div>
|
||||
{% translate 'Show on summaries' %}
|
||||
<div
|
||||
class="block text-gray-500 text-xs font-medium">{% translate 'Controlled by category' %}</div>
|
||||
class="block text-base-content/60 text-xs font-medium">{% translate 'Controlled by category' %}</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -218,13 +218,13 @@
|
||||
</ul>
|
||||
{% else %}
|
||||
<div class="tooltip" data-tippy-content="{% translate "Restore" %}">
|
||||
<a class="btn btn-secondary btn-sm transaction-action"
|
||||
<a class="btn btn-success btn-soft btn-sm transaction-action"
|
||||
role="button"
|
||||
hx-get="{% url 'transaction_undelete' transaction_id=transaction.id %}"><i
|
||||
class="fa-solid fa-trash-arrow-up"></i></a>
|
||||
</div>
|
||||
<div class="tooltip" data-tippy-content="{% translate "Delete" %}">
|
||||
<a class="btn btn-secondary btn-sm transaction-action"
|
||||
<a class="btn btn-error btn-soft btn-sm transaction-action"
|
||||
role="button"
|
||||
hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}"
|
||||
hx-trigger='confirmed'
|
||||
|
||||
@@ -2,204 +2,165 @@
|
||||
{% load i18n %}
|
||||
<div class="card bg-base-100 shadow-md card-border border-base-300">
|
||||
<div class="card-body">
|
||||
{% if account.account.group %}
|
||||
<div class="text-sm mb-2">
|
||||
<span class="badge badge-primary">{{ account.account.group }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<h5 class="card-title">
|
||||
{{ account.account.name }}
|
||||
<h5 class="card-title mb-4">
|
||||
{% if account.account.group %}<span class="badge badge-primary badge-outline">{{ account.account.group }}</span>{% endif %} {{ account.account.name }}
|
||||
</h5>
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end ">
|
||||
<div class="text-subtle">{% translate 'projected income' %}</div>
|
||||
<div class="card-data-section">
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'projected income' %}</span>
|
||||
<div class="card-data-values">
|
||||
{% if account.income_projected != 0 %}
|
||||
<c-amount.display
|
||||
:amount="account.income_projected"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
{% if account.exchanged and account.exchanged.income_projected %}
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.income_projected"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="font-semibold">-</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
{% if account.income_projected != 0 %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.income_projected"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'projected expenses' %}</span>
|
||||
<div class="card-data-values">
|
||||
{% if account.expense_projected != 0 %}
|
||||
<c-amount.display
|
||||
:amount="account.expense_projected"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
{% if account.exchanged and account.exchanged.expense_projected %}
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.expense_projected"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="font-semibold">-</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-end ">-</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if account.exchanged and account.exchanged.income_projected %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.income_projected"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end ">
|
||||
<div class="text-subtle">{% translate 'projected expenses' %}</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
<div>
|
||||
{% if account.expense_projected != 0 %}
|
||||
<div class="text-end">
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'projected total' %}</span>
|
||||
<div class="card-data-values">
|
||||
<c-amount.display
|
||||
:amount="account.expense_projected"
|
||||
:amount="account.total_projected"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
color="{% if account.total_projected > 0 %}green{% elif account.total_projected < 0 %}red{% endif %}"></c-amount.display>
|
||||
{% if account.exchanged.total_projected and account.exchanged.total_projected %}
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.total_projected"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-end ">-</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if account.exchanged and account.exchanged.expense_projected %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.expense_projected"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end ">
|
||||
<div class="text-subtle">{% translate 'projected total' %}</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
<div
|
||||
class="text-end ">
|
||||
<c-amount.display
|
||||
:amount="account.total_projected"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="{% if account.total_projected > 0 %}green{% elif account.total_projected < 0 %}red{% endif %}"></c-amount.display>
|
||||
</div>
|
||||
</div>
|
||||
{% if account.exchanged.total_projected and account.exchanged.total_projected %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.total_projected"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr class="my-3">
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end ">
|
||||
<div class="text-subtle">{% translate 'current income' %}</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
{% if account.income_current != 0 %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.income_current"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-end ">-</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if account.exchanged and account.exchanged.income_current %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.income_current"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end ">
|
||||
<div class="text-subtle">{% translate 'current expenses' %}</div>
|
||||
</div>
|
||||
<div class="dotted-line"></div>
|
||||
{% if account.expense_current != 0 %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.expense_current"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-end ">-</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if account.exchanged and account.exchanged.expense_current %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.expense_current"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end ">
|
||||
<div class="text-subtle">{% translate 'current total' %}</div>
|
||||
</div>
|
||||
<div class="dotted-linegrow"></div>
|
||||
<div class="text-end ">
|
||||
<c-amount.display
|
||||
:amount="account.total_current"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="{% if account.total_current > 0 %}green{% elif account.total_current < 0 %}red{% endif %}"></c-amount.display>
|
||||
</div>
|
||||
</div>
|
||||
{% if account.exchanged and account.exchanged.total_current %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.total_current"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<hr class="my-3">
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end ">
|
||||
<div class="text-subtle">{% translate 'final total' %}</div>
|
||||
<hr class="card-data-divider" />
|
||||
<div class="card-data-section">
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'current income' %}</span>
|
||||
<div class="card-data-values">
|
||||
{% if account.income_current != 0 %}
|
||||
<c-amount.display
|
||||
:amount="account.income_current"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
{% if account.exchanged and account.exchanged.income_current %}
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.income_current"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="font-semibold">-</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
<div class="text-end ">
|
||||
</div>
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'current expenses' %}</span>
|
||||
<div class="card-data-values">
|
||||
{% if account.expense_current != 0 %}
|
||||
<c-amount.display
|
||||
:amount="account.expense_current"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
{% if account.exchanged and account.exchanged.expense_current %}
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.expense_current"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="font-semibold">-</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'current total' %}</span>
|
||||
<div class="card-data-values">
|
||||
<c-amount.display
|
||||
:amount="account.total_current"
|
||||
:prefix="account.currency.prefix"
|
||||
:suffix="account.currency.suffix"
|
||||
:decimal_places="account.currency.decimal_places"
|
||||
color="{% if account.total_current > 0 %}green{% elif account.total_current < 0 %}red{% endif %}"></c-amount.display>
|
||||
{% if account.exchanged and account.exchanged.total_current %}
|
||||
<c-amount.display
|
||||
:amount="account.exchanged.total_current"
|
||||
:prefix="account.exchanged.currency.prefix"
|
||||
:suffix="account.exchanged.currency.suffix"
|
||||
:decimal_places="account.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="card-data-divider" />
|
||||
<div class="card-data-section">
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'final total' %}</span>
|
||||
<div class="card-data-values">
|
||||
<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>
|
||||
{% 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="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if account.exchanged and account.exchanged.total_final %}
|
||||
<div class="text-end">
|
||||
<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="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% with p=percentages|get_dict_item:account_id %}
|
||||
<div class="my-3">
|
||||
|
||||
@@ -2,198 +2,165 @@
|
||||
{% load i18n %}
|
||||
<div class="col card bg-base-100 shadow card-border">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<h5 class="card-title mb-4">
|
||||
{{ currency.currency.name }}
|
||||
</h5>
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end">
|
||||
<div class="text-subtle">{% translate 'projected income' %}</div>
|
||||
<div class="card-data-section">
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'projected income' %}</span>
|
||||
<div class="card-data-values">
|
||||
{% if currency.income_projected != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.income_projected"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
{% if currency.exchanged and currency.exchanged.income_projected %}
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.income_projected"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="font-semibold">-</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
{% if currency.income_projected != 0 %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.income_projected"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'projected expenses' %}</span>
|
||||
<div class="card-data-values">
|
||||
{% if currency.expense_projected != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.expense_projected"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
{% if currency.exchanged and currency.exchanged.expense_projected %}
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.expense_projected"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="font-semibold">-</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-end">-</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if currency.exchanged and currency.exchanged.income_projected %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.income_projected"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end">
|
||||
<div class="text-subtle">{% translate 'projected expenses' %}</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
<div>
|
||||
{% if currency.expense_projected != 0 %}
|
||||
<div class="text-end">
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'projected total' %}</span>
|
||||
<div class="card-data-values">
|
||||
<c-amount.display
|
||||
:amount="currency.expense_projected"
|
||||
:amount="currency.total_projected"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
color="{% if currency.total_projected > 0 %}green{% elif currency.total_projected < 0 %}red{% endif %}"></c-amount.display>
|
||||
{% if currency.exchanged.total_projected and currency.exchanged.total_projected %}
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.total_projected"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-end">-</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if currency.exchanged and currency.exchanged.expense_projected %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.expense_projected"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end">
|
||||
<div class="text-subtle">{% translate 'projected total' %}</div>
|
||||
</div>
|
||||
<div class="dotted-linegrow"></div>
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.total_projected"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="{% if currency.total_projected > 0 %}green{% elif currency.total_projected < 0 %}red{% endif %}"></c-amount.display>
|
||||
</div>
|
||||
</div>
|
||||
{% if currency.exchanged.total_projected and currency.exchanged.total_projected %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.total_projected"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr class="my-3 hr">
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end">
|
||||
<div class="text-subtle">{% translate 'current income' %}</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
{% if currency.income_current != 0 %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.income_current"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-end">-</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if currency.exchanged and currency.exchanged.income_current %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.income_current"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end">
|
||||
<div class="text-subtle">{% translate 'current expenses' %}</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
{% if currency.expense_current != 0 %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.expense_current"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-end">-</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if currency.exchanged and currency.exchanged.expense_current %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.expense_current"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end">
|
||||
<div class="text-subtle">{% translate 'current total' %}</div>
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.total_current"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="{% if currency.total_current > 0 %}green{% elif currency.total_current < 0 %}red{% endif %}"></c-amount.display>
|
||||
</div>
|
||||
</div>
|
||||
{% if currency.exchanged and currency.exchanged.total_current %}
|
||||
<div class="text-end">
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.total_current"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<hr class="my-3 hr">
|
||||
<div class="flex justify-between items-baseline mt-2">
|
||||
<div class="text-end">
|
||||
<div class="text-subtle">{% translate 'final total' %}</div>
|
||||
<hr class="card-data-divider" />
|
||||
<div class="card-data-section">
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'current income' %}</span>
|
||||
<div class="card-data-values">
|
||||
{% if currency.income_current != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.income_current"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
{% if currency.exchanged and currency.exchanged.income_current %}
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.income_current"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="font-semibold">-</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="dotted-line grow"></div>
|
||||
<div class="text-end">
|
||||
</div>
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'current expenses' %}</span>
|
||||
<div class="card-data-values">
|
||||
{% if currency.expense_current != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.expense_current"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
{% if currency.exchanged and currency.exchanged.expense_current %}
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.expense_current"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="font-semibold">-</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'current total' %}</span>
|
||||
<div class="card-data-values">
|
||||
<c-amount.display
|
||||
:amount="currency.total_current"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="{% if currency.total_current > 0 %}green{% elif currency.total_current < 0 %}red{% endif %}"></c-amount.display>
|
||||
{% if currency.exchanged and currency.exchanged.total_current %}
|
||||
<c-amount.display
|
||||
:amount="currency.exchanged.total_current"
|
||||
:prefix="currency.exchanged.currency.prefix"
|
||||
:suffix="currency.exchanged.currency.suffix"
|
||||
:decimal_places="currency.exchanged.currency.decimal_places"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="card-data-divider" />
|
||||
<div class="card-data-section">
|
||||
<div class="card-data-row">
|
||||
<span class="card-data-label">{% translate 'final total' %}</span>
|
||||
<div class="card-data-values">
|
||||
<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 %}"></c-amount.display>
|
||||
{% if currency.exchanged and currency.exchanged.total_final %}
|
||||
<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"
|
||||
color="gray"></c-amount.display>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if currency.exchanged and currency.exchanged.total_final %}
|
||||
<div class="text-end">
|
||||
<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"
|
||||
color="gray"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% with p=percentages|get_dict_item:currency_id %}
|
||||
<div class="my-3">
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
data-tippy-content="{% translate 'Duplicate' %}">
|
||||
<i class="fa-solid fa-clone fa-fw"></i>
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
<button class="btn btn-error btn-sm"
|
||||
hx-get="{% url 'transactions_bulk_delete' %}"
|
||||
hx-include=".transaction"
|
||||
hx-trigger="confirmed"
|
||||
@@ -90,7 +90,7 @@
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete them!" %}"
|
||||
_="install prompt_swal">
|
||||
<i class="fa-solid fa-trash text-error"></i>
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
<div class="divider divider-horizontal m-0"></div>
|
||||
<div class="join"
|
||||
@@ -139,7 +139,7 @@
|
||||
wait 1s
|
||||
put original_value into #real-total-front's innerText
|
||||
end">
|
||||
<i class="fa-solid fa-plus fa-fw me-md-2 text-primary"></i>
|
||||
<i class="fa-solid fa-plus fa-fw me-md-2"></i>
|
||||
<span class="hidden md:inline-block" id="real-total-front">0</span>
|
||||
</button>
|
||||
<div class="dropdown dropdown-end dropdown-top">
|
||||
@@ -147,7 +147,7 @@
|
||||
<i class="fa-solid fa-chevron-down fa-xs"></i>
|
||||
</button>
|
||||
|
||||
<ul tabindex="0" class="dropdown-content menu bg-base-300 rounded-box z-[1] w-full shadow fixed!">
|
||||
<ul tabindex="0" class="dropdown-content menu bg-base-300 rounded-box w-full shadow fixed! flex flex-col gap-1">
|
||||
<li class="cursor-pointer"
|
||||
_="on click
|
||||
set original_value to #calc-menu-flat-total's innerText
|
||||
@@ -156,13 +156,12 @@
|
||||
wait 1s
|
||||
put original_value into #calc-menu-flat-total
|
||||
end">
|
||||
<div class="p-0">
|
||||
<div class="py-1 px-3">
|
||||
<div>
|
||||
<div class="text-base-content/60 text-xs font-medium px-3">
|
||||
<div class="text-base-content/60 text-xs font-medium">
|
||||
{% trans "Flat Total" %}
|
||||
</div>
|
||||
<div class="px-3"
|
||||
id="calc-menu-flat-total">
|
||||
<div id="calc-menu-flat-total">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
@@ -176,13 +175,12 @@
|
||||
wait 1s
|
||||
put original_value into #calc-menu-real-total
|
||||
end">
|
||||
<div class="p-0">
|
||||
<div class="py-1 px-3">
|
||||
<div>
|
||||
<div class="text-base-content/60 text-xs font-medium px-3">
|
||||
<div class="text-base-content/60 text-xs font-medium">
|
||||
{% trans "Real Total" %}
|
||||
</div>
|
||||
<div class="px-3"
|
||||
id="calc-menu-real-total">
|
||||
<div id="calc-menu-real-total">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,13 +194,12 @@
|
||||
wait 1s
|
||||
put original_value into #calc-menu-mean
|
||||
end">
|
||||
<div class="p-0">
|
||||
<div class="p-1 px-3">
|
||||
<div>
|
||||
<div class="text-base-content/60 text-xs font-medium px-3">
|
||||
<div class="text-base-content/60 text-xs font-medium">
|
||||
{% trans "Mean" %}
|
||||
</div>
|
||||
<div class="px-3"
|
||||
id="calc-menu-mean">
|
||||
<div id="calc-menu-mean">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
@@ -216,13 +213,12 @@
|
||||
wait 1s
|
||||
put original_value into #calc-menu-max
|
||||
end">
|
||||
<div class="p-0">
|
||||
<div class="py-1 px-3">
|
||||
<div>
|
||||
<div class="text-base-content/60 text-xs font-medium px-3">
|
||||
<div class="text-base-content/60 text-xs font-medium">
|
||||
{% trans "Max" %}
|
||||
</div>
|
||||
<div class="px-3"
|
||||
id="calc-menu-max">
|
||||
<div id="calc-menu-max">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
@@ -236,13 +232,12 @@
|
||||
wait 1s
|
||||
put original_value into #calc-menu-min
|
||||
end">
|
||||
<div class="p-0">
|
||||
<div class="py-1 px-3">
|
||||
<div>
|
||||
<div class="text-base-content/60 text-xs font-medium px-3">
|
||||
<div class="text-base-content/60 text-xs font-medium">
|
||||
{% trans "Min" %}
|
||||
</div>
|
||||
<div class="px-3"
|
||||
id="calc-menu-min">
|
||||
<div id="calc-menu-min">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
@@ -256,13 +251,12 @@
|
||||
wait 1s
|
||||
put original_value into #calc-menu-count
|
||||
end">
|
||||
<div class="p-0">
|
||||
<div class="py-1 px-3">
|
||||
<div>
|
||||
<div class="text-base-content/60 text-xs font-medium px-3">
|
||||
<div class="text-base-content/60 text-xs font-medium">
|
||||
{% trans "Count" %}
|
||||
</div>
|
||||
<div class="px-3"
|
||||
id="calc-menu-count">
|
||||
<div id="calc-menu-count">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
{% vite_hmr_client %}
|
||||
|
||||
{% vite_asset 'bootstrap.js' defer=True %}
|
||||
{% vite_asset 'sweetalert2.js' defer=True %}
|
||||
{% vite_asset 'main.js' defer=True %}
|
||||
{% comment %} {% vite_asset 'sweetalert2.js' defer=True %}
|
||||
{% vite_asset 'select.js' defer=True %}
|
||||
{% vite_asset 'datepicker.js' %}
|
||||
{% vite_asset 'autosize.js' defer=True %}
|
||||
{% vite_asset 'autosize.js' defer=True %} {% endcomment %}
|
||||
|
||||
{% include 'includes/scripts/hyperscript/init_tom_select.html' %}
|
||||
{% include 'includes/scripts/hyperscript/init_date_picker.html' %}
|
||||
@@ -16,10 +16,10 @@
|
||||
{% include 'includes/scripts/hyperscript/sounds.html' %}
|
||||
{% include 'includes/scripts/hyperscript/swal.html' %}
|
||||
|
||||
{% vite_asset 'htmx.js' defer=True %}
|
||||
{% comment %} {% vite_asset 'htmx.js' defer=True %}
|
||||
{% vite_asset 'charts.js' %}
|
||||
|
||||
{% vite_asset 'style.js' %}
|
||||
{% vite_asset 'style.js' %} {% endcomment %}
|
||||
|
||||
<script>
|
||||
let tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
@@ -11,13 +11,22 @@
|
||||
set elements to <.amount/> in me
|
||||
for el in elements
|
||||
set el.textContent to el.dataset.originalValue
|
||||
set el.innerHTML to `<span>${el.dataset.originalSign}</span><span>${el.dataset.originalPrefix}</span><span>${el.dataset.originalAmount}</span><span>${el.dataset.originalSuffix}</span>`
|
||||
end
|
||||
end
|
||||
|
||||
on click[target matches .amount] if I include #settings-hide-amounts
|
||||
if event.target do not matches .revealed then set event.target.textContent to event.target.dataset.originalValue
|
||||
else set event.target.textContent to '•••••••••••' end
|
||||
then toggle .revealed on event.target
|
||||
on click[target matches .amount or target.parentNode matches .amount] if I include #settings-hide-amounts
|
||||
if event.target matches .amount
|
||||
set el to event.target
|
||||
else
|
||||
set el to event.target.parentNode
|
||||
end
|
||||
|
||||
if el do not matches .revealed
|
||||
then set el.innerHTML to `<span>${el.dataset.originalSign}</span><span>${el.dataset.originalPrefix}</span><span>${el.dataset.originalAmount}</span><span>${el.dataset.originalSuffix}</span>`
|
||||
else
|
||||
set el.textContent to '•••••••••••' end
|
||||
then toggle .revealed on el
|
||||
end
|
||||
end
|
||||
</script>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
label: "{% trans 'Projected Expenses' %}",
|
||||
data: accountData.datasets[3].data,
|
||||
backgroundColor: '#f8717180', // Added transparency
|
||||
backgroundColor: '#f8717180',
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
label: "{% trans 'Projected Income' %}",
|
||||
data: accountData.datasets[2].data,
|
||||
backgroundColor: '#4dde8080', // Added transparency
|
||||
backgroundColor: '#4dde8080',
|
||||
stack: 'stack0'
|
||||
},
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
label: "{% trans 'Projected Expenses' %}",
|
||||
data: currencyData.datasets[3].data,
|
||||
backgroundColor: '#f8717180', // Added transparency
|
||||
backgroundColor: '#f8717180',
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@
|
||||
{
|
||||
label: "{% trans 'Projected Income' %}",
|
||||
data: currencyData.datasets[2].data,
|
||||
backgroundColor: '#4dde8080', // Added transparency
|
||||
backgroundColor: '#4dde8080',
|
||||
stack: 'stack0'
|
||||
},
|
||||
|
||||
|
||||
@@ -1,37 +1,45 @@
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
<form _="install init_tom_select
|
||||
on change trigger updated
|
||||
init trigger updated" id="category-form">
|
||||
{% crispy category_form %}
|
||||
</form>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-3">
|
||||
<div class="w-full">
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card-header bg-base-200 p-4 font-semibold">
|
||||
{% trans "Income/Expense by Account" %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="account-card" class="show-loading" hx-get="{% url 'category_sum_by_account' %}"
|
||||
hx-trigger="updated from:window" hx-include="#category-form, #picker-form, #picker-type">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card-header bg-base-200 p-4 font-semibold">
|
||||
{% trans "Income/Expense by Currency" %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="currency-card" class="show-loading" hx-get="{% url 'category_sum_by_currency' %}"
|
||||
hx-trigger="updated from:window" hx-include="#category-form, #picker-form, #picker-type">
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card card-border bg-base-100">
|
||||
<div class="card-body">
|
||||
<form _="install init_tom_select
|
||||
on change trigger updated
|
||||
init trigger updated" id="category-form">
|
||||
{% crispy category_form %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card-header bg-base-200 p-4 font-semibold rounded-box shadow">
|
||||
{% trans "Income/Expense by Account" %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="account-card" class="show-loading" hx-get="{% url 'category_sum_by_account' %}"
|
||||
hx-trigger="updated from:window" hx-include="#category-form, #picker-form, #picker-type">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card-header bg-base-200 p-4 font-semibold rounded-box shadow">
|
||||
{% trans "Income/Expense by Currency" %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="currency-card" class="show-loading" hx-get="{% url 'category_sum_by_currency' %}"
|
||||
hx-trigger="updated from:window" hx-include="#category-form, #picker-form, #picker-type">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,56 +3,58 @@
|
||||
<div hx-get="{% url 'category_overview' %}" hx-trigger="updated from:window" class="show-loading" hx-swap="outerHTML"
|
||||
hx-include="#picker-form, #picker-type, #view-type, #show-tags, #showing, #show-entities">
|
||||
<div class="h-full text-center mb-4">
|
||||
<div class="join" role="group" id="view-type" _="on change trigger updated">
|
||||
<input type="radio" class="join-item btn btn-outline btn-primary rounded-full"
|
||||
name="view_type"
|
||||
id="table-view"
|
||||
autocomplete="off"
|
||||
value="table"
|
||||
aria-label="{% trans 'Table' %}"
|
||||
{% if view_type == "table" %}checked{% endif %}>
|
||||
|
||||
<input type="radio"
|
||||
class="join-item btn btn-outline btn-primary rounded-full"
|
||||
name="view_type"
|
||||
id="bars-view"
|
||||
autocomplete="off"
|
||||
value="bars"
|
||||
aria-label="{% trans 'Bars' %}"
|
||||
{% if view_type == "bars" %}checked{% endif %}>
|
||||
<div class="tabs tabs-box mx-auto w-fit" role="group" id="view-type" _="on change trigger updated">
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="view_type"
|
||||
id="table-view"
|
||||
autocomplete="off"
|
||||
value="table"
|
||||
aria-label="{% trans 'Table' %}"
|
||||
{% if view_type == "table" %}checked{% endif %}>
|
||||
<i class="fa-solid fa-table fa-fw me-2"></i>
|
||||
{% trans 'Table' %}
|
||||
</label>
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="view_type"
|
||||
id="bars-view"
|
||||
autocomplete="off"
|
||||
value="bars"
|
||||
aria-label="{% trans 'Bars' %}"
|
||||
{% if view_type == "bars" %}checked{% endif %}>
|
||||
<i class="fa-solid fa-chart-bar fa-fw me-2"></i>
|
||||
{% trans 'Bars' %}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 mb-1 flex flex-col md:flex-row justify-between">
|
||||
<div class="my-3 flex flex-col gap-3 md:flex-row justify-between">
|
||||
<div class="flex gap-4">
|
||||
{% if view_type == 'table' %}
|
||||
<div class="form-control" id="show-tags">
|
||||
<input type="hidden" name="show_tags" value="off">
|
||||
<label class="label cursor-pointer gap-2">
|
||||
<input type="checkbox" class="toggle" id="show-tags-switch" name="show_tags"
|
||||
<div id="show-tags">
|
||||
<label class="label">
|
||||
<input type="hidden" name="show_tags" value="off">
|
||||
<input type="checkbox" class="toggle toggle-primary toggle-sm" id="show-tags-switch" name="show_tags"
|
||||
_="on change trigger updated" {% if show_tags %}checked{% endif %}>
|
||||
{% spaceless %}
|
||||
<span class="label-text">
|
||||
<span>
|
||||
{% trans 'Tags' %}
|
||||
</span>
|
||||
<c-ui.help-icon
|
||||
content="{% trans 'Transaction amounts associated with multiple tags will be counted once for each tag' %}"
|
||||
icon="fa-solid fa-circle-exclamation"></c-ui.help-icon>
|
||||
{% endspaceless %}
|
||||
</span>
|
||||
<c-ui.help-icon
|
||||
content="{% trans 'Transaction amounts associated with multiple tags will be counted once for each tag' %}"
|
||||
icon="fa-solid fa-circle-exclamation"></c-ui.help-icon>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-control" id="show-entities" {% if not show_tags %}style="display: none;"{% endif %}>
|
||||
<input type="hidden" name="show_entities" value="off">
|
||||
<label class="label cursor-pointer gap-2">
|
||||
<input type="checkbox" class="toggle" id="show-entities-switch" name="show_entities"
|
||||
<div id="show-entities" class="{% if not show_tags %}hidden{% endif %}">
|
||||
<label class="label">
|
||||
<input type="hidden" name="show_entities" value="off">
|
||||
<input type="checkbox" class="toggle toggle-primary toggle-sm" id="show-entities-switch" name="show_entities"
|
||||
_="on change trigger updated" {% if show_entities %}checked{% endif %}>
|
||||
{% spaceless %}
|
||||
<span class="label-text">
|
||||
<span>
|
||||
{% trans 'Entities' %}
|
||||
</span>
|
||||
<c-ui.help-icon
|
||||
content="{% trans 'Transaction amounts associated with multiple tags and entities will be counted once for each tag' %}"
|
||||
icon="fa-solid fa-circle-exclamation"></c-ui.help-icon>
|
||||
{% endspaceless %}
|
||||
</span>
|
||||
<c-ui.help-icon
|
||||
content="{% trans 'Transaction amounts associated with multiple tags will be counted once for each tag' %}"
|
||||
icon="fa-solid fa-circle-exclamation"></c-ui.help-icon>
|
||||
</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -70,8 +72,10 @@
|
||||
</div>
|
||||
{% if total_table %}
|
||||
{% if view_type == "table" %}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-zebra">
|
||||
<div class="card bg-base-100 card-border">
|
||||
<c-config.search></c-config.search>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{% trans 'Category' %}</th>
|
||||
@@ -176,7 +180,7 @@
|
||||
{% for tag_id, tag in category.tags.items %}
|
||||
{% if tag.name or not tag.name and category.tags.values|length > 1 %}
|
||||
<tr class="bg-base-200">
|
||||
<td class="ps-4">
|
||||
<td class="ps-6">
|
||||
<i class="fa-solid fa-hashtag fa-fw me-2 text-base-content/60"></i>{% if tag.name %}{{ tag.name }}{% else %}{% trans 'Untagged' %}{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
@@ -269,7 +273,7 @@
|
||||
{% for entity_id, entity in tag.entities.items %}
|
||||
{% if entity.name or not entity.name and tag.entities.values|length > 1 %}
|
||||
<tr class="bg-base-300">
|
||||
<td class="ps-5">
|
||||
<td class="ps-10">
|
||||
<i class="fa-solid fa-user-group fa-fw me-2 text-base-content/60"></i>{% if entity.name %}{{ entity.name }}{% else %}{% trans 'No entity' %}{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
@@ -366,13 +370,16 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% elif view_type == "bars" %}
|
||||
<div>
|
||||
<div class="chart-container relative h-[78vh] w-full" _="init call setupChart() end">
|
||||
<canvas id="categoryChart"></canvas>
|
||||
<div class="card bg-base-100 card-border">
|
||||
<div class="card-body">
|
||||
<div class="chart-container relative h-[75vh] w-full" _="init call setupChart() end">
|
||||
<canvas id="categoryChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
<div hx-get="{% url 'insights_late_transactions' %}" hx-trigger="updated from:window" class="show-loading"
|
||||
<div hx-get="{% url 'insights_latest_transactions' %}" hx-trigger="updated from:window" class="show-loading"
|
||||
id="transactions-list" hx-swap="outerHTML">
|
||||
{% if transactions %}
|
||||
{% for transaction in transactions %}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="show-loading" hx-get="{% url 'insights_sankey_by_currency' %}" hx-trigger="updated from:window"
|
||||
hx-swap="outerHTML" hx-include="#picker-form, #picker-type">
|
||||
{% endif %}
|
||||
<div class="chart-container relative min-h-[85vh] max-h-[85vh] h-full w-full"
|
||||
<div class="card bg-base-100 card-border chart-container relative min-h-[85vh] max-h-[85vh] h-full w-full"
|
||||
id="sankeyContainer"
|
||||
_="init call setupSankeyChart() end">
|
||||
<canvas id="sankeyChart"></canvas>
|
||||
@@ -15,7 +15,14 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var style = getComputedStyle(document.body);
|
||||
var incomeColor = style.getPropertyValue('--color-success');
|
||||
var expenseColor = style.getPropertyValue('--color-error');
|
||||
var primaryColor = style.getPropertyValue('--color-primary');
|
||||
var contentColor = style.getPropertyValue('--color-base-content');
|
||||
console.log('Sankey colors:', incomeColor, expenseColor, primaryColor, contentColor);
|
||||
var data = {{ sankey_data|safe }};
|
||||
console.log(convertColorToRgba(incomeColor))
|
||||
|
||||
function setupSankeyChart(chartId = 'sankeyChart') {
|
||||
function formatCurrency(value, currency) {
|
||||
@@ -35,11 +42,11 @@
|
||||
const colors = {};
|
||||
data.nodes.forEach(node => {
|
||||
if (node.id.startsWith('income_')) {
|
||||
colors[node.id] = '#4dde80'; // Green for income
|
||||
colors[node.id] = convertColorToRgba(incomeColor); // Green for income
|
||||
} else if (node.id.startsWith('expense_')) {
|
||||
colors[node.id] = '#f87171'; // Red for expenses
|
||||
colors[node.id] = convertColorToRgba(expenseColor); // Red for expenses
|
||||
} else {
|
||||
colors[node.id] = '#fbb700'; // Primary for others
|
||||
colors[node.id] = convertColorToRgba(primaryColor); // Primary for others
|
||||
}
|
||||
});
|
||||
|
||||
@@ -63,7 +70,7 @@
|
||||
colorMode: 'gradient',
|
||||
alpha: 0.5,
|
||||
size: 'max',
|
||||
color: "white",
|
||||
color: contentColor,
|
||||
nodePadding: 30,
|
||||
priority: data.nodes.reduce((acc, node) => {
|
||||
acc[node.id] = node.priority;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="row gy-3">
|
||||
<div class="col-12 md:col-3 gy-3">
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="card bg-base-100 card-borderS">
|
||||
<div class="card-body">
|
||||
@@ -73,22 +73,22 @@
|
||||
remove .btn-active from <.insights-list button/>
|
||||
add .btn-active to event.target
|
||||
set event.target's @aria-selected to 'true'">
|
||||
<button class="btn btn-ghost justify-start"
|
||||
<button class="btn btn-ghost justify-start text-start"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'insights_sankey_by_account' %}">
|
||||
{% trans 'Account Flow' %}
|
||||
</button>
|
||||
<button class="btn btn-ghost justify-start" data-bs-target="#v-pills-content"
|
||||
<button class="btn btn-ghost justify-start text-start" data-bs-target="#v-pills-content"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'insights_sankey_by_currency' %}"
|
||||
>{% trans 'Currency Flow' %}
|
||||
</button>
|
||||
<button class="btn btn-ghost justify-start" data-bs-target="#v-pills-content"
|
||||
<button class="btn btn-ghost justify-start text-start" data-bs-target="#v-pills-content"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'category_explorer_index' %}">
|
||||
{% trans 'Category Explorer' %}
|
||||
</button>
|
||||
<button class="btn btn-ghost justify-start" data-bs-target="#v-pills-content"
|
||||
<button class="btn btn-ghost justify-start text-start" data-bs-target="#v-pills-content"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'category_overview' %}"
|
||||
>{% trans 'Categories Overview' %}
|
||||
@@ -106,17 +106,17 @@
|
||||
remove .btn-active from <.insights-list button/>
|
||||
add .btn-active to event.target
|
||||
set event.target's @aria-selected to 'true'">
|
||||
<button class="btn btn-ghost justify-start" data-bs-target="#v-pills-content"
|
||||
<button class="btn btn-ghost justify-start text-start" data-bs-target="#v-pills-content"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'insights_late_transactions' %}">
|
||||
{% trans 'Late Transactions' %}
|
||||
</button>
|
||||
<button class="btn btn-ghost justify-start" data-bs-target="#v-pills-content"
|
||||
<button class="btn btn-ghost justify-start text-start" data-bs-target="#v-pills-content"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'insights_latest_transactions' %}">
|
||||
{% trans 'Latest Transactions' %}
|
||||
</button>
|
||||
<button class="btn btn-ghost justify-start" data-bs-target="#v-pills-content"
|
||||
<button class="btn btn-ghost justify-start text-start" data-bs-target="#v-pills-content"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'insights_emergency_fund' %}">
|
||||
{% trans 'Emergency Fund' %}
|
||||
@@ -126,7 +126,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-9">
|
||||
<div class="col-12 md:col-9 gy-3">
|
||||
<div id="tab-content" class="show-loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
|
||||
{% include 'includes/mobile_navbar.html' %}
|
||||
{% include 'includes/sidebar.html' %}
|
||||
<main class="my-4 px-3">
|
||||
<main class="my-8 px-3">
|
||||
{% settings "DEMO" as demo_mode %}
|
||||
{% if demo_mode %}
|
||||
<div class="px-3 m-0" id="demo-mode-alert" hx-preserve>
|
||||
|
||||
@@ -17,22 +17,31 @@
|
||||
class="show-loading"
|
||||
hx-get=""
|
||||
hx-target="body">
|
||||
<div class="h-full text-center mb-4 pt-2 w-full">
|
||||
<div class="h-full text-center mb-4 w-full">
|
||||
<div class="tabs tabs-box mx-auto w-fit"
|
||||
id="view-type"
|
||||
_="on change trigger updated">
|
||||
<input type="radio"
|
||||
name="view_type"
|
||||
class="tab"
|
||||
aria-label="{% trans "Current" %}"
|
||||
value="current"
|
||||
{% if type == "current" %}checked{% endif %} />
|
||||
<input type="radio"
|
||||
name="view_type"
|
||||
class="tab"
|
||||
aria-label="{% trans "Projected" %}"
|
||||
value="projected"
|
||||
{% if type == "projected" %}checked{% endif %} />
|
||||
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="view_type"
|
||||
class="tab"
|
||||
aria-label="{% trans "Current" %}"
|
||||
value="current"
|
||||
{% if type == "current" %}checked{% endif %} />
|
||||
<i class="fa-solid fa-sack-dollar fa-fw me-2"></i>
|
||||
{% trans "Current" %}
|
||||
</label>
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="view_type"
|
||||
class="tab"
|
||||
aria-label="{% trans "Projected" %}"
|
||||
value="projected"
|
||||
{% if type == "projected" %}checked{% endif %} />
|
||||
<i class="fa-solid fa-rocket fa-fw me-2"></i>
|
||||
{% trans "Projected" %}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container px-md-3 py-3"
|
||||
@@ -45,10 +54,10 @@
|
||||
{% for currency in currency_net_worth.values %}
|
||||
<li>
|
||||
{% if currency.consolidated and currency.consolidated.total_final != currency.total_final %}
|
||||
<a class="cursor-pointer flex justify-between items-center w-full"
|
||||
<a class="cursor-pointer select-auto 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">
|
||||
<span class="currency-name text-start font-mono shrink text-ellipsis">{{ currency.currency.name }}</span>
|
||||
<span class="text-end 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>
|
||||
@@ -61,19 +70,19 @@
|
||||
</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">
|
||||
<a class="text-base-content/60 select-auto">
|
||||
<span class="text-start shrink">{% trans "Consolidated" %}</span>
|
||||
<span class="text-end 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"
|
||||
<a class="cursor-pointer select-auto 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">
|
||||
<span class="currency-name text-start font-mono shrink">{{ currency.currency.name }}</span>
|
||||
<span class="text-end 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>
|
||||
@@ -134,16 +143,16 @@
|
||||
{% if data.grouper %}
|
||||
<li>
|
||||
<details open>
|
||||
<summary class="font-mono">
|
||||
<summary class="select-auto">
|
||||
<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"
|
||||
<a class="cursor-pointer select-auto flex justify-between items-center w-full"
|
||||
_="on click showOnlyAccountDataset('{{ account.account.name }}')">
|
||||
<span class="account-name text-start font-mono flex-shrink text-ellipsis">{{ account.account.name }}</span>
|
||||
<span class="text-end flex-shrink-0">
|
||||
<span class="account-name text-start font-mono shrink text-ellipsis">{{ account.account.name }}</span>
|
||||
<span class="text-end 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>
|
||||
@@ -162,10 +171,10 @@
|
||||
{% else %}
|
||||
{% for account in data.list %}
|
||||
<li>
|
||||
<a class="cursor-pointer flex justify-between items-center w-full"
|
||||
<a class="cursor-pointer flex select-auto 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">
|
||||
<span class="account-name text-start font-mono shrink">{{ account.account.name }}</span>
|
||||
<span class="text-end 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>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
_="on click
|
||||
remove .btn-active from <button/> in #filter-pills
|
||||
add .btn-active to me">
|
||||
{% if account.group.name %}<span class="badge badge-primary me-2">{{ account.group.name }}</span>{% endif %} {{ account.name }}
|
||||
{% if account.group.name %}<span class="badge badge-primary badge-outline">{{ account.group.name }}</span>{% endif %} {{ account.name }}
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="h-full text-center mb-4 pt-2 w-full">
|
||||
<div class="h-full text-center mb-4 w-full">
|
||||
<div role="tablist" class="tabs tabs-box mx-auto w-fit">
|
||||
<a href="{% url 'yearly_overview_currency' year=year %}" class="tab {% if type == 'currency' %}tab-active{% endif %}" hx-boost>
|
||||
<i class="fa-solid fa-solid fa-coins fa-fw me-2"></i>{% trans 'Currency' %}
|
||||
|
||||
37
frontend/src/js/_utils.js
Normal file
37
frontend/src/js/_utils.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Converts ANY valid CSS color string (oklch, hex, hsl, etc.)
|
||||
* into a standard RGBA string that Chart.js can understand.
|
||||
* This method uses a canvas to force the browser to compute the color.
|
||||
* @param {string} colorString The color string to convert.
|
||||
* @returns {string} The computed 'rgba(r, g, b, a)' string.
|
||||
*/
|
||||
window.convertColorToRgba = function convertColorToRgba(colorString) {
|
||||
if (!colorString) return 'rgba(0,0,0,0.1)'; // Fallback
|
||||
|
||||
console.log(colorString)
|
||||
|
||||
// Create a 1x1 pixel canvas
|
||||
let canvas = document.createElement('canvas');
|
||||
canvas.width = 1;
|
||||
canvas.height = 1;
|
||||
let ctx = canvas.getContext('2d');
|
||||
|
||||
// Set the fillStyle to the color string
|
||||
// The browser MUST parse the oklch string here
|
||||
ctx.fillStyle = colorString.trim();
|
||||
|
||||
// Draw the pixel
|
||||
ctx.fillRect(0, 0, 1, 1);
|
||||
|
||||
// Get the pixel data. This is ALWAYS returned as [R, G, B, A]
|
||||
// with values from 0-255.
|
||||
const data = ctx.getImageData(0, 0, 1, 1).data;
|
||||
|
||||
// Convert the 0-255 alpha to a 0-1 float
|
||||
const a = data[3] / 255;
|
||||
|
||||
console.log(data)
|
||||
|
||||
// Return the standard rgba string
|
||||
return `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${a})`;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import './js/_tooltip.js';
|
||||
import './_tooltip.js';
|
||||
import 'bootstrap/js/dist/dropdown';
|
||||
import Toast from 'bootstrap/js/dist/toast';
|
||||
import 'bootstrap/js/dist/dropdown';
|
||||
@@ -1,4 +1,4 @@
|
||||
import '@fontsource-variable/jetbrains-mono/wght-italic.css';
|
||||
import '@fontsource-variable/jetbrains-mono';
|
||||
import './styles/tailwind.css';
|
||||
import './styles/style.scss';
|
||||
import '../styles/tailwind.css';
|
||||
import '../styles/style.scss';
|
||||
9
frontend/src/main.js
Normal file
9
frontend/src/main.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import './js/bootstrap.js';
|
||||
import './js/datepicker.js';
|
||||
import './js/htmx.js';
|
||||
import './js/select.js';
|
||||
import './js/charts.js';
|
||||
import './js/autosize.js';
|
||||
import './js/sweetalert2.js';
|
||||
import './js/style.js';
|
||||
import './js/_utils.js';
|
||||
@@ -139,24 +139,46 @@
|
||||
}
|
||||
|
||||
.text-exchange-rate {
|
||||
@apply text-base-content/60;
|
||||
@apply text-base-content/60 text-xs;
|
||||
}
|
||||
|
||||
.text-subtle {
|
||||
@apply text-base-content/80;
|
||||
}
|
||||
|
||||
/* Card Data Display Styles */
|
||||
.card-data-section {
|
||||
@apply space-y-1;
|
||||
}
|
||||
|
||||
.card-data-row {
|
||||
@apply flex justify-between py-1 px-3 rounded-lg transition-colors duration-150 hover:bg-base-200/50 items-center;
|
||||
}
|
||||
|
||||
.card-data-label {
|
||||
@apply text-base-content/80; /* .text-subtle */
|
||||
@apply text-sm font-medium;
|
||||
}
|
||||
|
||||
.card-data-values {
|
||||
@apply flex flex-col items-end gap-0.5;
|
||||
}
|
||||
|
||||
.card-data-divider {
|
||||
@apply text-base-content/60; /* .hr */
|
||||
@apply my-3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@layer components {
|
||||
.fab {
|
||||
@layer daisyui.component {
|
||||
> :nth-child(n+7) {
|
||||
transition-delay: 150ms;
|
||||
@layer daisyui.component {
|
||||
> :nth-child(n+7) {
|
||||
transition-delay: 150ms;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* === Sidebar styles === */
|
||||
.sidebar-active {
|
||||
@@ -173,7 +195,7 @@
|
||||
|
||||
.sidebar-floating {
|
||||
/* Establishes the hover group and sets the collapsed/hover widths for the container */
|
||||
@apply lg:w-16 lg:hover:w-112;
|
||||
@apply lg:w-16 lg:hover:w-md;
|
||||
}
|
||||
|
||||
.sidebar-floating #sidebar {
|
||||
|
||||
@@ -10,14 +10,7 @@ const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const rollupInputs = {
|
||||
autosize: resolve(__dirname, 'src/autosize.js'),
|
||||
charts: resolve(__dirname, 'src/charts.js'),
|
||||
datepicker: resolve(__dirname, 'src/datepicker.js'),
|
||||
bootstrap: resolve(__dirname, 'src/bootstrap.js'),
|
||||
htmx: resolve(__dirname, 'src/htmx.js'),
|
||||
select: resolve(__dirname, 'src/select.js'),
|
||||
style: resolve(__dirname, 'src/style.js'),
|
||||
sweetalert2: resolve(__dirname, 'src/sweetalert2.js'),
|
||||
main: resolve(__dirname, 'src/main.js'),
|
||||
};
|
||||
|
||||
|
||||
@@ -42,6 +35,7 @@ export default defineConfig({
|
||||
usePolling: true,
|
||||
disableGlobbing: false,
|
||||
},
|
||||
hmr: false,
|
||||
cors: true,
|
||||
origin: 'http://100.118.164.62:5173'
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user