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:
@@ -38,6 +38,7 @@ class SharedObjectForm(forms.Form):
|
||||
choices=SharedObject.Visibility.choices,
|
||||
required=True,
|
||||
label=_("Visibility"),
|
||||
widget=TomSelect(clear_button=False),
|
||||
help_text=_(
|
||||
"Private: Only shown for the owner and shared users. Only editable by the owner."
|
||||
"<br/>"
|
||||
@@ -47,9 +48,6 @@ class SharedObjectForm(forms.Form):
|
||||
|
||||
class Meta:
|
||||
fields = ["visibility", "shared_with_users"]
|
||||
widgets = {
|
||||
"visibility": TomSelect(clear_button=False),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Get the current user to filter available sharing options
|
||||
@@ -72,7 +70,7 @@ class SharedObjectForm(forms.Form):
|
||||
self.helper.layout = Layout(
|
||||
Field("owner"),
|
||||
Field("visibility"),
|
||||
HTML("<hr>"),
|
||||
HTML('<hr class="hr my-3">'),
|
||||
Field("shared_with_users"),
|
||||
FormActions(
|
||||
NoClassSubmit("submit", _("Save"), css_class="btn btn-primary"),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.forms import widgets, SelectMultiple
|
||||
from django.forms import SelectMultiple, widgets
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
@@ -17,7 +17,7 @@ class TomSelect(widgets.Select):
|
||||
checkboxes=False,
|
||||
group_by=None,
|
||||
*args,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(attrs, *args, **kwargs)
|
||||
self.remove_button = remove_button
|
||||
|
||||
@@ -337,7 +337,7 @@ class QuickTransactionForm(forms.ModelForm):
|
||||
),
|
||||
Field("is_paid", template="transactions/widgets/paid_toggle_button.html"),
|
||||
"name",
|
||||
HTML("<hr />"),
|
||||
HTML('<hr class="hr my-3" />'),
|
||||
Row(
|
||||
Column("account"),
|
||||
Column("entities"),
|
||||
@@ -365,11 +365,8 @@ class QuickTransactionForm(forms.ModelForm):
|
||||
else:
|
||||
self.fields["amount"].widget = ArbitraryDecimalDisplayNumberInput()
|
||||
self.helper.layout.append(
|
||||
Div(
|
||||
NoClassSubmit(
|
||||
"submit", _("Add"), css_class="btn btn-outline-primary"
|
||||
),
|
||||
css_class="d-grid gap-2",
|
||||
FormActions(
|
||||
NoClassSubmit("submit", _("Add"), css_class="btn btn-primary"),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -22,11 +22,14 @@ def _format_string(prefix, amount, decimal_places, suffix):
|
||||
|
||||
|
||||
@register.simple_tag(name="currency_display")
|
||||
def currency_display(amount, prefix, suffix, decimal_places):
|
||||
def currency_display(amount, prefix, suffix, decimal_places, string=False):
|
||||
sign, prefix, amount, suffix = _format_string(
|
||||
prefix, amount, decimal_places, suffix
|
||||
)
|
||||
|
||||
if string:
|
||||
return f"{sign}{prefix}{amount}{suffix}"
|
||||
|
||||
return {
|
||||
"sign": sign,
|
||||
"prefix": prefix,
|
||||
|
||||
@@ -20,14 +20,14 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for account_group in account_groups %}
|
||||
<tr class="account_group">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -35,7 +35,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'account_group_delete' pk=account_group.id %}"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{{ form.management_form }}
|
||||
<div class="space-y-2" id="balanceAccordionFlush">
|
||||
{% for form in form.forms %}
|
||||
<div class="collapse collapse-arrow bg-base-100 border-base-300 border overflow-visible">
|
||||
<div class="collapse collapse-arrow bg-base-100 border-base-300 border-2">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title font-medium text-sm">
|
||||
{% if form.account_group %}<span class="badge badge-primary badge-outline me-2">{{ form.account_group.name }}</span>{% endif %}{{ form.account_name }}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<table class="table table-hover whitespace-nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Group' %}</th>
|
||||
<th scope="col">{% translate 'Currency' %}</th>
|
||||
@@ -32,7 +32,7 @@
|
||||
<tbody>
|
||||
{% for account in accounts %}
|
||||
<tr class="account">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -40,7 +40,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'account_delete' pk=account.id %}"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Muted' %}</th>
|
||||
</tr>
|
||||
@@ -20,7 +20,7 @@
|
||||
<tbody>
|
||||
{% for category in categories %}
|
||||
<tr class="category">
|
||||
<td class="w-auto text-center">
|
||||
<td class="table-col-auto text-center">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -29,7 +29,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'category_delete' category_id=category.id %}"
|
||||
|
||||
@@ -21,3 +21,5 @@
|
||||
<div class="alert-warning"></div>
|
||||
<div class="textarea"></div>
|
||||
<div class="border-base-content/60"></div>
|
||||
<div class="bg-error/20"></div>
|
||||
<div class="bg-success/20"></div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<li>
|
||||
<div class="flex items-center min-h-6">
|
||||
{% if title %}
|
||||
<span class="sidebar-menu-header text-base-content/60 text-xs font-bold uppercase mr-3">{{ title }}</span>
|
||||
{% endif %}
|
||||
<hr class="hr grow"/>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
data-confirm-text="{% translate "Yes, delete it!" %}"
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i>
|
||||
</a>
|
||||
<button class="btn btn-soft 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" 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">
|
||||
|
||||
7
app/templates/cotton/ui/fab_single_action.html
Normal file
7
app/templates/cotton/ui/fab_single_action.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<div class="fab">
|
||||
<button class="btn btn-lg btn-circle btn-primary"
|
||||
hx-get="{{ url }}"
|
||||
hx-target="{{ hx_target }}">
|
||||
<i class="fa-solid fa-plus text-2xl fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
{% load i18n %}
|
||||
<div class="sticky bottom-4 left-0 right-0 z-50 hidden mx-auto w-fit" id="actions-bar"
|
||||
<div class="sticky bottom-4 left-0 right-0 z-1000 hidden mx-auto w-fit" id="actions-bar"
|
||||
_="on change from #transactions-list or htmx:afterSettle from window
|
||||
if #actions-bar then
|
||||
if no <input[type='checkbox']:checked/> in #transactions-list
|
||||
@@ -22,41 +22,43 @@
|
||||
{% spaceless %}
|
||||
<div class="font-bold text-md ms-2" id="selected-count">0</div>
|
||||
<div class="divider divider-horizontal m-0"></div>
|
||||
<div class="dropdown dropdown-top dropdown-end">
|
||||
<button tabindex="0" role="button" class="btn btn-secondary btn-soft btn-sm" type="button">
|
||||
<div>
|
||||
<button role="button" class="btn btn-secondary btn-sm" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fa-regular fa-square-check fa-fw"></i>
|
||||
<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 p-2 shadow fixed!">
|
||||
<ul class="dropdown-menu menu">
|
||||
<li>
|
||||
<a class="cursor-pointer"
|
||||
_="on click set <#transactions-list .transaction:not([style*='display: none']) input[type='checkbox']/>'s checked to true then call me.blur() then trigger change">
|
||||
<i class="fa-regular fa-square-check text-green-400 me-3"></i>{% translate 'Select All' %}
|
||||
<i class="fa-regular fa-square-check text-success me-3"></i>{% translate 'Select All' %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="cursor-pointer"
|
||||
_="on click set <#transactions-list input[type='checkbox']/>'s checked to false then call me.blur() then trigger change">
|
||||
<i class="fa-regular fa-square text-red-400 me-3"></i>{% translate 'Unselect All' %}
|
||||
<i class="fa-regular fa-square text-error me-3"></i>{% translate 'Unselect All' %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="divider divider-horizontal m-0"></div>
|
||||
<div class="join">
|
||||
<button class="btn btn-secondary btn-soft join-item btn-sm"
|
||||
<button class="btn btn-secondary join-item btn-sm"
|
||||
hx-get="{% url 'transactions_bulk_edit' %}"
|
||||
hx-target="#generic-offcanvas"
|
||||
hx-include=".transaction"
|
||||
data-tippy-content="{% translate 'Edit' %}">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</button>
|
||||
<div class="dropdown dropdown-top dropdown-end">
|
||||
<button type="button" tabindex="0" role="button" class="join-item btn btn-sm btn-secondary">
|
||||
<div>
|
||||
<button type="button" role="button" class="join-item btn btn-sm btn-secondary"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fa-solid fa-chevron-down fa-xs"></i>
|
||||
</button>
|
||||
|
||||
<ul tabindex="0" class="dropdown-content fixed! menu bg-base-300 rounded-box z-[1] w-full p-2 shadow">
|
||||
<ul class="dropdown-menu menu">
|
||||
<li>
|
||||
<a class="cursor-pointer"
|
||||
hx-get="{% url 'transactions_bulk_unpay' %}"
|
||||
@@ -142,12 +144,16 @@
|
||||
<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">
|
||||
<button type="button" tabindex="0" role="button" class="join-item btn btn-sm btn-secondary">
|
||||
<div>
|
||||
<button class="join-item btn btn-sm btn-secondary"
|
||||
type="button"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
aria-expanded="false">
|
||||
<i class="fa-solid fa-chevron-down fa-xs"></i>
|
||||
</button>
|
||||
|
||||
<ul tabindex="0" class="dropdown-content menu bg-base-300 rounded-box w-full shadow fixed! flex flex-col gap-1">
|
||||
<ul class="dropdown-menu dropdown-menu-end menu">
|
||||
<li class="cursor-pointer"
|
||||
_="on click
|
||||
set original_value to #calc-menu-flat-total's innerText
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
{% if help_text_inline %}
|
||||
<span id="{{ field.auto_id }}_helptext" class="text-xs text-base-content/60 text-wrap">{{ field.help_text|safe}}</span>
|
||||
{% else %}
|
||||
<div {% if field.auto_id %}id="{{ field.auto_id }}_helptext" {% endif %}class="text-xs text-base-content/60 mt-1 text-wrap">{{ field.help_text|safe }}</div>
|
||||
<p {% if field.auto_id %}id="{{ field.auto_id }}_helptext" {% endif %}class="label">{{ field.help_text|safe }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="w-auto">{% translate 'Code' %}</th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col" class="table-col-auto">{% translate 'Code' %}</th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Archived' %}</th>
|
||||
</tr>
|
||||
@@ -29,7 +29,7 @@
|
||||
<tbody>
|
||||
{% for currency in currencies %}
|
||||
<tr class="currency">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -37,7 +37,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'currency_delete' pk=currency.id %}"
|
||||
@@ -49,7 +49,7 @@
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="w-auto">{{ currency.code }}</td>
|
||||
<td class="table-col-auto">{{ currency.code }}</td>
|
||||
<td>{{ currency.name }}</td>
|
||||
<td>{% if currency.is_archived %}<i class="fa-solid fa-solid fa-check text-success"></i>{% endif %}</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,53 +1,50 @@
|
||||
{% load currency_display %}
|
||||
{% load i18n %}
|
||||
<div class="container-fluid px-md-3 py-3 column-gap-5">
|
||||
<div class="lg:flex justify-between mb-3 w-full">
|
||||
<div class="text-3xl font-bold font-mono flex items-center">
|
||||
{{ strategy.name }}
|
||||
</div>
|
||||
<div class="text-sm lg:text-right mt-2 lg:mt-0">
|
||||
<div class="mb-2">
|
||||
<span class="badge badge-secondary rounded-full">{{ strategy.payment_currency.name }}</span> x <span class="badge badge-secondary rounded-full">{{ strategy.target_currency.name }}</span>
|
||||
<c-ui.fab-single-action
|
||||
url="{% url 'dca_entry_add' strategy_id=strategy.id %}"
|
||||
hx_target="#generic-offcanvas">
|
||||
</c-ui.fab-single-action>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="lg:flex justify-between mb-3 w-full">
|
||||
<div class="text-3xl font-bold font-mono flex items-center">
|
||||
{{ strategy.name }}
|
||||
</div>
|
||||
<div>
|
||||
{% if strategy.current_price %}
|
||||
<c-amount.display
|
||||
:amount="strategy.current_price.0"
|
||||
:prefix="strategy.payment_currency.prefix"
|
||||
:suffix="strategy.payment_currency.suffix"
|
||||
:decimal_places="strategy.payment_currency.decimal_places">
|
||||
• {{ strategy.current_price.1|date:"SHORT_DATETIME_FORMAT" }}
|
||||
</c-amount.display>
|
||||
{% else %}
|
||||
<div class="text-red-400">{% trans "No exchange rate available" %}</div>
|
||||
{% endif %}
|
||||
<div class="text-sm lg:text-right mt-2 lg:mt-0">
|
||||
<div class="mb-2">
|
||||
<span class="badge badge-secondary rounded-full">{{ strategy.payment_currency.name }}</span> x <span class="badge badge-secondary rounded-full">{{ strategy.target_currency.name }}</span>
|
||||
</div>
|
||||
<div>
|
||||
{% if strategy.current_price %}
|
||||
<c-amount.display
|
||||
:amount="strategy.current_price.0"
|
||||
:prefix="strategy.payment_currency.prefix"
|
||||
:suffix="strategy.payment_currency.suffix"
|
||||
:decimal_places="strategy.payment_currency.decimal_places">
|
||||
• {{ strategy.current_price.1|date:"SHORT_DATETIME_FORMAT" }}
|
||||
</c-amount.display>
|
||||
{% else %}
|
||||
<div class="text-error">{% trans "No exchange rate available" %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid lg:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-body overflow-x-auto">
|
||||
{% spaceless %}
|
||||
<div class="card-title text-xl">{% trans "Entries" %}<span>
|
||||
<a class="no-underline p-1 category-action"
|
||||
role="button"
|
||||
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>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-title text-xl">{% trans "Entries" %}</div>
|
||||
{% endspaceless %}
|
||||
|
||||
{% if entries %}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-hover whitespace-nowrap">
|
||||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="table-col-auto"></th>
|
||||
<th>{% trans "Date" %}</th>
|
||||
<th>{% trans "Amount Received" %}</th>
|
||||
<th>{% trans "Amount Paid" %}</th>
|
||||
@@ -58,7 +55,7 @@
|
||||
<tbody>
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -67,7 +64,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'dca_entry_delete' entry_id=entry.id strategy_id=entry.strategy.id %}"
|
||||
@@ -88,7 +85,7 @@
|
||||
:suffix="entry.strategy.target_currency.suffix"
|
||||
:decimal_places="entry.strategy.target_currency.decimal_places"></c-amount.display>
|
||||
</td>
|
||||
<td title="{% currency_display amount=entry.entry_price prefix=entry.strategy.payment_currency.prefix suffix=entry.strategy.payment_currency.suffix decimal_places=entry.strategy.payment_currency.decimal_places %}">
|
||||
<td title="{% currency_display amount=entry.entry_price prefix=entry.strategy.payment_currency.prefix suffix=entry.strategy.payment_currency.suffix decimal_places=entry.strategy.payment_currency.decimal_places string=True %}">
|
||||
<c-amount.display
|
||||
:amount="entry.amount_paid"
|
||||
:prefix="entry.strategy.payment_currency.prefix"
|
||||
@@ -105,10 +102,10 @@
|
||||
<td>
|
||||
{% if entry.profit_loss_percentage > 0 %}
|
||||
<span class="badge badge-success"><i
|
||||
class="fa-solid fa-up-long me-2"></i>{{ entry.profit_loss_percentage|floatformat:"2g" }}%</span>
|
||||
class="fa-solid fa-up-long"></i>{{ entry.profit_loss_percentage|floatformat:"2g" }}%</span>
|
||||
{% elif entry.profit_loss_percentage < 0 %}
|
||||
<span class="badge badge-error"><i
|
||||
class="fa-solid fa-down-long me-2"></i>{{ entry.profit_loss_percentage|floatformat:"2g" }}%</span>
|
||||
class="fa-solid fa-down-long"></i>{{ entry.profit_loss_percentage|floatformat:"2g" }}%</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -124,10 +121,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card bg-base-100 shadow h-full">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Total Invested" %}</h5>
|
||||
<div class="text-base-content">
|
||||
@@ -141,7 +138,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card bg-base-100 shadow h-full">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Total Received" %}</h5>
|
||||
<div class="text-base-content">
|
||||
@@ -155,7 +152,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card bg-base-100 shadow h-full">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Current Total Value" %}</h5>
|
||||
<div class="text-base-content">
|
||||
@@ -169,7 +166,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card bg-base-100 shadow h-full">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Average Entry Price" %}</h5>
|
||||
<div class="text-base-content">
|
||||
@@ -183,11 +180,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card bg-base-100 shadow h-full">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Total P/L" %}</h5>
|
||||
<div
|
||||
class="text-base-content {% if strategy.total_profit_loss >= 0 %}text-green-400{% else %}text-red-400{% endif %}">
|
||||
class="text-base-content {% if strategy.total_profit_loss >= 0 %}text-success{% else %}text-error{% endif %}">
|
||||
<c-amount.display
|
||||
:amount="strategy.total_profit_loss"
|
||||
:prefix="strategy.payment_currency.prefix"
|
||||
@@ -199,11 +196,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow-xl h-full">
|
||||
<div class="card bg-base-100 shadow h-full">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Total % P/L" %}</h5>
|
||||
<div
|
||||
class="text-base-content {% if strategy.total_profit_loss >= 0 %}text-green-400{% else %}text-red-400{% endif %}">
|
||||
class="text-base-content {% if strategy.total_profit_loss >= 0 %}text-success{% else %}text-error{% endif %}">
|
||||
{{ strategy.total_profit_loss_percentage|floatformat:2 }}%
|
||||
</div>
|
||||
</div>
|
||||
@@ -216,71 +213,70 @@
|
||||
set perfomancectx to #performanceChart.getContext('2d')
|
||||
js(perfomancectx)
|
||||
new Chart(perfomancectx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [{% for entry in entries_data %}'{{ entry.entry.date|date:"SHORT_DATE_FORMAT" }}'{% if not forloop.last %}, {% endif %}{% endfor %}],
|
||||
datasets: [{
|
||||
label: '{% trans "P/L %" %}',
|
||||
data: [{% for entry in entries_data %}{{ entry.profit_loss_percentage|floatformat:"-40u" }}{% if not forloop.last %}, {% endif %}{% endfor %}],
|
||||
stepped: true,
|
||||
segment: {
|
||||
borderColor: ctx => {
|
||||
const gradient = ctx.chart.ctx.createLinearGradient(ctx.p0.x, 0, ctx.p1.x, 0);
|
||||
|
||||
if (ctx.p0.parsed.y >= 0 && ctx.p1.parsed.y >= 0) {
|
||||
// Both positive - solid green
|
||||
gradient.addColorStop(0, 'rgb(75, 192, 75)');
|
||||
gradient.addColorStop(1, 'rgb(75, 192, 75)');
|
||||
} else if (ctx.p0.parsed.y < 0 && ctx.p1.parsed.y < 0) {
|
||||
// Both negative - solid red
|
||||
gradient.addColorStop(0, 'rgb(255, 99, 132)');
|
||||
gradient.addColorStop(1, 'rgb(255, 99, 132)');
|
||||
} else if (ctx.p0.parsed.y >= 0 && ctx.p1.parsed.y < 0) {
|
||||
// Positive to negative - green to red
|
||||
gradient.addColorStop(0, 'rgb(75, 192, 75)');
|
||||
gradient.addColorStop(1, 'rgb(255, 99, 132)');
|
||||
} else {
|
||||
// Negative to positive - red to green
|
||||
gradient.addColorStop(0, 'rgb(255, 99, 132)');
|
||||
gradient.addColorStop(1, 'rgb(75, 192, 75)');
|
||||
}
|
||||
|
||||
return gradient;
|
||||
}
|
||||
},
|
||||
fill: false,
|
||||
borderWidth: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: false
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
mode: 'index',
|
||||
intersect: false
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [{% for entry in entries_data %}'{{ entry.entry.date|date:"SHORT_DATE_FORMAT" }}'{% if not forloop.last %}, {% endif %}{% endfor %}],
|
||||
datasets: [{
|
||||
label: '{% trans "P/L %" %}',
|
||||
data: [{% for entry in entries_data %}{{ entry.profit_loss_percentage|floatformat:"-40u" }}{% if not forloop.last %}, {% endif %}{% endfor %}],
|
||||
stepped: true,
|
||||
segment: {
|
||||
borderColor: ctx => {
|
||||
const gradient = ctx.chart.ctx.createLinearGradient(ctx.p0.x, 0, ctx.p1.x, 0);
|
||||
|
||||
if (ctx.p0.parsed.y >= 0 && ctx.p1.parsed.y >= 0) {
|
||||
// Both positive - solid green
|
||||
gradient.addColorStop(0, 'rgb(75, 192, 75)');
|
||||
gradient.addColorStop(1, 'rgb(75, 192, 75)');
|
||||
} else if (ctx.p0.parsed.y < 0 && ctx.p1.parsed.y < 0) {
|
||||
// Both negative - solid red
|
||||
gradient.addColorStop(0, 'rgb(255, 99, 132)');
|
||||
gradient.addColorStop(1, 'rgb(255, 99, 132)');
|
||||
} else if (ctx.p0.parsed.y >= 0 && ctx.p1.parsed.y < 0) {
|
||||
// Positive to negative - green to red
|
||||
gradient.addColorStop(0, 'rgb(75, 192, 75)');
|
||||
gradient.addColorStop(1, 'rgb(255, 99, 132)');
|
||||
} else {
|
||||
// Negative to positive - red to green
|
||||
gradient.addColorStop(0, 'rgb(255, 99, 132)');
|
||||
gradient.addColorStop(1, 'rgb(75, 192, 75)');
|
||||
}
|
||||
|
||||
return gradient;
|
||||
}
|
||||
},
|
||||
fill: false,
|
||||
borderWidth: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: false
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
mode: 'index',
|
||||
intersect: false
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
end">
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Performance Over Time" %}</h5>
|
||||
<canvas id="performanceChart"></canvas>
|
||||
@@ -295,96 +291,95 @@
|
||||
set priceData to {{ price_comparison_data|safe }}
|
||||
js(pricectx, priceData)
|
||||
new Chart(pricectx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: priceData.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: '{% trans "Entry Price" %}',
|
||||
data: priceData.entry_prices,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.5)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1,
|
||||
yAxisID: 'y'
|
||||
},
|
||||
{
|
||||
label: '{% trans "Current Price" %}',
|
||||
data: priceData.current_prices,
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.5)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1,
|
||||
yAxisID: 'y'
|
||||
},
|
||||
{
|
||||
label: '{% trans "Amount Bought" %}',
|
||||
data: priceData.amounts_bought,
|
||||
type: 'line',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
yAxisID: 'y1',
|
||||
tension: 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
}
|
||||
},
|
||||
y: {
|
||||
type: 'linear',
|
||||
display: true,
|
||||
position: 'left',
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
ticks: {
|
||||
display: false,
|
||||
format: { maximumFractionDigits: 40, minimumFractionDigits: 1 }
|
||||
}
|
||||
},
|
||||
y1: {
|
||||
type: 'linear',
|
||||
display: true,
|
||||
position: 'right',
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
drawOnChartArea: false
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
ticks: {
|
||||
display: false,
|
||||
format: { maximumFractionDigits: 40, minimumFractionDigits: 1 }
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top'
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: priceData.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: '{% trans "Entry Price" %}',
|
||||
data: priceData.entry_prices,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.5)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1,
|
||||
yAxisID: 'y'
|
||||
},
|
||||
{
|
||||
label: '{% trans "Current Price" %}',
|
||||
data: priceData.current_prices,
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.5)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1,
|
||||
yAxisID: 'y'
|
||||
},
|
||||
{
|
||||
label: '{% trans "Amount Bought" %}',
|
||||
data: priceData.amounts_bought,
|
||||
type: 'line',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
yAxisID: 'y1',
|
||||
tension: 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
}
|
||||
},
|
||||
y: {
|
||||
type: 'linear',
|
||||
display: true,
|
||||
position: 'left',
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
ticks: {
|
||||
display: false,
|
||||
format: { maximumFractionDigits: 40, minimumFractionDigits: 1 }
|
||||
}
|
||||
},
|
||||
y1: {
|
||||
type: 'linear',
|
||||
display: true,
|
||||
position: 'right',
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
drawOnChartArea: false
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
ticks: {
|
||||
display: false,
|
||||
format: { maximumFractionDigits: 40, minimumFractionDigits: 1 }
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top'
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
end">
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Entry Price vs Current Price" %}</h5>
|
||||
<canvas id="priceChart"></canvas>
|
||||
@@ -447,7 +442,7 @@
|
||||
})
|
||||
end
|
||||
">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans "Investment Frequency" %}</h5>
|
||||
<p class="text-base-content/60">
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
{% load i18n %}
|
||||
<c-ui.fab-single-action
|
||||
url="{% url 'dca_strategy_add' %}"
|
||||
hx_target="#generic-offcanvas">
|
||||
</c-ui.fab-single-action>
|
||||
<div class="container px-md-3 py-3 column-gap-5">
|
||||
<div class="text-3xl font-bold font-mono w-full mb-3">
|
||||
{% spaceless %}
|
||||
<div>{% translate 'Dollar Cost Average Strategies' %}<span>
|
||||
<a class="no-underline text-2xl p-1 category-action"
|
||||
role="button"
|
||||
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>
|
||||
</span></div>
|
||||
<div>{% translate 'Dollar Cost Average Strategies' %}</div>
|
||||
{% endspaceless %}
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
|
||||
{% for strategy in strategies %}
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow-xl h-full flex flex-col">
|
||||
<div class="card bg-base-100 card-border shadow h-full flex flex-col">
|
||||
<div class="card-header bg-base-200 p-4">
|
||||
<span class="badge badge-secondary rounded-full">{{ strategy.payment_currency.name }}</span> x <span
|
||||
class="badge badge-secondary rounded-full">{{ strategy.target_currency.name }}</span>
|
||||
@@ -28,7 +25,7 @@
|
||||
<div class="text-base-content/60">{{ strategy.notes }}</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="card-footer bg-base-200 p-4 text-right">
|
||||
<div class="card-footer bg-base-200 p-4 text-right cursor-pointer">
|
||||
<a class="no-underline text-base-content/60 p-1"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Edit" %}"
|
||||
@@ -36,7 +33,7 @@
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-pencil fa-fw"></i>
|
||||
</a>
|
||||
<a class="text-error no-underline p-1"
|
||||
<a class="text-error no-underline p-1 cursor-pointer"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'dca_strategy_delete' strategy_id=strategy.id %}"
|
||||
@@ -49,14 +46,14 @@
|
||||
<i class="fa-solid fa-trash fa-fw"></i>
|
||||
</a>
|
||||
{% if not strategy.owner %}
|
||||
<a class="text-primary no-underline p-1"
|
||||
<a class="text-primary no-underline p-1 cursor-pointer"
|
||||
role="button"
|
||||
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 %}
|
||||
{% if user == strategy.owner %}
|
||||
<a class="text-primary no-underline p-1"
|
||||
<a class="text-primary no-underline p-1 cursor-pointer"
|
||||
role="button"
|
||||
hx-target="#generic-offcanvas"
|
||||
data-tippy-content="{% translate "Share" %}"
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entity in entities %}
|
||||
<tr class="entity">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -28,7 +28,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
hx-swap="innerHTML"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<table class="table table-hover whitespace-nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Date' %}</th>
|
||||
<th scope="col">{% translate 'Pairing' %}</th>
|
||||
<th scope="col">{% translate 'Rate' %}</th>
|
||||
@@ -15,7 +15,7 @@
|
||||
<tbody>
|
||||
{% for exchange_rate in page_obj %}
|
||||
<tr class="exchange-rate">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -24,7 +24,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'exchange_rate_delete' pk=exchange_rate.id %}"
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col" class="w-auto">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Service' %}</th>
|
||||
<th scope="col">{% translate 'Targeting' %}</th>
|
||||
@@ -37,7 +37,7 @@
|
||||
<tbody>
|
||||
{% for service in services %}
|
||||
<tr class="services">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -45,7 +45,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'automatic_exchange_rate_delete' pk=service.id %}"
|
||||
@@ -57,9 +57,9 @@
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="w-auto">{% if service.is_active %}<i class="fa-solid fa-circle text-success"></i>{% else %}
|
||||
<td class="table-col-auto">{% if service.is_active %}<i class="fa-solid fa-circle text-success"></i>{% else %}
|
||||
<i class="fa-solid fa-circle text-error"></i>{% endif %}</td>
|
||||
<td class="w-auto">{{ service.name }}</td>
|
||||
<td class="table-col-auto">{{ service.name }}</td>
|
||||
<td>{{ service.get_service_type_display }}</td>
|
||||
<td>{{ service.target_currencies.count }} {% trans 'currencies' %}, {{ service.target_accounts.count }} {% trans 'accounts' %}</td>
|
||||
<td>{{ service.last_fetch|date:"SHORT_DATETIME_FORMAT" }}</td>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<table class="table table-hover whitespace-nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Date' %}</th>
|
||||
<th scope="col">{% translate 'Pairing' %}</th>
|
||||
<th scope="col">{% translate 'Rate' %}</th>
|
||||
@@ -15,7 +15,7 @@
|
||||
<tbody>
|
||||
{% for exchange_rate in page_obj %}
|
||||
<tr class="exchange-rate">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -24,7 +24,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'exchange_rate_delete' pk=exchange_rate.id %}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% load i18n %}
|
||||
<div class="offcanvas-header flex justify-between items-center border-b border-base-content/10">
|
||||
<h5 class="offcanvas-title font-medium text-xl">{% block title %}{% endblock %}</h5>
|
||||
<h5 class="offcanvas-title font-medium">{% block title %}{% endblock %}</h5>
|
||||
<button type="button" class="btn btn-ghost btn-sm btn-circle" aria-label="{% trans 'Close' %}" data-bs-dismiss="offcanvas"><i class="fa-solid fa-xmark"></i></button>
|
||||
</div>
|
||||
<div id="generic-offcanvas-body" class="offcanvas-body"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<table class="table table-hover whitespace-nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Version' %}</th>
|
||||
</tr>
|
||||
@@ -37,7 +37,7 @@
|
||||
<tbody>
|
||||
{% for profile in profiles %}
|
||||
<tr class="profile">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -57,7 +57,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'import_profile_delete' profile_id=profile.id %}"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="lg:hidden flex justify-between items-center p-4 text-base-content">
|
||||
<div class="lg:hidden flex justify-between items-center p-4 text-base-content border-b border-base-content/10">
|
||||
<a href="{% url 'index' %}" class="flex justify-start no-underline">
|
||||
<div class="logo"></div>
|
||||
<span class="text-2xl font-bold ml-3">WYGIWYH</span>
|
||||
@@ -44,7 +44,7 @@
|
||||
aria-label={% translate 'Close' %}><i class="fa-solid fa-xmark"></i></button>
|
||||
</div>
|
||||
|
||||
<ul class="list-none p-3 flex flex-col gap-1 whitespace-nowrap lg:group-hover:animate-[disable-pointer-events] overflow-y-auto lg:overflow-y-hidden lg:hover:overflow-y-auto overflow-x-hidden"
|
||||
<ul class="sidebar-item-list list-none p-3 flex flex-col gap-1 whitespace-nowrap lg:group-hover:animate-[disable-pointer-events]"
|
||||
style="animation-duration: 100ms">
|
||||
|
||||
<c-components.sidebar-menu-item
|
||||
@@ -133,9 +133,7 @@
|
||||
icon="fa-solid fa-money-bill-transfer">
|
||||
</c-components.sidebar-menu-item>
|
||||
|
||||
<div>
|
||||
<hr class="hr">
|
||||
</div>
|
||||
<c-components.sidebar-menu-header title=""></c-components.sidebar-menu-header>
|
||||
|
||||
<div role="button"
|
||||
data-bs-toggle="collapse"
|
||||
@@ -156,10 +154,13 @@
|
||||
class="bs collapse p-0 absolute bottom-0 left-0 w-full z-30 max-h-dvh {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index||users_index' css_class="show" %}">
|
||||
<div class="h-dvh bg-base-300 flex flex-col">
|
||||
<div
|
||||
class="justify-between items-center p-4 border-b border-base-content/10 sidebar-submenu-header text-base-content">
|
||||
<h5 class="text-lg font-semibold text-base-content m-0">
|
||||
{% trans 'Management' %}
|
||||
</h5>
|
||||
class="items-center p-4 border-b border-base-content/10 sidebar-submenu-header text-base-content">
|
||||
<div class="flex items-center sidebar-submenu-title">
|
||||
<i class="fa-solid fa-toolbox fa-fw lg:group-hover:me-2 me-2 lg:me-0"></i>
|
||||
<h5 class="text-lg font-semibold text-base-content m-0">
|
||||
{% trans 'Management' %}
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-ghost btn-sm btn-circle" aria-label="{% trans 'Close' %}"
|
||||
data-bs-toggle="collapse"
|
||||
@@ -170,7 +171,7 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul class="list-none p-3 flex flex-col gap-1 whitespace-nowrap lg:group-hover:animate-[disable-pointer-events] overflow-y-auto lg:overflow-y-hidden lg:hover:overflow-y-auto overflow-x-hidden"
|
||||
<ul class="sidebar-item-list list-none p-3 flex flex-col gap-1 whitespace-nowrap lg:group-hover:animate-[disable-pointer-events] overflow-y-auto lg:overflow-y-hidden lg:hover:overflow-y-auto overflow-x-hidden"
|
||||
style="animation-duration: 100ms">
|
||||
<c-components.sidebar-menu-header title="{% translate 'Transactions' %}"></c-components.sidebar-menu-header>
|
||||
<c-components.sidebar-menu-item
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div id="toasts">
|
||||
<div class="toast toast-top toast-end toast-container" hx-trigger="load, updated from:window, toasts from:window" hx-get="{% url 'toasts' %}" hx-swap="beforeend">
|
||||
<div class="toast toast-top toast-end toast-container z-1050" hx-trigger="load, updated from:window, toasts from:window" hx-get="{% url 'toasts' %}" hx-swap="beforeend">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
{% load i18n %}
|
||||
<c-ui.fab-single-action
|
||||
url="{% url 'installment_plan_add' %}"
|
||||
hx_target="#generic-offcanvas">
|
||||
</c-ui.fab-single-action>
|
||||
<div class="container px-md-3 py-3 column-gap-5">
|
||||
<div class="text-3xl font-bold font-mono w-full mb-3">
|
||||
{% spaceless %}
|
||||
<div>{% translate 'Installment Plans' %}<span>
|
||||
<a class="no-underline text-2xl p-1 category-action"
|
||||
role="button"
|
||||
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>
|
||||
</span></div>
|
||||
<div>{% translate 'Installment Plans' %}</div>
|
||||
{% endspaceless %}
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-header bg-base-200 p-4">
|
||||
<div role="tablist" class="tabs tabs-lifted">
|
||||
<button class="tab tab-active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'active_installment_plans_list' %}" hx-trigger="load, click" hx-target="#installment-plans-table">{% translate 'All' %}</button>
|
||||
<button class="tab" hx-get="{% url 'finished_installment_plans_list' %}" hx-target="#installment-plans-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Finished' %}</button>
|
||||
<div class="card-header bg-base-200 p-4 rounded-box">
|
||||
<div role="tablist" class="tabs tabs-border">
|
||||
<input type="radio" name="installment_plan_tabs" class="tab" aria-label="{% translate 'Active' %}" checked="checked"
|
||||
hx-get="{% url 'active_installment_plans_list' %}" hx-trigger="load, click" hx-target="#installment-plans-table"
|
||||
hx-indicator="#installment-plans-table" />
|
||||
<input type="radio" name="installment_plan_tabs" class="tab" aria-label="{% translate 'Finished' %}"
|
||||
hx-get="{% url 'finished_installment_plans_list' %}" hx-trigger="click" hx-target="#installment-plans-table" hx-indicator="#installment-plans-table" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div id="installment-plans-table"></div>
|
||||
<div id="installment-plans-table" class="show-loading"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Account' %}</th>
|
||||
<th scope="col">{% translate 'Amount' %}</th>
|
||||
@@ -21,7 +21,7 @@
|
||||
<tbody>
|
||||
{% for installment_plan in installment_plans %}
|
||||
<tr class="installment-plan">
|
||||
<td class="w-auto text-center">
|
||||
<td class="table-col-auto text-center">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -37,7 +37,7 @@
|
||||
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"
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Refresh" %}"
|
||||
hx-get="{% url 'installment_plan_refresh' installment_plan_id=installment_plan.id %}"
|
||||
@@ -49,7 +49,7 @@
|
||||
data-confirm-text="{% translate "Yes, refresh it!" %}"
|
||||
_="install prompt_swal">
|
||||
<i class="fa-solid fa-arrows-rotate fa-fw"></i></a>
|
||||
<a class="btn btn-secondary btn-sm join-item text-error"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'installment_plan_delete' installment_plan_id=installment_plan.id %}"
|
||||
@@ -62,7 +62,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="{% if installment_plan.type == 'EX' %}text-red-400{% else %}text-green-400{% endif %}">
|
||||
<div class="{% if installment_plan.type == 'EX' %}text-error{% else %}text-success{% endif %}">
|
||||
{{ installment_plan.description }}
|
||||
</div>
|
||||
<div class="text-sm text-base-content/60">{{ installment_plan.notes|linebreaksbr }}</div>
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
<div class="text-3xl font-bold font-mono w-full mb-3">
|
||||
<div>{% translate 'Unit Price Calculator' %}</div>
|
||||
</div>
|
||||
<div class="card bg-base-100 shadow-xl mb-3 hidden" id="card-placeholder">
|
||||
<div class="card-header bg-base-200 p-4 flex flex-row justify-between">
|
||||
<h5 class="title flex-grow"></h5>
|
||||
<button class="btn btn-secondary btn-sm text-error"
|
||||
<div class="card bg-base-100 shadow mb-3 hidden" id="card-placeholder">
|
||||
<div class="card-header bg-base-200 p-4 flex flex-row justify-between rounded-box">
|
||||
<h5 class="title grow"></h5>
|
||||
<button class="btn btn-error btn-sm"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
_="on click remove the closest .card to me then trigger update on #items then trigger tooltips on body">
|
||||
@@ -21,21 +21,23 @@
|
||||
<div class="card-body">
|
||||
<div class="grid lg:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<div>
|
||||
<label for="price" class="label">{% trans 'Item price' %}</label>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Item price' %}</legend>
|
||||
<input type="number" inputmode="decimal" class="input input-bordered w-full item-price" id="price">
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<label for="amount" class="label">{% trans 'Item amount' %}</label>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Item amount' %}</legend>
|
||||
<input type="number" inputmode="decimal" class="input input-bordered w-full item-amount" id="amount">
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label">{% trans 'Unit price' %}</label>
|
||||
<div class="unit-price text-xl" data-amount="0">0</div>
|
||||
</div>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Unit price' %}</legend>
|
||||
<div class="unit-price text-xl" data-amount="0">0</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,59 +91,63 @@
|
||||
end
|
||||
end
|
||||
end">
|
||||
<div class="card bg-base-100 shadow-xl mb-3">
|
||||
<div class="card-header bg-base-200 p-4">
|
||||
<div class="card bg-base-100 shadow mb-3">
|
||||
<div class="card-header bg-base-200 p-4 flex flex-row justify-between rounded-box">
|
||||
<h5>{% trans "Item" %} A</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid lg:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<div>
|
||||
<label for="price" class="label">{% trans 'Item price' %}</label>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Item price' %}</legend>
|
||||
<input type="number" inputmode="decimal" class="input input-bordered w-full item-price" id="price">
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<label for="amount" class="label">{% trans 'Item amount' %}</label>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Item amount' %}</legend>
|
||||
<input type="number" inputmode="decimal" class="input input-bordered w-full item-amount" id="amount">
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label">{% trans 'Unit price' %}</label>
|
||||
<div class="unit-price text-xl" data-amount="0">0</div>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Unit price' %}</legend>
|
||||
<div class="unit-price text-xl" data-amount="0">0</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card bg-base-100 shadow-xl mb-3">
|
||||
<div class="card-header bg-base-200 p-4">
|
||||
<div class="card bg-base-100 shadow mb-3">
|
||||
<div class="card-header bg-base-200 p-4 flex flex-row justify-between rounded-box">
|
||||
<h5>{% trans "Item" %} B</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid lg:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<div>
|
||||
<label for="price" class="label">{% trans 'Item price' %}</label>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Item price' %}</legend>
|
||||
<input type="number" inputmode="decimal" class="input input-bordered w-full item-price" id="price">
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<label for="amount" class="label">{% trans 'Item amount' %}</label>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Item amount' %}</legend>
|
||||
<input type="number" inputmode="decimal" class="input input-bordered w-full item-amount" id="amount">
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label">{% trans 'Unit price' %}</label>
|
||||
<div class="unit-price text-xl" data-amount="0">0</div>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">{% trans 'Unit price' %}</legend>
|
||||
<div class="unit-price text-xl" data-amount="0">0</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid lg:grid-cols-[2fr_1fr] gap-3 mt-3">
|
||||
<div class="grid lg:grid-cols-[2fr_1fr] gap-3 mt-6">
|
||||
<div>
|
||||
<button class="btn btn-primary w-full"
|
||||
_="on click
|
||||
|
||||
@@ -127,36 +127,37 @@
|
||||
when its textContent.toLowerCase() contains my value.toLowerCase()">
|
||||
|
||||
{# Order by icon dropdown #}
|
||||
<div class="dropdown dropdown-end">
|
||||
<button tabindex="0" class="btn btn-secondary join-item" type="button"
|
||||
<div>
|
||||
<button class="btn btn-secondary join-item" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false"
|
||||
title="{% translate 'Order by' %}">
|
||||
<i class="fa-solid fa-sort fa-fw"></i>
|
||||
</button>
|
||||
<ul tabindex="0" class="dropdown-content menu bg-base-300 rounded-box z-1 w-62 p-2 shadow-md mt-1">
|
||||
<ul class="dropdown-menu dropdown-menu-end menu w-max relative">
|
||||
<li>
|
||||
<button class="{% if order == 'default' %}menu-active{% endif %}" type="button"
|
||||
_="on click remove .menu-active from <li > button/> in the closest <ul/>
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'default'
|
||||
then trigger change on #order">
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'default'
|
||||
then trigger change on #order">
|
||||
{% translate 'Default' %}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="{% if order == 'older' %}menu-active{% endif %}" type="button"
|
||||
_="on click remove .menu-active from <li > button/> in the closest <ul/>
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'older'
|
||||
then trigger change on #order">
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'older'
|
||||
then trigger change on #order">
|
||||
{% translate 'Oldest first' %}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="{% if order == 'newer' %}menu-active{% endif %}" type="button"
|
||||
_="on click remove .menu-active from <li > button/> in the closest <ul/>
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'newer'
|
||||
then trigger change on #order">
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'newer'
|
||||
then trigger change on #order">
|
||||
{% translate 'Newest first' %}
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Account' %}</th>
|
||||
<th scope="col">{% translate 'Amount' %}</th>
|
||||
@@ -18,7 +18,7 @@
|
||||
<tbody>
|
||||
{% for qt in quick_transactions %}
|
||||
<tr class="recurring_transaction">
|
||||
<td class="w-auto text-center">
|
||||
<td class="table-col-auto text-center">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -27,7 +27,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'quick_transaction_delete' quick_transaction_id=qt.id %}"
|
||||
@@ -42,14 +42,14 @@
|
||||
</td>
|
||||
<td>
|
||||
<div
|
||||
class="{% if qt.type == 'EX' %}text-red-400{% else %}text-green-400{% endif %}">
|
||||
class="{% if qt.type == 'EX' %}text-error{% else %}text-success{% endif %}">
|
||||
{{ qt.name }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="w-auto">
|
||||
<td>
|
||||
{% if qt.account.group %}{{ qt.account.group }} • {% endif %}{{ qt.account }}
|
||||
</td>
|
||||
<td class="w-auto">
|
||||
<td>
|
||||
<c-amount.display
|
||||
:amount="qt.amount"
|
||||
:prefix="qt.account.currency.prefix"
|
||||
|
||||
@@ -5,17 +5,14 @@
|
||||
{% block title %}{% translate 'Quick Transactions' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<c-ui.fab-single-action
|
||||
url="{% url 'quick_transaction_add' %}"
|
||||
hx_target="#generic-offcanvas">
|
||||
</c-ui.fab-single-action>
|
||||
<div class="container px-md-3 py-3 column-gap-5">
|
||||
<div class="text-3xl font-bold font-mono w-full mb-3">
|
||||
{% spaceless %}
|
||||
<div>{% translate 'Quick Transactions' %}<span>
|
||||
<a class="no-underline text-2xl p-1 category-action"
|
||||
role="button"
|
||||
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>
|
||||
</span></div>
|
||||
<div>{% translate 'Quick Transactions' %}</div>
|
||||
{% endspaceless %}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
{% load i18n %}
|
||||
<c-ui.fab-single-action
|
||||
url="{% url 'recurring_transaction_add' %}"
|
||||
hx_target="#generic-offcanvas">
|
||||
</c-ui.fab-single-action>
|
||||
<div class="container px-md-3 py-3 column-gap-5">
|
||||
<div class="text-3xl font-bold font-mono w-full mb-3">
|
||||
{% spaceless %}
|
||||
<div>{% translate 'Recurring Transactions' %}<span>
|
||||
<a class="no-underline text-2xl p-1 category-action"
|
||||
role="button"
|
||||
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>
|
||||
</span></div>
|
||||
<div>{% translate 'Recurring Transactions' %}</div>
|
||||
{% endspaceless %}
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-header bg-base-200 p-4">
|
||||
<div role="tablist" class="tabs tabs-lifted">
|
||||
<button class="tab tab-active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'active_recurring_transaction_list' %}" hx-trigger="load, click" hx-target="#recurring-transactions-table">{% translate 'Active' %}</button>
|
||||
<button class="tab" hx-get="{% url 'paused_recurring_transaction_list' %}" hx-target="#recurring-transactions-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Paused' %}</button>
|
||||
<button class="tab" hx-get="{% url 'finished_recurring_transaction_list' %}" hx-target="#recurring-transactions-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Finished' %}</button>
|
||||
<div role="tablist" class="tabs tabs-border">
|
||||
<input type="radio" name="installment_plan_tabs" class="tab" aria-label="{% translate 'Active' %}" checked="checked"
|
||||
hx-get="{% url 'active_recurring_transaction_list' %}" hx-trigger="load, click" hx-target="#recurring-transactions-table" hx-indicator="#recurring-transactions-table" />
|
||||
<input type="radio" name="installment_plan_tabs" class="tab" aria-label="{% translate 'Paused' %}"
|
||||
hx-get="{% url 'paused_recurring_transaction_list' %}" hx-trigger="click" hx-target="#recurring-transactions-table" hx-indicator="#recurring-transactions-table" />
|
||||
<input type="radio" name="installment_plan_tabs" class="tab" aria-label="{% translate 'Finished' %}"
|
||||
hx-get="{% url 'finished_recurring_transaction_list' %}" hx-trigger="click" hx-target="#recurring-transactions-table" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div id="recurring-transactions-table"></div>
|
||||
<div id="recurring-transactions-table" class="show-loading"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Account' %}</th>
|
||||
<th scope="col">{% translate 'Amount' %}</th>
|
||||
@@ -23,7 +23,7 @@
|
||||
<tbody>
|
||||
{% for recurring_transaction in recurring_transactions %}
|
||||
<tr class="recurring_transaction">
|
||||
<td class="w-auto text-center">
|
||||
<td class="table-col-auto text-center">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -41,7 +41,7 @@
|
||||
<i class="fa-solid fa-eye fa-fw"></i></a>
|
||||
{% if status != 'finished' %}
|
||||
{% if recurring_transaction.is_paused %}
|
||||
<a class="btn btn-secondary btn-sm join-item text-info"
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Unpause" %}"
|
||||
hx-get="{% url 'recurring_transaction_toggle_pause' recurring_transaction_id=recurring_transaction.id %}"
|
||||
@@ -54,7 +54,7 @@
|
||||
data-confirm-text="{% translate "Yes, unpause it!" %}"
|
||||
_="install prompt_swal"><i class="fa-solid fa-play fa-fw"></i></a>
|
||||
{% else %}
|
||||
<a class="btn btn-secondary btn-sm join-item text-info"
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Pause" %}"
|
||||
hx-get="{% url 'recurring_transaction_toggle_pause' recurring_transaction_id=recurring_transaction.id %}"
|
||||
@@ -68,7 +68,7 @@
|
||||
_="install prompt_swal">
|
||||
<i class="fa-solid fa-pause fa-fw"></i></a>
|
||||
{% endif %}
|
||||
<a class="btn btn-secondary btn-sm join-item text-info"
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Finish" %}"
|
||||
hx-get="{% url 'recurring_transaction_finish' recurring_transaction_id=recurring_transaction.id %}"
|
||||
@@ -82,7 +82,7 @@
|
||||
_="install prompt_swal">
|
||||
<i class="fa-solid fa-flag-checkered fa-fw"></i></a>
|
||||
{% endif %}
|
||||
<a class="btn btn-secondary btn-sm join-item text-error"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'recurring_transaction_delete' recurring_transaction_id=recurring_transaction.id %}"
|
||||
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="{% if recurring_transaction.type == 'EX' %}text-red-400{% else %}text-green-400{% endif %}">
|
||||
<div class="{% if recurring_transaction.type == 'EX' %}text-error{% else %}text-success{% endif %}">
|
||||
{{ recurring_transaction.description }}
|
||||
</div>
|
||||
<div class="text-sm text-base-content/60">{{ recurring_transaction.notes|linebreaksbr }}</div>
|
||||
|
||||
@@ -20,16 +20,16 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="w-auto">{% translate 'Order' %}</th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col" class="table-col-auto">{% translate 'Order' %}</th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for rule in transaction_rules %}
|
||||
<tr class="transaction_rule">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -37,7 +37,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'transaction_rule_delete' transaction_rule_id=rule.id %}"
|
||||
@@ -65,7 +65,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<a class="no-underline"
|
||||
role="button"
|
||||
data-tippy-content="
|
||||
@@ -75,7 +75,7 @@
|
||||
<i class="fa-solid fa-toggle-off text-red-400"></i>{% endif %}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<td class="table-col-auto text-center">
|
||||
<div>{{ rule.order }}</div>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for tag in tags %}
|
||||
<tr class="tag">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
@@ -28,7 +28,7 @@
|
||||
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"
|
||||
<a class="btn btn-error btn-sm join-item"
|
||||
role="button"
|
||||
hx-swap="innerHTML"
|
||||
data-tippy-content="{% translate "Delete" %}"
|
||||
|
||||
@@ -78,36 +78,38 @@
|
||||
when its textContent.toLowerCase() contains my value.toLowerCase()">
|
||||
|
||||
{# Order by icon dropdown #}
|
||||
<div class="dropdown dropdown-end">
|
||||
<button tabindex="0" class="btn btn-secondary join-item" type="button"
|
||||
{# Order by icon dropdown #}
|
||||
<div>
|
||||
<button class="btn btn-secondary join-item" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false"
|
||||
title="{% translate 'Order by' %}">
|
||||
<i class="fa-solid fa-sort fa-fw"></i>
|
||||
</button>
|
||||
<ul tabindex="0" class="dropdown-content menu bg-base-300 rounded-box z-1 w-62 p-2 shadow-md mt-1">
|
||||
<ul class="dropdown-menu dropdown-menu-end menu w-max relative">
|
||||
<li>
|
||||
<button class="{% if order == 'default' %}menu-active{% endif %}" type="button"
|
||||
_="on click remove .menu-active from <li > button/> in the closest <ul/>
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'default'
|
||||
then trigger change on #order">
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'default'
|
||||
then trigger change on #order">
|
||||
{% translate 'Default' %}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="{% if order == 'older' %}menu-active{% endif %}" type="button"
|
||||
_="on click remove .menu-active from <li > button/> in the closest <ul/>
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'older'
|
||||
then trigger change on #order">
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'older'
|
||||
then trigger change on #order">
|
||||
{% translate 'Oldest first' %}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="{% if order == 'newer' %}menu-active{% endif %}" type="button"
|
||||
_="on click remove .menu-active from <li > button/> in the closest <ul/>
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'newer'
|
||||
then trigger change on #order">
|
||||
then add .menu-active to me
|
||||
then set the value of #order to 'newer'
|
||||
then trigger change on #order">
|
||||
{% translate 'Newest first' %}
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-auto"></th>
|
||||
<th scope="col" class="table-col-auto"></th>
|
||||
<th scope="col">{% translate 'Active' %}</th>
|
||||
<th scope="col">{% translate 'Name' %}</th>
|
||||
<th scope="col">{% translate 'Email' %}</th>
|
||||
@@ -33,7 +33,7 @@
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr class="tag">
|
||||
<td class="w-auto">
|
||||
<td class="table-col-auto">
|
||||
<div class="join" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm join-item"
|
||||
role="button"
|
||||
|
||||
@@ -23,10 +23,11 @@ window.TomSelect = function createDynamicTomSelect(element) {
|
||||
},
|
||||
},
|
||||
|
||||
onInitialize: function () {
|
||||
onDropdownOpen: function () {
|
||||
// Move dropdown to body to escape stacking context issues
|
||||
document.body.appendChild(this.dropdown);
|
||||
|
||||
|
||||
this.popper = Popper.createPopper(this.control, this.dropdown, {
|
||||
placement: "bottom-start",
|
||||
strategy: "fixed",
|
||||
@@ -58,11 +59,9 @@ window.TomSelect = function createDynamicTomSelect(element) {
|
||||
});
|
||||
|
||||
},
|
||||
onDropdownOpen: function () {
|
||||
this.popper.update();
|
||||
},
|
||||
onDropdownClose: function () {
|
||||
// Optional: move back to wrapper to keep DOM clean, but not necessary
|
||||
this.popper.destroy();
|
||||
this.dropdown.remove();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -81,15 +81,14 @@
|
||||
position: relative;
|
||||
top: 0;
|
||||
min-height: 100px;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: -10px;
|
||||
right: -10px;
|
||||
bottom: -10px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
backdrop-filter: blur(4px);
|
||||
z-index: 100;
|
||||
animation: fade-in 0.1s ease-in forwards;
|
||||
@@ -110,7 +109,7 @@
|
||||
animation: spin 1s linear infinite, fade-in 0.1s ease-in forwards;
|
||||
animation-delay: 200ms;
|
||||
opacity: 0;
|
||||
z-index: 9999;
|
||||
z-index: 101;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ $offcanvas-z-index: 1090 !default;
|
||||
$offcanvas-backdrop-z-index: 1040 !default;
|
||||
$offcanvas-width: 400px !default;
|
||||
$offcanvas-height: 30vh !default;
|
||||
$offcanvas-padding: 1rem !default;
|
||||
$offcanvas-padding: 0.5rem !default;
|
||||
$offcanvas-transition-duration: 0.3s !default;
|
||||
$offcanvas-backdrop-opacity: 0.5 !default;
|
||||
|
||||
|
||||
@@ -168,6 +168,10 @@
|
||||
@apply text-base-content/60; /* .hr */
|
||||
@apply my-3;
|
||||
}
|
||||
|
||||
.table-col-auto {
|
||||
@apply w-1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,19 +248,31 @@
|
||||
}
|
||||
|
||||
.sidebar-submenu-header {
|
||||
@apply flex;
|
||||
@apply flex justify-between;
|
||||
}
|
||||
|
||||
.sidebar-submenu-title {
|
||||
@apply flex items-center;
|
||||
}
|
||||
|
||||
.sidebar-floating .sidebar-submenu-header {
|
||||
@apply lg:hidden lg:group-hover:flex;
|
||||
@apply lg:justify-center lg:group-hover:justify-between;
|
||||
}
|
||||
|
||||
.sidebar-floating .sidebar-submenu-header h5 {
|
||||
@apply lg:invisible lg:group-hover:visible;
|
||||
.sidebar-floating .sidebar-submenu-title {
|
||||
@apply lg:h-8;
|
||||
}
|
||||
|
||||
.sidebar-floating .sidebar-submenu-title i {
|
||||
@apply lg:me-0 lg:group-hover:me-2;
|
||||
}
|
||||
|
||||
.sidebar-floating .sidebar-submenu-title h5 {
|
||||
@apply lg:invisible lg:w-0 lg:h-0 lg:overflow-hidden lg:group-hover:visible lg:group-hover:w-auto lg:group-hover:h-auto;
|
||||
}
|
||||
|
||||
.sidebar-floating .sidebar-submenu-header button {
|
||||
@apply lg:hidden lg:group-hover:inline;
|
||||
@apply lg:hidden! lg:group-hover:flex!;
|
||||
}
|
||||
|
||||
.sidebar-floating .list-unstyled {
|
||||
@@ -267,6 +283,10 @@
|
||||
@apply text-wrap lg:text-nowrap ;
|
||||
}
|
||||
|
||||
.sidebar-floating .sidebar-item-list {
|
||||
@apply overflow-y-auto lg:overflow-y-hidden lg:group-hover:overflow-y-auto overflow-x-hidden;
|
||||
}
|
||||
|
||||
.sidebar-fixed {
|
||||
/* Sets the fixed, expanded width for the container */
|
||||
@apply lg:w-[17%] transition-all duration-100;
|
||||
@@ -277,6 +297,10 @@
|
||||
@apply lg:w-[17%] transition-all duration-100;
|
||||
}
|
||||
|
||||
.sidebar-fixed .sidebar-item-list {
|
||||
@apply overflow-y-auto overflow-x-hidden;
|
||||
}
|
||||
|
||||
.sidebar-fixed + main {
|
||||
/* Adjusts the main content margin to account for the expanded sidebar */
|
||||
@apply lg:ml-[17%] transition-all duration-100;
|
||||
@@ -314,7 +338,19 @@
|
||||
|
||||
.sidebar-fixed .sidebar-submenu-header {
|
||||
/* Ensures menu headers are always visible */
|
||||
@apply lg:flex;
|
||||
@apply lg:flex lg:justify-between;
|
||||
}
|
||||
|
||||
.sidebar-fixed .sidebar-submenu-title i {
|
||||
@apply me-2!;
|
||||
}
|
||||
|
||||
.sidebar-fixed .sidebar-submenu-title h5 {
|
||||
@apply lg:block;
|
||||
}
|
||||
|
||||
.sidebar-fixed .sidebar-submenu-header button {
|
||||
@apply lg:inline;
|
||||
}
|
||||
|
||||
.sidebar-fixed .list-unstyled {
|
||||
|
||||
Reference in New Issue
Block a user