feat: automated replacement

This commit is contained in:
Herculino Trotta
2025-10-28 14:13:30 -03:00
parent dd82289488
commit e600d87968
167 changed files with 4442 additions and 2503 deletions

2
.gitignore vendored
View File

@@ -160,3 +160,5 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear # and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/ .idea/
node_modules/

7
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"djlint.showInstallError": false,
"files.associations": {
"*.css": "tailwindcss"
},
"tailwindCSS.experimental.configFile": "frontend/src/styles/tailwind.css",
}

View File

@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.1/ref/settings/
""" """
import os import os
import re
import sys import sys
from pathlib import Path from pathlib import Path
@@ -46,7 +47,7 @@ INSTALLED_APPS = [
"django.contrib.sites", "django.contrib.sites",
"whitenoise.runserver_nostatic", "whitenoise.runserver_nostatic",
"django.contrib.staticfiles", "django.contrib.staticfiles",
"webpack_boilerplate", "django_vite",
"django.contrib.humanize", "django.contrib.humanize",
"django.contrib.postgres", "django.contrib.postgres",
"django_browser_reload", "django_browser_reload",
@@ -128,6 +129,14 @@ STORAGES = {
WHITENOISE_MANIFEST_STRICT = False WHITENOISE_MANIFEST_STRICT = False
def immutable_file_test(path, url):
# Match vite (rollup)-generated hashes, à la, `some_file-CSliV9zW.js`
return re.match(r"^.+[.-][0-9a-zA-Z_-]{8,12}\..+$", url)
WHITENOISE_IMMUTABLE_FILE_TEST = immutable_file_test
WSGI_APPLICATION = "WYGIWYH.wsgi.application" WSGI_APPLICATION = "WYGIWYH.wsgi.application"
@@ -289,7 +298,7 @@ STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "static_files" STATIC_ROOT = BASE_DIR / "static_files"
STATICFILES_DIRS = [ STATICFILES_DIRS = [
ROOT_DIR / "frontend/build", ROOT_DIR / "frontend" / "build",
BASE_DIR / "static", BASE_DIR / "static",
] ]
@@ -305,9 +314,10 @@ CACHES = {
} }
} }
WEBPACK_LOADER = { DJANGO_VITE_ASSETS_PATH = ROOT_DIR / "frontend" / "build"
"MANIFEST_FILE": ROOT_DIR / "frontend/build/manifest.json", DJANGO_VITE_MANIFEST_PATH = DJANGO_VITE_ASSETS_PATH / "manifest.json"
} DJANGO_VITE_DEV_MODE = DEBUG
DJANGO_VITE_DEV_SERVER_PORT = 5173
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
@@ -354,8 +364,12 @@ ACCOUNT_ADAPTER = "allauth.account.adapter.DefaultAccountAdapter"
SOCIALACCOUNT_ADAPTER = "allauth.socialaccount.adapter.DefaultSocialAccountAdapter" SOCIALACCOUNT_ADAPTER = "allauth.socialaccount.adapter.DefaultSocialAccountAdapter"
# CRISPY FORMS # CRISPY FORMS
CRISPY_ALLOWED_TEMPLATE_PACKS = ["bootstrap5", "crispy_forms/pure_text"] CRISPY_ALLOWED_TEMPLATE_PACKS = [
CRISPY_TEMPLATE_PACK = "bootstrap5" "bootstrap5",
"crispy_forms/pure_text",
"crispy-daisyui",
]
CRISPY_TEMPLATE_PACK = "crispy-daisyui"
SESSION_EXPIRE_AT_BROWSER_CLOSE = False SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_COOKIE_AGE = int(os.getenv("SESSION_EXPIRY_TIME", 2678400)) # 31 days SESSION_COOKIE_AGE = int(os.getenv("SESSION_EXPIRY_TIME", 2678400)) # 31 days

View File

@@ -1,9 +1,9 @@
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Account Groups' %}<span> <div>{% translate 'Account Groups' %}<span>
<a class="text-decoration-none tw:text-2xl p-1 category-action" <a class="tw:no-underline tw:text-2xl tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -14,30 +14,30 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body table-responsive"> <div class="tw:card-body tw:overflow-x-auto">
{% if account_groups %} {% if account_groups %}
<c-config.search></c-config.search> <c-config.search></c-config.search>
<table class="table table-hover"> <table class="tw:table tw:table-hover">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th> <th scope="col">{% translate 'Name' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for account_group in account_groups %} {% for account_group in account_groups %}
<tr class="account_group"> <tr class="account_group">
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'account_group_edit' pk=account_group.id %}" hx-get="{% url 'account_group_edit' pk=account_group.id %}"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -49,7 +49,7 @@
data-confirm-text="{% translate "Yes, delete it!" %}" data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not account_group.owner %} {% if not account_group.owner %}
<a class="btn btn-secondary btn-sm text-warning" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-warning"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}" data-bs-title="{% translate "Take ownership" %}"
@@ -57,7 +57,7 @@
<i class="fa-solid fa-crown fa-fw"></i></a> <i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %} {% endif %}
{% if user == account_group.owner %} {% if user == account_group.owner %}
<a class="btn btn-secondary btn-sm text-primary" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-primary"
role="button" role="button"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-swap="innerHTML" hx-swap="innerHTML"
@@ -68,7 +68,7 @@
{% endif %} {% endif %}
</div> </div>
</td> </td>
<td class="col">{{ account_group.name }}</td> <td>{{ account_group.name }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@@ -9,65 +9,60 @@
<form hx-post="{% url 'account_reconciliation' %}"> <form hx-post="{% url 'account_reconciliation' %}">
{% csrf_token %} {% csrf_token %}
{{ form.management_form }} {{ form.management_form }}
<div class="accordion accordion-flush" id="balanceAccordionFlush"> <div class="tw:space-y-2" id="balanceAccordionFlush">
{% for form in form.forms %} {% for form in form.forms %}
<div class="accordion-item"> <div class="tw:collapse tw:collapse-arrow tw:bg-base-200">
<h2 class="accordion-header"> <input type="radio" name="my-accordion-flush" id="accordion-{{ forloop.counter0 }}" />
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" <label for="accordion-{{ forloop.counter0 }}" class="tw:collapse-title tw:text-base tw:font-medium">
data-bs-target="#flush-collapse-{{ forloop.counter0 }}" aria-expanded="false" {% if form.account_group %}<span class="tw:badge tw:badge-primary tw:me-2">{{ form.account_group.name }}</span>{% endif %}{{ form.account_name }}
aria-controls="flush-collapseOne"> </label>
{% if form.account_group %}<span class="badge text-bg-primary me-2">{{ form.account_group.name }}</span>{% endif %}{{ form.account_name }} <div class="tw:collapse-content">
</button> <div class="tw:mb-3">
</h2> <div class="tw:label">
<div id="flush-collapse-{{ forloop.counter0 }}" class="accordion-collapse collapse"> <span class="tw:label-text">{% translate 'Current balance' %}</span>
<div class="accordion-body">
<div class="mb-3">
<div class="form-label">
{% translate 'Current balance' %}
</div>
<div data-amount="{{ form.current_balance|floatformat:"-40u" }}"
data-decimal-places="{{ form.currency_decimal_places }}"
id="amount-{{ forloop.counter0 }}">
{% currency_display amount=form.current_balance prefix=form.currency_prefix suffix=form.currency_suffix decimal_places=form.currency_decimal_places %}
</div>
</div> </div>
<div> <div data-amount="{{ form.current_balance|floatformat:"-40u" }}"
{% crispy form %} data-decimal-places="{{ form.currency_decimal_places }}"
id="amount-{{ forloop.counter0 }}">
{% currency_display amount=form.current_balance prefix=form.currency_prefix suffix=form.currency_suffix decimal_places=form.currency_decimal_places %}
</div> </div>
<div class="mb-3"> </div>
<div class="form-label"> <div>
{% translate 'Difference' %} {% crispy form %}
</div> </div>
<div _="on input from #id_form-{{ forloop.counter0 }}-new_balance <div class="tw:mb-3">
set original_amount to parseFloat('{{ form.current_balance|floatformat:"-40u" }}') <div class="tw:label">
then set prefix to '{{ form.currency_prefix }}' <span class="tw:label-text">{% translate 'Difference' %}</span>
then set suffix to '{{ form.currency_suffix }}'
then set decimal_places to {{ form.currency_decimal_places }}
then call parseLocaleNumber(#id_form-{{ forloop.counter0 }}-new_balance.value)
then set new_amount to result
then set diff to (Math.round((new_amount - original_amount) * Math.pow(10, decimal_places))) / Math.pow(10, decimal_places)
then log diff
then set format_new_amount to
Intl.NumberFormat(
undefined,
{
minimumFractionDigits: decimal_places,
maximumFractionDigits: decimal_places,
roundingMode: 'trunc'
}
).format(diff)
then set formatted_string to `${prefix}${format_new_amount}${suffix}`
then put formatted_string into me if diff else
put '-' into me">-</div>
</div> </div>
<div _="on input from #id_form-{{ forloop.counter0 }}-new_balance
set original_amount to parseFloat('{{ form.current_balance|floatformat:"-40u" }}')
then set prefix to '{{ form.currency_prefix }}'
then set suffix to '{{ form.currency_suffix }}'
then set decimal_places to {{ form.currency_decimal_places }}
then call parseLocaleNumber(#id_form-{{ forloop.counter0 }}-new_balance.value)
then set new_amount to result
then set diff to (Math.round((new_amount - original_amount) * Math.pow(10, decimal_places))) / Math.pow(10, decimal_places)
then log diff
then set format_new_amount to
Intl.NumberFormat(
undefined,
{
minimumFractionDigits: decimal_places,
maximumFractionDigits: decimal_places,
roundingMode: 'trunc'
}
).format(diff)
then set formatted_string to `${prefix}${format_new_amount}${suffix}`
then put formatted_string into me if diff else
put '-' into me">-</div>
</div> </div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<div class="mt-3"> <div class="tw:mt-3">
<div> <div>
<input type="submit" name="submit" value="{% translate 'Reconcile balances' %}" class="btn btn-outline-primary w-100" id="submit-id-submit"> <input type="submit" name="submit" value="{% translate 'Reconcile balances' %}" class="tw:btn tw:btn-outline tw:btn-primary tw:w-full" id="submit-id-submit">
</div> </div>
</div> </div>
</form> </form>

View File

@@ -1,9 +1,9 @@
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Accounts' %}<span> <div>{% translate 'Accounts' %}<span>
<a class="text-decoration-none tw:text-2xl p-1 category-action" <a class="tw:no-underline tw:text-2xl tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -14,35 +14,35 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body table-responsive"> <div class="tw:card-body tw:overflow-x-auto">
{% if accounts %} {% if accounts %}
<c-config.search></c-config.search> <c-config.search></c-config.search>
<table class="table table-hover text-nowrap"> <table class="tw:table tw:table-hover tw:whitespace-nowrap">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th> <th scope="col">{% translate 'Name' %}</th>
<th scope="col" class="col">{% translate 'Group' %}</th> <th scope="col">{% translate 'Group' %}</th>
<th scope="col" class="col">{% translate 'Currency' %}</th> <th scope="col">{% translate 'Currency' %}</th>
<th scope="col" class="col">{% translate 'Exchange Currency' %}</th> <th scope="col">{% translate 'Exchange Currency' %}</th>
<th scope="col" class="col">{% translate 'Is Asset' %}</th> <th scope="col">{% translate 'Is Asset' %}</th>
<th scope="col" class="col">{% translate 'Archived' %}</th> <th scope="col">{% translate 'Archived' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for account in accounts %} {% for account in accounts %}
<tr class="account"> <tr class="account">
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'account_edit' pk=account.id %}" hx-get="{% url 'account_edit' pk=account.id %}"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -54,7 +54,7 @@
data-confirm-text="{% translate "Yes, delete it!" %}" data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not account.owner %} {% if not account.owner %}
<a class="btn btn-secondary btn-sm text-primary" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-primary"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}" data-bs-title="{% translate "Take ownership" %}"
@@ -62,7 +62,7 @@
<i class="fa-solid fa-crown fa-fw"></i></a> <i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %} {% endif %}
{% if user == account.owner %} {% if user == account.owner %}
<a class="btn btn-secondary btn-sm text-primary" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-primary"
role="button" role="button"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-swap="innerHTML" hx-swap="innerHTML"
@@ -71,7 +71,7 @@
hx-get="{% url 'account_share_settings' pk=account.id %}"> hx-get="{% url 'account_share_settings' pk=account.id %}">
<i class="fa-solid fa-share fa-fw"></i></a> <i class="fa-solid fa-share fa-fw"></i></a>
{% endif %} {% endif %}
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
hx-get="{% url 'account_toggle_untracked' pk=account.id %}" hx-get="{% url 'account_toggle_untracked' pk=account.id %}"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
@@ -84,12 +84,12 @@
</a> </a>
</div> </div>
</td> </td>
<td class="col">{{ account.name }}</td> <td>{{ account.name }}</td>
<td class="col">{{ account.group.name }}</td> <td>{{ account.group.name }}</td>
<td class="col">{{ account.currency }}</td> <td>{{ account.currency }}</td>
<td class="col">{% if account.exchange_currency %}{{ account.exchange_currency }}{% else %}-{% endif %}</td> <td>{% if account.exchange_currency %}{{ account.exchange_currency }}{% else %}-{% endif %}</td>
<td class="col">{% if account.is_asset %}<i class="fa-solid fa-solid fa-check text-success"></i>{% endif %}</td> <td>{% if account.is_asset %}<i class="fa-solid fa-solid fa-check tw:text-success"></i>{% endif %}</td>
<td class="col">{% if account.is_archived %}<i class="fa-solid fa-solid fa-check text-success"></i>{% endif %}</td> <td>{% if account.is_archived %}<i class="fa-solid fa-solid fa-check tw:text-success"></i>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@@ -2,40 +2,40 @@
{% load i18n %} {% load i18n %}
<div> <div>
<div class="tw:hidden tw:lg:grid tw:lg:grid-cols-7 tw:gap-4 tw:lg:gap-0"> <div class="tw:hidden tw:lg:grid tw:lg:grid-cols-7 tw:gap-4 tw:lg:gap-0 bg-base-300">
<div class="border-start border-top border-bottom p-2 text-center"> <div class="tw:border-l tw:border-t tw:border-b tw:border-base-100 tw:p-2 tw:text-center">
{% translate 'MON' %} {% translate 'MON' %}
</div> </div>
<div class="border-top border-bottom p-2 text-center"> <div class="tw:border-t tw:border-b tw:border-base-300 tw:p-2 tw:text-center">
{% translate 'TUE' %} {% translate 'TUE' %}
</div> </div>
<div class="border-top border-bottom p-2 text-center"> <div class="tw:border-t tw:border-b tw:border-base-300 tw:p-2 tw:text-center">
{% translate 'WED' %} {% translate 'WED' %}
</div> </div>
<div class="border-top border-bottom p-2 text-center"> <div class="tw:border-t tw:border-b tw:border-base-300 tw:p-2 tw:text-center">
{% translate 'THU' %} {% translate 'THU' %}
</div> </div>
<div class="border-top border-bottom p-2 text-center"> <div class="tw:border-t tw:border-b tw:border-base-300 tw:p-2 tw:text-center">
{% translate 'FRI' %} {% translate 'FRI' %}
</div> </div>
<div class="border-top border-bottom p-2 text-center"> <div class="tw:border-t tw:border-b tw:border-base-300 tw:p-2 tw:text-center">
{% translate 'SAT' %} {% translate 'SAT' %}
</div> </div>
<div class="border-end border-top border-bottom p-2 text-center"> <div class="tw:border-r tw:border-t tw:border-b tw:border-base-300 tw:p-2 tw:text-center">
{% translate 'SUN' %} {% translate 'SUN' %}
</div> </div>
</div> </div>
<div class="tw:grid tw:grid-cols-1 tw:grid-rows-1 tw:lg:grid-cols-7 tw:lg:grid-rows-6 tw:gap-4 tw:lg:gap-0"> <div class="tw:grid tw:grid-cols-1 tw:grid-rows-1 tw:lg:grid-cols-7 tw:lg:grid-rows-6 tw:gap-4 tw:lg:gap-0">
{% for date in dates %} {% for date in dates %}
{% if date %} {% if date %}
<div class="card h-100 tw:hover:bg-zinc-900! rounded-0{% if not date.transactions %} tw:hidden! tw:lg:flex!{% endif %}{% if today == date.date %} tw:border-yellow-300 border-primary{% endif %} " role="button" <div class="tw:card tw:bg-base-200 tw:h-full tw:hover:bg-base-300! tw:rounded-none tw:card-border tw:border-base-content/50 {% if not date.transactions %}tw:hidden! tw:lg:flex!{% endif %}{% if today == date.date %} tw:card-border tw:border-2 tw:border-primary{% endif %}" role="button"
hx-get="{% url 'calendar_transactions_list' day=date.date.day month=date.date.month year=date.date.year %}" hx-get="{% url 'calendar_transactions_list' day=date.date.day month=date.date.month year=date.date.year %}"
hx-target="#persistent-generic-offcanvas-left"> hx-target="#persistent-generic-offcanvas-left">
<div class="card-header border-0 bg-transparent text-end tw:flex justify-content-between p-2 w-100"> <div class="tw:card-header tw:border-0 tw:bg-transparent tw:text-end tw:flex tw:justify-between tw:p-2 tw:w-full">
<div class="tw:lg:hidden text-start w-100">{{ date.date|date:"l"|lower }}</div> <div class="tw:lg:hidden tw:text-start tw:w-full">{{ date.date|date:"l"|lower }}</div>
<div class="text-end w-100">{{ date.day }}</div> <div class="tw:text-end tw:w-full">{{ date.day }}</div>
</div> </div>
<div class="card-body p-2"> <div class="tw:card-body tw:p-2">
{% for transaction in date.transactions %} {% for transaction in date.transactions %}
{% if transaction.is_paid %} {% if transaction.is_paid %}
{% if transaction.type == "IN" and not transaction.account.is_asset %} {% if transaction.type == "IN" and not transaction.account.is_asset %}
@@ -62,7 +62,7 @@
</div> </div>
</div> </div>
{% else %} {% else %}
<div class="tw:hidden! tw:lg:block! card h-100 rounded-0"></div> <div class="tw:hidden! tw:lg:block! tw:card tw:bg-base-100 tw:h-full tw:rounded-none"></div>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>

View File

@@ -3,7 +3,6 @@
{% load i18n %} {% load i18n %}
{% load month_name %} {% load month_name %}
{% load static %} {% load static %}
{% load webpack_loader %}
{% block title %}{% translate 'Monthly Overview' %} :: {{ month|month_name }}/{{ year }}{% endblock %} {% block title %}{% translate 'Monthly Overview' %} :: {{ month|month_name }}/{{ year }}{% endblock %}
@@ -13,28 +12,28 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:gap-x-5">
<div class="row mb-3 gx-xl-4 gy-3 mb-4"> <div class="tw:flex tw:flex-wrap tw:mb-4 tw:gap-x-xl-4 tw:gap-y-3">
{# Date picker#} {# Date picker#}
<div class="col-12 col-xl-4 flex-row align-items-center d-flex"> <div class="tw:w-full tw:xl:w-4/12 tw:flex-row tw:items-center tw:flex">
<div class="tw:text-base h-100 align-items-center d-flex"> <div class="tw:text-base tw:h-full tw:items-center tw:flex">
<a role="button" <a role="button"
class="pe-4 py-2" class="tw:pe-4 tw:py-2"
hx-boost="true" hx-boost="true"
hx-trigger="click, previous_month from:window" hx-trigger="click, previous_month from:window"
href="{% url 'calendar' month=previous_month year=previous_year %}"><i href="{% url 'calendar' month=previous_month year=previous_year %}"><i
class="fa-solid fa-chevron-left"></i></a> class="fa-solid fa-chevron-left"></i></a>
</div> </div>
<div class="tw:text-3xl fw-bold font-monospace tw:w-full text-center" <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:text-center"
hx-get="{% url 'month_year_picker' %}" hx-get="{% url 'month_year_picker' %}"
hx-target="#generic-offcanvas-left" hx-target="#generic-offcanvas-left"
hx-trigger="click, date_picker from:window" hx-trigger="click, date_picker from:window"
hx-vals='{"month": {{ month }}, "year": {{ year }}, "for": "calendar", "field": "date"}' role="button"> hx-vals='{"month": {{ month }}, "year": {{ year }}, "for": "calendar", "field": "date"}' role="button">
{{ month|month_name }} {{ year }} {{ month|month_name }} {{ year }}
</div> </div>
<div class="tw:text-base mx-2 h-100 align-items-center d-flex"> <div class="tw:text-base tw:mx-2 tw:h-full tw:items-center tw:flex">
<a role="button" <a role="button"
class="ps-3 py-2" class="tw:ps-3 tw:py-2"
hx-boost="true" hx-boost="true"
hx-trigger="click, next_month from:window" hx-trigger="click, next_month from:window"
href="{% url 'calendar' month=next_month year=next_year %}"> href="{% url 'calendar' month=next_month year=next_year %}">
@@ -43,15 +42,15 @@
</div> </div>
</div> </div>
{# Action buttons#} {# Action buttons#}
<div class="col-12 col-xl-8"> <div class="tw:w-full tw:xl:w-8/12">
{# <c-ui.quick-transactions-buttons#} {# <c-ui.quick-transactions-buttons#}
{# :year="year"#} {# :year="year"#}
{# :month="month"#} {# :month="month"#}
{# ></c-ui.quick-transactions-buttons>#} {# ></c-ui.quick-transactions-buttons>#}
</div> </div>
</div> </div>
<div class="row"> <div class="tw:flex tw:flex-wrap">
<div class="show-loading" hx-get="{% url 'calendar_list' month=month year=year %}" <div class="show-loading tw:w-full" hx-get="{% url 'calendar_list' month=month year=year %}"
hx-trigger="load, updated from:window, selective_update from:window, every 10m"></div> hx-trigger="load, updated from:window, selective_update from:window, every 10m"></div>
</div> </div>
</div> </div>

View File

@@ -1,9 +1,9 @@
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Categories' %}<span> <div>{% translate 'Categories' %}<span>
<a class="text-decoration-none tw:text-2xl p-1 category-action" <a class="tw:no-underline tw:text-2xl tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -14,18 +14,14 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-header"> <div class="tw:card-header tw:bg-base-200 tw:p-4">
<ul class="nav nav-pills card-header-pills" id="myTab" role="tablist"> <div role="tablist" class="tw:tabs tw:tabs-lifted">
<li class="nav-item" role="presentation"> <button class="tw:tab tw:tab-active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'categories_table_active' %}" hx-trigger="load, click" hx-target="#categories-table">{% translate 'Active' %}</button>
<button class="nav-link active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'categories_table_active' %}" hx-trigger="load, click" hx-target="#categories-table">{% translate 'Active' %}</button> <button class="tw:tab" hx-get="{% url 'categories_table_archived' %}" hx-target="#categories-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Archived' %}</button>
</li> </div>
<li class="nav-item" role="presentation">
<button class="nav-link" hx-get="{% url 'categories_table_archived' %}" hx-target="#categories-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Archived' %}</button>
</li>
</ul>
</div> </div>
<div class="card-body"> <div class="tw:card-body">
<div id="categories-table"></div> <div id="categories-table"></div>
</div> </div>
</div> </div>

View File

@@ -7,22 +7,22 @@
hx-swap="outerHTML"> hx-swap="outerHTML">
{% endif %} {% endif %}
{% if categories %} {% if categories %}
<div class="table-responsive"> <div class="tw:overflow-x-auto">
<c-config.search></c-config.search> <c-config.search></c-config.search>
<table class="table table-hover"> <table class="tw:table tw:table-hover">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th> <th scope="col">{% translate 'Name' %}</th>
<th scope="col" class="col">{% translate 'Muted' %}</th> <th scope="col">{% translate 'Muted' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for category in categories %} {% for category in categories %}
<tr class="category"> <tr class="category">
<td class="col-auto text-center"> <td class="tw:w-auto tw:text-center">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
hx-swap="innerHTML" hx-swap="innerHTML"
@@ -30,7 +30,7 @@
hx-get="{% url 'category_edit' category_id=category.id %}" hx-get="{% url 'category_edit' category_id=category.id %}"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -43,7 +43,7 @@
data-confirm-text="{% translate "Yes, delete it!" %}" data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not category.owner %} {% if not category.owner %}
<a class="btn btn-secondary btn-sm text-primary" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-primary"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}" data-bs-title="{% translate "Take ownership" %}"
@@ -51,7 +51,7 @@
<i class="fa-solid fa-crown fa-fw"></i></a> <i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %} {% endif %}
{% if user == category.owner %} {% if user == category.owner %}
<a class="btn btn-secondary btn-sm text-primary" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-primary"
role="button" role="button"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-swap="innerHTML" hx-swap="innerHTML"
@@ -62,9 +62,9 @@
{% endif %} {% endif %}
</div> </div>
</td> </td>
<td class="col">{{ category.name }}</td> <td>{{ category.name }}</td>
<td class="col"> <td>
{% if category.mute %}<i class="fa-solid fa-check text-success"></i>{% endif %} {% if category.mute %}<i class="fa-solid fa-check tw:text-success"></i>{% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@@ -7,49 +7,33 @@
{% block body %} {% block body %}
{% regroup month_year_data by year as years_list %} {% regroup month_year_data by year as years_list %}
<ul class="nav nav-pills nav-fill" id="yearTabs" role="tablist"> <div role="tablist" class="tw:tabs tw:tabs-bordered tw:w-full" id="yearTabs">
{% for x in years_list %} {% for x in years_list %}
<li class="nav-item" role="presentation"> <input type="radio"
<button class="nav-link{% if x.grouper == current_year %} active{% endif %}" name="year_tabs"
id="{{ x.grouper }}" role="tab"
data-bs-toggle="tab" class="tw:tab"
data-bs-target="#{{ x.grouper }}-pane" aria-label="{{ x.grouper }}"
type="button" id="tab-{{ x.grouper }}"
role="tab" {% if x.grouper == current_year %}checked="checked"{% endif %} />
aria-controls="{{ x.grouper }}-pane" <div role="tabpanel" class="tw:tab-content tw:p-4" id="{{ x.grouper }}-pane">
aria-selected="{% if x.grouper == current_year %}true{% else %}false{% endif %}"> <ul class="tw:menu tw:bg-base-100 tw:w-full" id="month-year-list" hx-boost="true">
{{ x.grouper }}
</button>
</li>
{% endfor %}
</ul>
<div class="tab-content" id="yearTabsContent" hx-boost="true">
{% for x in years_list %}
<div class="tab-pane fade{% if x.grouper == current_year %} show active{% endif %} mt-2"
id="{{ x.grouper }}-pane"
role="tabpanel"
aria-labelledby="{{ x.grouper }}"
tabindex="0">
<ul class="list-group list-group-flush" id="month-year-list">
{% for month_data in x.list %} {% for month_data in x.list %}
<li class="list-group-item tw:hover:bg-zinc-900 <li {% if month_data.month == current_month and month_data.year == current_year %}class="tw:disabled"{% endif %}>
{% if month_data.month == current_month and month_data.year == current_year %} disabled bg-primary{% endif %}" <a class="{% if month_data.month == current_month and month_data.year == current_year %}tw:active{% endif %}"
{% if month_data.month == current_month and month_data.year == current_year %}aria-disabled="true"{% endif %}> href={{ month_data.url }}
<div class="d-flex justify-content-between"> {% if month_data.month == current_month and month_data.year == current_year %}aria-disabled="true"{% endif %}>
<a class="text-decoration-none stretched-link {% if month_data.month == current_month and month_data.year == current_year %} text-black{% endif %}" <span class="tw:flex-1">{{ month_data.month|month_name }}</span>
href={{ month_data.url }}> <span class="tw:badge tw:badge-primary">{{ month_data.transaction_count }}</span>
{{ month_data.month|month_name }}</a> </a>
<span class="badge text-bg-secondary">{{ month_data.transaction_count }}</span>
</div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<hr> <hr class="tw:border-base-300">
<div class="w-full text-end"> <div class="tw:w-full tw:text-end">
<a class="btn btn-outline-primary btn-sm" href="{{ today_url }}" role="button" hx-boost="true">{% trans 'Today' %}</a> <a class="tw:btn tw:btn-outline tw:btn-primary tw:btn-sm" href="{{ today_url }}" role="button" hx-boost="true">{% trans 'Today' %}</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -2,19 +2,25 @@
{% load toast_bg %} {% load toast_bg %}
{% if messages %} {% if messages %}
{% for message in messages %} {% for message in messages %}
<div class="toast align-items-center text-bg-{{ message.tags | toast_bg }} border-0" <div class="tw:alert tw:alert-{{ message.tags | toast_bg }}"
role="alert" role="alert"
aria-live="assertive" aria-live="assertive"
aria-atomic="true"> aria-atomic="true">
<div class="toast-header"> <div class="tw:flex tw:items-center tw:justify-between tw:w-full">
<i class="{{ message.tags | toast_icon }} fa-fw me-1"></i> <div class="tw:flex tw:items-center tw:gap-2">
<strong class="me-auto">{{ message.tags | toast_title }}</strong> <i class="{{ message.tags | toast_icon }} fa-fw"></i>
<div>
<strong>{{ message.tags | toast_title }}</strong>
<div>{{ message }}</div>
</div>
</div>
<button type="button" <button type="button"
class="btn-close" class="tw:btn tw:btn-ghost tw:btn-sm tw:btn-circle"
data-bs-dismiss="toast" data-bs-dismiss="toast"
aria-label={% translate 'Close' %}></button> aria-label={% translate 'Close' %}>
<i class="fa-solid fa-xmark"></i>
</button>
</div> </div>
<div class="toast-body">{{ message }}</div>
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}

View File

@@ -1,9 +1,9 @@
{% load currency_display %} {% load currency_display %}
{% if not divless %} {% if not divless %}
<div class="{% if text_end %}text-end{% elif text_start %}text-start{% endif %}"> <div class="{% if text_end %}tw:text-end{% elif text_start %}tw:text-start{% endif %}">
{% endif %} {% endif %}
<span class="amount{% if color == 'grey' or color == "gray" %} tw:text-gray-500{% elif color == 'green' %} tw:text-green-400{% elif color == 'red' %} tw:text-red-400{% endif %} {{ custom_class }}" <span class="amount{% if color == 'grey' or color == "gray" %} tw:text-base-content/70{% elif color == 'green' %} tw:dark:text-green-400 tw:text-green-600 {% elif color == 'red' %} tw:dark:text-red-400 tw:text-red-600{% endif %} {{ custom_class }}"
data-original-value="{% currency_display amount=amount prefix=prefix suffix=suffix decimal_places=decimal_places %}" data-original-value="{% currency_display amount=amount prefix=prefix suffix=suffix decimal_places=decimal_places %}"
data-amount="{{ amount|floatformat:"-40u" }}"> data-amount="{{ amount|floatformat:"-40u" }}">
</span><span>{{ slot }}</span> </span><span>{{ slot }}</span>

View File

@@ -1,33 +1,14 @@
<div class="tw:min-h-16"> {% load i18n%}
<div
id="fab-wrapper"
class="tw:fixed tw:bottom-5 tw:right-5 tw:ml-auto tw:w-max tw:flex tw:flex-col tw:items-end mt-5 tw:z-20">
<div
id="menu"
class="tw:flex tw:flex-col tw:items-end tw:space-y-6 tw:transition-all tw:duration-300 tw:ease-in-out tw:opacity-0 tw:invisible tw:hidden tw:mb-2">
{{ slot }} <div class="tw:fab">
<div tabindex="0" role="button" class="tw:btn tw:btn-lg tw:btn-circle tw:btn-primary">
<i class="fa-solid fa-plus tw:text-2xl fa-fw"></i>
</div> </div>
<button <div class="tw:fab-close">
class="btn btn-primary rounded-circle p-0 tw:w-12 tw:h-12 tw:flex tw:items-center tw:justify-center tw:shadow-lg tw:hover:shadow-xl tw:focus:shadow-xl tw:transition-all tw:duration-300 tw:ease-in-out" {% trans 'Close' %} <span class="tw:btn tw:btn-circle tw:btn-lg tw:btn-error"><i class="fa-solid fa-xmark tw:text-2xl fa-fw"></i></span>
_=" </div>
on click or focusout
if #menu.classList.contains('tw:invisible') and event.type === 'click' {{ slot }}
add .{'tw:rotate-45'} to #fab-icon
remove .{'tw:invisible'} from #menu </div>
remove .{'tw:hidden'} from #menu
remove .{'tw:opacity-0'} from #menu
else
wait 0.2s
remove .{'tw:rotate-45'} from #fab-icon
add .{'tw:invisible'} to #menu
add .{'tw:hidden'} to #menu
add .{'tw:opacity-0'} to #menu
end
"
>
<i id="fab-icon" class="fa-solid fa-plus tw:text-3xl tw:transition-transform tw:duration-300 tw:ease-in-out"></i>
</button>
</div>
</div>

View File

@@ -1,11 +1,6 @@
{% load i18n %} <div hx-get="{{ url }}"
<div class="tw:relative fab-item"> hx-trigger="{{ hx_trigger }}"
<button class="btn btn-sm btn-{{ color }}" hx-target="{{ hx_target }}"
hx-get="{{ url }}" hx-vals='{{ hx_vals }}'>
hx-trigger="{{ hx_trigger }}" {{ title }}
hx-target="{{ hx_target }}" <button class="tw:btn tw:btn-lg tw:btn-circle tw:btn-{{color}}"><i class="{{ icon }} fa-fw"></i></button></div>
hx-vals='{{ hx_vals }}'>
<i class="{{ icon }} me-2"></i>
{{ title }}
</button>
</div>

View File

@@ -1,12 +1,12 @@
<li class="tw:lg:hidden tw:lg:group-hover:block"> <li class="tw:lg:hidden tw:lg:group-hover:block">
<div class="d-flex align-items-center" data-bs-toggle="collapse" href="#{{ title|slugify }}" role="button" <div class="tw:flex tw:items-center" data-bs-toggle="collapse" href="#{{ title|slugify }}" role="button"
aria-expanded="false" aria-controls="{{ title|slugify }}"> aria-expanded="false" aria-controls="{{ title|slugify }}">
<span <span
class="text-muted small fw-bold text-uppercase tw:lg:hidden tw:lg:group-hover:inline me-2">{{ title }}</span> class="tw:text-base-content/60 tw:text-sm tw:font-bold tw:uppercase tw:lg:hidden tw:lg:group-hover:inline tw:me-2">{{ title }}</span>
<hr class="flex-grow-1"/> <hr class="tw:flex-grow"/>
<i class="fas fa-chevron-down text-muted tw:lg:before:hidden tw:lg:group-hover:before:inline tw:ml-2 tw:lg:ml-0 tw:lg:group-hover:ml-2"></i> <i class="fas fa-chevron-down tw:text-base-content/60 tw:lg:before:hidden tw:lg:group-hover:before:inline tw:ml-2 tw:lg:ml-0 tw:lg:group-hover:ml-2"></i>
</div> </div>
</li> </li>
<div class="collapse tw:lg:hidden tw:lg:group-hover:block" id="{{ title|slugify }}"> <div class="tw:collapse tw:lg:hidden tw:lg:group-hover:block" id="{{ title|slugify }}">
{{ slot }} {{ slot }}
</div> </div>

View File

@@ -1,6 +1,6 @@
<li> <li>
<div class="d-flex align-items-center"> <div class="tw:flex tw:items-center">
<span class="sidebar-menu-header text-muted small fw-bold text-uppercase me-2">{{ title }}</span> <span class="sidebar-menu-header tw:text-base-content/60 tw:text-sm tw:font-bold tw:uppercase tw:mr-3">{{ title }}</span>
<hr class="flex-grow-1"/> <hr class="tw:text-base-content/60 tw:flex-grow"/>
</div> </div>
</li> </li>

View File

@@ -1,7 +1,7 @@
{% load active_link %} {% load active_link %}
<li> <li>
<a href="{% url url %}" <a href="{% url url %}"
class="tw:lg:text-sm d-flex align-items-center text-decoration-none p-2 rounded-3 sidebar-item {% active_link views=active css_class="sidebar-active" %}" class="tw:lg:text-sm tw:flex tw:items-center tw:no-underline tw:p-2 tw:rounded-3xl sidebar-item {% active_link views=active css_class="sidebar-active" %}"
{% if tooltip %} {% if tooltip %}
data-bs-placement="right" data-bs-placement="right"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
@@ -9,6 +9,6 @@
{% endif %}> {% endif %}>
<i class="{{ icon }} fa-fw"></i> <i class="{{ icon }} fa-fw"></i>
<span <span
class="ms-3 fw-medium tw:lg:group-hover:truncate tw:lg:group-focus:truncate tw:lg:group-hover:text-ellipsis tw:lg:group-focus:text-ellipsis">{{ title }}</span> class="tw:ms-3 tw:font-medium tw:lg:group-hover:truncate tw:lg:group-focus:truncate tw:lg:group-hover:text-ellipsis tw:lg:group-focus:text-ellipsis">{{ title }}</span>
</a> </a>
</li> </li>

View File

@@ -2,7 +2,7 @@
<li> <li>
<a href="{{ url }}" <a href="{{ url }}"
hx-boost="false" hx-boost="false"
class="tw:lg:text-sm d-flex align-items-center text-decoration-none p-2 rounded-3 sidebar-item {% active_link views=active css_class="sidebar-active" %}" class="tw:lg:text-sm tw:flex tw:items-center tw:no-underline tw:p-2 tw:rounded-3xl sidebar-item {% active_link views=active css_class="sidebar-active" %}"
{% if tooltip %} {% if tooltip %}
data-bs-placement="right" data-bs-placement="right"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
@@ -11,6 +11,6 @@
<i class="{{ icon }} fa-fw"></i> <i class="{{ icon }} fa-fw"></i>
<span <span
class="ms-3 fw-medium tw:lg:group-hover:truncate tw:lg:group-focus:truncate tw:lg:group-hover:text-ellipsis tw:lg:group-focus:text-ellipsis">{{ title }}</span> class="tw:ms-3 tw:font-medium tw:lg:group-hover:truncate tw:lg:group-focus:truncate tw:lg:group-hover:text-ellipsis tw:lg:group-focus:text-ellipsis">{{ title }}</span>
</a> </a>
</li> </li>

View File

@@ -1,8 +1,8 @@
{% load i18n %} {% load i18n %}
<div id="search" class="mb-3"> <div id="search" class="tw:mb-3">
<label class="w-100"> <label class="tw:w-full">
<input type="search" <input type="search"
class="form-control" class="tw:input tw:input-bordered tw:w-full"
placeholder="{% translate 'Search' %}" placeholder="{% translate 'Search' %}"
_="on input or search _="on input or search
show < tbody>tr /> in <table/> show < tbody>tr /> in <table/>

View File

@@ -1,8 +1,8 @@
<div class="row {% if not remove_padding %}p-5{% endif %}"> <div class="tw:grid tw:grid-cols-1 {% if not remove_padding %}tw:p-5{% endif %}">
<div class="col {% if not remove_padding %}p-5{% endif %}"> <div class="{% if not remove_padding %}tw:p-5{% endif %}">
<div class="text-center"> <div class="tw:text-center">
<i class="{% if icon %}{{ icon }}{% else %}fa-solid fa-circle-xmark{% endif %} tw:text-6xl"></i> <i class="{% if icon %}{{ icon }}{% else %}fa-solid fa-circle-xmark{% endif %} tw:text-6xl"></i>
<p class="lead mt-4 mb-0">{{ title }}</p> <p class="tw:text-lg tw:mt-4 tw:mb-0">{{ title }}</p>
<p class="tw:text-gray-500">{{ subtitle }}</p> <p class="tw:text-gray-500">{{ subtitle }}</p>
</div> </div>
</div> </div>

View File

@@ -2,22 +2,21 @@
{% load i18n %} {% load i18n %}
<div <div
class="transaction {% if transaction.type == "EX" %}expense{% else %}income{% endif %} tw:group/transaction tw:relative tw:hover:z-10"> class="transaction {% if transaction.type == "EX" %}expense{% else %}income{% endif %} tw:group/transaction tw:relative tw:hover:z-10">
<div class="d-flex my-1"> <div class="tw:flex tw:my-1">
{% if not disable_selection or not dummy %} {% if not disable_selection or not dummy %}
<label class="px-3 d-flex align-items-center justify-content-center"> <label class="tw:px-3 tw:flex! tw:items-center tw:justify-center">
<input class="form-check-input" type="checkbox" name="transactions" value="{{ transaction.id }}" <input class="tw:checkbox" type="checkbox" name="transactions" value="{{ transaction.id }}"
id="check-{{ transaction.id }}" aria-label="{% translate 'Select' %}" hx-preserve> id="check-{{ transaction.id }}" aria-label="{% translate 'Select' %}" hx-preserve>
</label> </label>
{% endif %} {% endif %}
<div class="tw:border-s-4 tw:border-e-0 tw:border-t-0 tw:border-b-0 border-bottom <div class="tw:border-s-4 tw:border-e-0 tw:border-t-0
tw:hover:bg-zinc-900 p-2 {% if transaction.account.is_asset %}tw:border-dashed{% else %}tw:border-solid{% endif %} tw:hover:bg-neutral-500/20 tw:p-2 {% if transaction.account.is_asset %}tw:border-l-dashed{% else %}tw:border-solid{% endif %}
{% if transaction.type == "EX" %}tw:border-red-500{% else %}tw:border-green-500{% endif %} tw:relative {% if transaction.type == "EX" %}tw:border-l-red-500{% else %}tw:border-l-green-500{% endif %} tw:relative
w-100 transaction-item"> tw:w-full transaction-item tw:bg-base-200 tw:rounded">
<div class="row font-monospace tw:text-sm align-items-center"> <div class="tw:flex tw:flex-wrap tw:font-mono tw:text-sm tw:items-center">
<div <div class="tw:lg:w-auto tw:w-full tw:flex tw:items-center tw:text-2xl tw:lg:text-xl tw:lg:text-center tw:text-center tw:p-0 tw:cursor-pointer">
class="col-lg-auto col-12 d-flex align-items-center tw:text-2xl tw:lg:text-xl text-lg-center text-center p-0 ps-1">
{% if not transaction.deleted %} {% if not transaction.deleted %}
<a class="text-decoration-none p-3 tw:text-gray-500!" <a class="tw:no-underline tw:p-3 tw:text-gray-500!"
title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}" title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}"
role="button" role="button"
{% if not dummy %} {% if not dummy %}
@@ -28,7 +27,7 @@
class="fa-regular fa-circle"></i>{% endif %} class="fa-regular fa-circle"></i>{% endif %}
</a> </a>
{% else %} {% else %}
<div class="text-decoration-none p-3 tw:text-gray-500!" <div class="tw:no-underline tw:p-3 tw:text-gray-500!"
title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}"> 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 {% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i
class="fa-regular fa-circle"></i>{% endif %} class="fa-regular fa-circle"></i>{% endif %}
@@ -36,79 +35,79 @@
{% endif %} {% endif %}
</div> </div>
<div <div
class="col-lg col-12 {% if transaction.account.is_untracked_by or transaction.category.mute or transaction.mute %}tw:brightness-80{% endif %}"> class="tw:lg:flex-1 tw:w-full {% if transaction.account.is_untracked_by or transaction.category.mute or transaction.mute %}tw:brightness-80{% endif %}">
{# Date#} {# Date#}
<div class="row mb-2 mb-lg-1 tw:text-gray-400"> <div class="tw:flex tw:flex-wrap tw:mb-2 tw:lg:mb-1 tw:text-base-content/70">
<div class="col-auto pe-1"><i class="fa-solid fa-calendar fa-fw me-1 fa-xs"></i></div> <div class="tw:w-auto tw:pe-1"><i class="fa-solid fa-calendar fa-fw tw:mr-1 fa-xs"></i></div>
<div <div
class="col ps-0">{{ transaction.date|date:"SHORT_DATE_FORMAT" }} • {{ transaction.reference_date|date:"b/Y" }}</div> class="tw:flex-1 tw:ps-0">{{ transaction.date|date:"SHORT_DATE_FORMAT" }} • {{ transaction.reference_date|date:"b/Y" }}</div>
</div> </div>
{# Description#} {# Description#}
<div class="mb-2 mb-lg-1 text-body tw:text-base"> <div class="tw:mb-2 tw:lg:mb-1 tw:text-base-content tw:text-base">
{% spaceless %} {% spaceless %}
<span class="{% if transaction.description %}me-2{% endif %}">{{ transaction.description }}</span> <span class="{% if transaction.description %}tw:mr-2{% endif %}">{{ transaction.description }}</span>
{% if transaction.installment_plan and transaction.installment_id %} {% if transaction.installment_plan and transaction.installment_id %}
<span <span
class="badge text-bg-secondary mx-1">{{ transaction.installment_id }}/{{ transaction.installment_plan.installment_total_number }}</span> class="tw:badge tw:badge-neutral tw:mx-1">{{ transaction.installment_id }}/{{ transaction.installment_plan.installment_total_number }}</span>
{% endif %} {% endif %}
{% if transaction.recurring_transaction %} {% if transaction.recurring_transaction %}
<span class="text-primary tw:text-xs mx-1"><i class="fa-solid fa-arrows-rotate fa-fw"></i></span> <span class="tw:text-primary tw:text-xs tw:mx-1"><i class="fa-solid fa-arrows-rotate fa-fw"></i></span>
{% endif %} {% endif %}
{% if transaction.dca_expense_entries.all or transaction.dca_income_entries.all %} {% if transaction.dca_expense_entries.all or transaction.dca_income_entries.all %}
<span class="badge text-bg-secondary mx-1">{% trans 'DCA' %}</span> <span class="tw:badge tw:badge-neutral tw:mx-1">{% trans 'DCA' %}</span>
{% endif %} {% endif %}
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="tw:text-gray-400 tw:text-sm"> <div class="tw:text-base-content/70 tw:text-sm">
{# Entities #} {# Entities #}
{% comment %} First, check for the highest priority: a valid 'overriden_entities' list. {% endcomment %} {% comment %} First, check for the highest priority: a valid 'overriden_entities' list. {% endcomment %}
{% if overriden_entities %} {% if overriden_entities %}
<div class="row mb-2 mb-lg-1 tw:text-gray-400"> <div class="tw:flex tw:flex-wrap tw:mb-2 tw:lg:mb-1 tw:text-base-content/70">
<div class="col-auto pe-1"><i class="fa-solid fa-user-group fa-fw me-1 fa-xs"></i></div> <div class="tw:w-auto tw:pe-1"><i class="fa-solid fa-user-group fa-fw tw:mr-1 fa-xs"></i></div>
<div class="col ps-0">{{ overriden_entities|join:", " }}</div> <div class="tw:flex-1 tw:ps-0">{{ overriden_entities|join:", " }}</div>
</div> </div>
{% comment %} If no override, fall back to transaction entities, but ONLY if the transaction has an ID. {% endcomment %} {% comment %} If no override, fall back to transaction entities, but ONLY if the transaction has an ID. {% endcomment %}
{% elif transaction.id and transaction.entities.all %} {% elif transaction.id and transaction.entities.all %}
<div class="row mb-2 mb-lg-1 tw:text-gray-400"> <div class="tw:flex tw:flex-wrap tw:mb-2 tw:lg:mb-1 tw:text-base-content/70">
<div class="col-auto pe-1"><i class="fa-solid fa-user-group fa-fw me-1 fa-xs"></i></div> <div class="tw:w-auto tw:pe-1"><i class="fa-solid fa-user-group fa-fw tw:mr-1 fa-xs"></i></div>
<div class="col ps-0">{{ transaction.entities.all|join:", " }}</div> <div class="tw:flex-1 tw:ps-0">{{ transaction.entities.all|join:", " }}</div>
</div> </div>
{% endif %} {% endif %}
{# Notes#} {# Notes#}
{% if transaction.notes %} {% if transaction.notes %}
<div class="row mb-2 mb-lg-1 tw:text-gray-400"> <div class="tw:flex tw:flex-wrap tw:mb-2 tw:lg:mb-1 tw:text-base-content/70">
<div class="col-auto pe-1"><i class="fa-solid fa-align-left fa-fw me-1 fa-xs"></i></div> <div class="tw:w-auto tw:pe-1"><i class="fa-solid fa-align-left fa-fw tw:mr-1 fa-xs"></i></div>
<div class="col ps-0">{{ transaction.notes | limited_markdown | linebreaksbr }}</div> <div class="tw:flex-1 tw:ps-0">{{ transaction.notes | limited_markdown | linebreaksbr }}</div>
</div> </div>
{% endif %} {% endif %}
{# Category#} {# Category#}
{% if transaction.category %} {% if transaction.category %}
<div class="row mb-2 mb-lg-1 tw:text-gray-400"> <div class="tw:flex tw:flex-wrap tw:mb-2 tw:lg:mb-1 tw:text-base-content/70">
<div class="col-auto pe-1"><i class="fa-solid fa-icons fa-fw me-1 fa-xs"></i></div> <div class="tw:w-auto tw:pe-1"><i class="fa-solid fa-icons fa-fw tw:mr-1 fa-xs"></i></div>
<div class="col ps-0">{{ transaction.category.name }}</div> <div class="tw:flex-1 tw:ps-0">{{ transaction.category.name }}</div>
</div> </div>
{% endif %} {% endif %}
{# Tags#} {# Tags#}
{% comment %} First, check for the highest priority: a valid 'overriden_tags' list. {% endcomment %} {% comment %} First, check for the highest priority: a valid 'overriden_tags' list. {% endcomment %}
{% if overriden_tags %} {% if overriden_tags %}
<div class="row mb-2 mb-lg-1 tw:text-gray-400"> <div class="tw:flex tw:flex-wrap tw:mb-2 tw:lg:mb-1 tw:text-base-content/70">
<div class="col-auto pe-1"><i class="fa-solid fa-hashtag fa-fw me-1 fa-xs"></i></div> <div class="tw:w-auto tw:pe-1"><i class="fa-solid fa-hashtag fa-fw tw:mr-1 fa-xs"></i></div>
<div class="col ps-0">{{ overriden_tags|join:", " }}</div> <div class="tw:flex-1 tw:ps-0">{{ overriden_tags|join:", " }}</div>
</div> </div>
{% comment %} If no override, fall back to transaction tags, but ONLY if the transaction has an ID. {% endcomment %} {% comment %} If no override, fall back to transaction tags, but ONLY if the transaction has an ID. {% endcomment %}
{% elif transaction.id and transaction.tags.all %} {% elif transaction.id and transaction.tags.all %}
<div class="row mb-2 mb-lg-1 tw:text-gray-400"> <div class="tw:flex tw:flex-wrap tw:mb-2 tw:lg:mb-1 tw:text-base-content/70">
<div class="col-auto pe-1"><i class="fa-solid fa-hashtag fa-fw me-1 fa-xs"></i></div> <div class="tw:w-auto tw:pe-1"><i class="fa-solid fa-hashtag fa-fw tw:mr-1 fa-xs"></i></div>
<div class="col ps-0">{{ transaction.tags.all|join:", " }}</div> <div class="tw:flex-1 tw:ps-0">{{ transaction.tags.all|join:", " }}</div>
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div <div
class="col-lg-auto col-12 text-lg-end align-self-end {% if transaction.account.is_untracked_by or transaction.category.mute or transaction.mute %}tw:brightness-80{% endif %}"> class="tw:lg:w-auto tw:w-full tw:lg:text-right tw:self-end {% if transaction.account.is_untracked_by or transaction.category.mute or transaction.mute %}tw:brightness-80{% endif %}">
<div class="main-amount mb-2 mb-lg-0"> <div class="main-amount tw:mb-2 tw:lg:mb-0">
<c-amount.display <c-amount.display
:amount="transaction.amount" :amount="transaction.amount"
:prefix="transaction.account.currency.prefix" :prefix="transaction.account.currency.prefix"
@@ -120,7 +119,7 @@
{% if not dummy %} {% if not dummy %}
{% with exchanged=transaction.exchanged_amount %} {% with exchanged=transaction.exchanged_amount %}
{% if exchanged %} {% if exchanged %}
<div class="exchanged-amount mb-2 mb-lg-0"> <div class="exchanged-amount tw:mb-2 tw:lg:mb-0">
<c-amount.display <c-amount.display
:amount="exchanged.amount" :amount="exchanged.amount"
:prefix="exchanged.prefix" :prefix="exchanged.prefix"
@@ -139,109 +138,106 @@
<div> <div>
{# Item actions#} {# Item actions#}
<div <div
class="transaction-actions tw:absolute! tw:left-1/2 tw:top-0 tw:-translate-x-1/2 tw:-translate-y-1/2 tw:invisible tw:group-hover/transaction:visible d-flex flex-row card"> class="transaction-actions tw:absolute! tw:left-1/2 tw:top-0 tw:-translate-x-1/2 tw:-translate-y-1/2 tw:invisible tw:group-hover/transaction:visible tw:flex tw:flex-row tw:card tw:bg-base-300">
<div class="card-body p-1 shadow-lg d-flex flex-row gap-1"> <div class="tw:card-body tw:p-1 tw:shadow-lg tw:flex tw:flex-row tw:gap-1">
{% if not transaction.deleted %} {% if not transaction.deleted %}
<a class="btn btn-secondary btn-sm transaction-action" <div class="tw:tooltip" data-tip="{% translate "Edit" %}">
role="button" <a class="tw:btn btn-neutral tw:btn-sm transaction-action"
data-bs-toggle="tooltip" role="button"
data-bs-title="{% translate "Edit" %}" hx-get="{% url 'transaction_edit' transaction_id=transaction.id %}"
hx-get="{% url 'transaction_edit' transaction_id=transaction.id %}" hx-target="#generic-offcanvas" hx-swap="innerHTML">
hx-target="#generic-offcanvas" hx-swap="innerHTML"> <i class="fa-solid fa-pencil fa-fw"></i></a>
<i class="fa-solid fa-pencil fa-fw"></i></a> </div>
<a class="btn btn-secondary btn-sm transaction-action" <div class="tw:tooltip" data-tip="{% translate "Delete" %}">
role="button" <a class="tw:btn btn-neutral tw:btn-sm transaction-action"
data-bs-toggle="tooltip" role="button"
data-bs-title="{% translate "Delete" %}" hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}"
hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}" hx-trigger='confirmed'
hx-trigger='confirmed' data-bypass-on-ctrl="true"
data-bypass-on-ctrl="true" data-title="{% translate "Are you sure?" %}"
data-title="{% translate "Are you sure?" %}" data-text="{% translate "You won't be able to revert this!" %}"
data-text="{% translate "You won't be able to revert this!" %}" data-confirm-text="{% translate "Yes, delete it!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}" _="install prompt_swal"><i class="fa-solid fa-trash fa-fw tw:text-red-500"></i>
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw text-danger"></i> </a>
</a> </div>
<button class="btn btn-secondary btn-sm transaction-action" type="button" data-bs-toggle="dropdown" <div class="tw:dropdown tw:dropdown-end">
aria-expanded="false"> <button type="button" tabindex="0" role="button" class="tw:btn btn-neutral tw:btn-sm transaction-action">
<i class="fa-solid fa-ellipsis fa-fw"></i> <i class="fa-solid fa-ellipsis fa-fw"></i>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-md-start"> <ul tabindex="0" class="tw:dropdown-content tw:menu tw:p-2 tw:shadow tw:bg-base-200 tw:rounded-box tw:w-72 z-[1]">
{% if transaction.account.is_untracked_by %} {% if transaction.account.is_untracked_by %}
<li> <li>
<a class="dropdown-item disabled d-flex align-items-center" aria-disabled="true"> <a class="tw:disabled tw:flex tw:items-center" aria-disabled="true">
<i class="fa-solid fa-eye fa-fw me-2"></i> <i class="fa-solid fa-eye fa-fw tw:mr-2"></i>
<div> <div>
{% translate 'Show on summaries' %} {% translate 'Show on summaries' %}
<div <div
class="d-block text-body-secondary tw:text-xs tw:font-medium">{% translate 'Controlled by account' %}</div> class="tw:block tw:text-gray-500 tw:text-xs tw:font-medium">{% translate 'Controlled by account' %}</div>
</div> </div>
</a> </a>
</li>
{% elif transaction.category.mute %}
<li>
<a class="tw:disabled tw:flex tw:items-center" aria-disabled="true">
<i class="fa-solid fa-eye fa-fw tw:mr-2"></i>
<div>
{% translate 'Show on summaries' %}
<div
class="tw:block tw:text-gray-500 tw:text-xs tw:font-medium">{% translate 'Controlled by category' %}</div>
</div>
</a>
</li>
{% elif transaction.mute %}
<li><a href="#"
hx-get="{% url 'transaction_mute' transaction_id=transaction.id %}"
hx-target="closest .transaction" hx-swap="outerHTML"><i
class="fa-solid fa-eye fa-fw tw:mr-2"></i>{% translate 'Show on summaries' %}</a></li>
{% else %}
<li><a href="#"
hx-get="{% url 'transaction_mute' transaction_id=transaction.id %}"
hx-target="closest .transaction" hx-swap="outerHTML"><i
class="fa-solid fa-eye-slash fa-fw tw:mr-2"></i>{% translate 'Hide from summaries' %}</a></li>
{% endif %}
<li><a href="#"
hx-get="{% url 'quick_transaction_add_as_quick_transaction' transaction_id=transaction.id %}"><i
class="fa-solid fa-person-running fa-fw tw:mr-2"></i>{% translate 'Add as quick transaction' %}</a>
</li> </li>
{% elif transaction.category.mute %} <hr class="tw:my-1 tw:text-base-content/60">
<li> <li><a href="#"
<a class="dropdown-item disabled d-flex align-items-center" aria-disabled="true"> hx-get="{% url 'transaction_change_month' transaction_id=transaction.id change_type='previous' %}"><i
<i class="fa-solid fa-eye fa-fw me-2"></i> class="fa-solid fa-calendar-minus fa-fw tw:mr-2"></i>{% translate 'Move to previous month' %}</a>
<div>
{% translate 'Show on summaries' %}
<div
class="d-block text-body-secondary tw:text-xs tw:font-medium">{% translate 'Controlled by category' %}</div>
</div>
</a>
</li> </li>
{% elif transaction.mute %} <li><a href="#"
<li><a class="dropdown-item" href="#" hx-get="{% url 'transaction_change_month' transaction_id=transaction.id change_type='next' %}"><i
hx-get="{% url 'transaction_mute' transaction_id=transaction.id %}" class="fa-solid fa-calendar-plus fa-fw tw:mr-2"></i>{% translate 'Move to next month' %}</a></li>
hx-target="closest .transaction" hx-swap="outerHTML"><i <li><a href="#"
class="fa-solid fa-eye fa-fw me-2"></i>{% translate 'Show on summaries' %}</a></li> hx-get="{% url 'transaction_move_to_today' transaction_id=transaction.id %}"><i
{% else %} class="fa-solid fa-calendar-day fa-fw tw:mr-2"></i>{% translate 'Move to today' %}</a></li>
<li><a class="dropdown-item" href="#" <hr class="tw:my-1 tw:text-base-content/60">
hx-get="{% url 'transaction_mute' transaction_id=transaction.id %}" <li><a href="#"
hx-target="closest .transaction" hx-swap="outerHTML"><i hx-get="{% url 'transaction_clone' transaction_id=transaction.id %}"><i
class="fa-solid fa-eye-slash fa-fw me-2"></i>{% translate 'Hide from summaries' %}</a></li> class="fa-solid fa-clone fa-fw tw:mr-2"></i>{% translate 'Duplicate' %}</a></li>
{% endif %} </ul>
<li><a class="dropdown-item" href="#" </div>
hx-get="{% url 'quick_transaction_add_as_quick_transaction' transaction_id=transaction.id %}"><i
class="fa-solid fa-person-running fa-fw me-2"></i>{% translate 'Add as quick transaction' %}</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item" href="#"
hx-get="{% url 'transaction_change_month' transaction_id=transaction.id change_type='previous' %}"><i
class="fa-solid fa-calendar-minus fa-fw me-2"></i>{% translate 'Move to previous month' %}</a>
</li>
<li><a class="dropdown-item" href="#"
hx-get="{% url 'transaction_change_month' transaction_id=transaction.id change_type='next' %}"><i
class="fa-solid fa-calendar-plus fa-fw me-2"></i>{% translate 'Move to next month' %}</a></li>
<li><a class="dropdown-item" href="#"
hx-get="{% url 'transaction_move_to_today' transaction_id=transaction.id %}"><i
class="fa-solid fa-calendar-day fa-fw me-2"></i>{% translate 'Move to today' %}</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item" href="#"
hx-get="{% url 'transaction_clone' transaction_id=transaction.id %}"><i
class="fa-solid fa-clone fa-fw me-2"></i>{% translate 'Duplicate' %}</a></li>
</ul>
{% else %} {% else %}
<a class="btn btn-secondary btn-sm transaction-action" <div class="tw:tooltip" data-tip="{% translate "Restore" %}">
role="button" <a class="tw:btn tw:btn-secondary tw:btn-sm transaction-action"
data-bs-toggle="tooltip" role="button"
data-bs-title="{% translate "Restore" %}" hx-get="{% url 'transaction_undelete' transaction_id=transaction.id %}"><i
hx-get="{% url 'transaction_undelete' transaction_id=transaction.id %}"><i class="fa-solid fa-trash-arrow-up"></i></a>
class="fa-solid fa-trash-arrow-up"></i></a> </div>
<a class="btn btn-secondary btn-sm transaction-action" <div class="tw:tooltip" data-tip="{% translate "Delete" %}">
role="button" <a class="tw:btn tw:btn-secondary tw:btn-sm transaction-action"
data-bs-toggle="tooltip" role="button"
data-bs-title="{% translate "Delete" %}" hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}"
hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}" hx-trigger='confirmed'
hx-trigger='confirmed' data-bypass-on-ctrl="true"
data-bypass-on-ctrl="true" data-title="{% translate "Are you sure?" %}"
data-title="{% translate "Are you sure?" %}" data-text="{% translate "You won't be able to revert this!" %}"
data-text="{% translate "You won't be able to revert this!" %}" data-confirm-text="{% translate "Yes, delete it!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}" _="install prompt_swal"><i class="fa-solid fa-trash fa-fw tw:text-red-500"></i>
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw text-danger"></i> </a>
</a> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@@ -1,22 +1,22 @@
<div class="card mb-2 transaction-item"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:mb-2 transaction-item">
<div class="card-body p-2 tw:flex tw:items-center tw:gap-3" data-bs-toggle="collapse" data-bs-target="#{{ transaction.id }}" role="button" aria-expanded="false" aria-controls="{{ transaction.id }}"> <div class="tw:card-body tw:p-2 tw:flex tw:items-center tw:gap-3" data-bs-toggle="collapse" data-bs-target="#{{ transaction.id }}" role="button" aria-expanded="false" aria-controls="{{ transaction.id }}">
<!-- Main visible content --> <!-- Main visible content -->
<div class="tw:flex flex-lg-row flex-column tw:lg:items-center tw:w-full tw:gap-3"> <div class="tw:flex tw:flex-col tw:lg:flex-row tw:lg:items-center tw:w-full tw:gap-3">
<!-- Type indicator --> <!-- Type indicator -->
<div class="tw:w-8"> <div class="tw:w-8">
{% if transaction.type == 'IN' %} {% if transaction.type == 'IN' %}
<span class="badge bg-success"></span> <span class="tw:badge tw:badge-success"></span>
{% else %} {% else %}
<span class="badge bg-danger"></span> <span class="tw:badge tw:badge-error"></span>
{% endif %} {% endif %}
</div> </div>
<!-- Payment status --> <!-- Payment status -->
<div class="tw:w-8"> <div class="tw:w-8">
{% if transaction.is_paid %} {% if transaction.is_paid %}
<span class="badge bg-success"></span> <span class="tw:badge tw:badge-success"></span>
{% else %} {% else %}
<span class="badge bg-warning"></span> <span class="tw:badge tw:badge-warning"></span>
{% endif %} {% endif %}
</div> </div>
@@ -32,7 +32,7 @@
</span> </span>
{% if transaction.exchanged_amount %} {% if transaction.exchanged_amount %}
<br> <br>
<small class="text-muted"> <small class="tw:text-base-content/60">
{{ transaction.exchanged_amount.prefix }}{{ transaction.exchanged_amount.amount }}{{ transaction.exchanged_amount.suffix }} {{ transaction.exchanged_amount.prefix }}{{ transaction.exchanged_amount.amount }}{{ transaction.exchanged_amount.suffix }}
</small> </small>
{% endif %} {% endif %}
@@ -41,50 +41,50 @@
</div> </div>
<!-- Expandable details --> <!-- Expandable details -->
<div class="collapse" id="{{ transaction.id }}"> <div class="tw:collapse" id="{{ transaction.id }}">
<div class="card-body p-3 transaction-details"> <div class="tw:card-body tw:p-3 transaction-details">
<div class="row"> <div class="tw:grid tw:grid-cols-1 tw:md:grid-cols-2">
<div class="col-md-6"> <div>
<dl class="row"> <dl class="tw:grid tw:grid-cols-3">
<dt class="col-sm-4">Date</dt> <dt class="tw:col-span-1">Date</dt>
<dd class="col-sm-8">{{ transaction.date|date:"Y-m-d" }}</dd> <dd class="tw:col-span-2">{{ transaction.date|date:"Y-m-d" }}</dd>
<dt class="col-sm-4">Reference Date</dt> <dt class="tw:col-span-1">Reference Date</dt>
<dd class="col-sm-8">{{ transaction.reference_date|date:"Y-m" }}</dd> <dd class="tw:col-span-2">{{ transaction.reference_date|date:"Y-m" }}</dd>
<dt class="col-sm-4">Account</dt> <dt class="tw:col-span-1">Account</dt>
<dd class="col-sm-8">{{ transaction.account.name }}</dd> <dd class="tw:col-span-2">{{ transaction.account.name }}</dd>
<dt class="col-sm-4">Category</dt> <dt class="tw:col-span-1">Category</dt>
<dd class="col-sm-8">{{ transaction.category|default:"-" }}</dd> <dd class="tw:col-span-2">{{ transaction.category|default:"-" }}</dd>
</dl> </dl>
</div> </div>
<div class="col-md-6"> <div>
<dl class="row"> <dl class="tw:grid tw:grid-cols-3">
{% if transaction.tags.exists %} {% if transaction.tags.exists %}
<dt class="col-sm-4">Tags</dt> <dt class="tw:col-span-1">Tags</dt>
<dd class="col-sm-8"> <dd class="tw:col-span-2">
{% for tag in transaction.tags.all %} {% for tag in transaction.tags.all %}
<span class="badge bg-secondary">{{ tag.name }}</span> <span class="tw:badge tw:badge-secondary">{{ tag.name }}</span>
{% endfor %} {% endfor %}
</dd> </dd>
{% endif %} {% endif %}
{% if transaction.installment_plan %} {% if transaction.installment_plan %}
<dt class="col-sm-4">Installment</dt> <dt class="tw:col-span-1">Installment</dt>
<dd class="col-sm-8"> <dd class="tw:col-span-2">
{{ transaction.installment_id }} of {{ transaction.installment_plan.total_installments }} {{ transaction.installment_id }} of {{ transaction.installment_plan.total_installments }}
</dd> </dd>
{% endif %} {% endif %}
{% if transaction.recurring_transaction %} {% if transaction.recurring_transaction %}
<dt class="col-sm-4">Recurring</dt> <dt class="tw:col-span-1">Recurring</dt>
<dd class="col-sm-8">Yes</dd> <dd class="tw:col-span-2">Yes</dd>
{% endif %} {% endif %}
{% if transaction.notes %} {% if transaction.notes %}
<dt class="col-sm-4">Notes</dt> <dt class="tw:col-span-1">Notes</dt>
<dd class="col-sm-8">{{ transaction.notes }}</dd> <dd class="tw:col-span-2">{{ transaction.notes }}</dd>
{% endif %} {% endif %}
</dl> </dl>
</div> </div>

View File

@@ -1,22 +1,22 @@
{% load tools %} {% load tools %}
{% load i18n %} {% load i18n %}
<div class="col card shadow"> <div class="col tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body"> <div class="tw:card-body">
{% if account.account.group %} {% if account.account.group %}
<div class="tw:text-sm mb-2"> <div class="tw:text-sm tw:mb-2">
<span class="badge text-bg-primary ">{{ account.account.group }}</span> <span class="tw:badge tw:badge-primary">{{ account.account.group }}</span>
</div> </div>
{% endif %} {% endif %}
<h5 class="card-title"> <h5 class="tw:card-title">
{{ account.account.name }} {{ account.account.name }}
</h5> </h5>
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'projected income' %}</div> <div class="tw:text-gray-400">{% translate 'projected income' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
{% if account.income_projected != 0 %} {% if account.income_projected != 0 %}
<div class="text-end font-monospace tw:text-green-400"> <div class="tw:text-end tw:font-mono tw:text-green-400">
<c-amount.display <c-amount.display
:amount="account.income_projected" :amount="account.income_projected"
:prefix="account.currency.prefix" :prefix="account.currency.prefix"
@@ -24,11 +24,11 @@
:decimal_places="account.currency.decimal_places"></c-amount.display> :decimal_places="account.currency.decimal_places"></c-amount.display>
</div> </div>
{% else %} {% else %}
<div class="text-end font-monospace">-</div> <div class="tw:text-end tw:font-mono">-</div>
{% endif %} {% endif %}
</div> </div>
{% if account.exchanged and account.exchanged.income_projected %} {% if account.exchanged and account.exchanged.income_projected %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="account.exchanged.income_projected" :amount="account.exchanged.income_projected"
:prefix="account.exchanged.currency.prefix" :prefix="account.exchanged.currency.prefix"
@@ -36,14 +36,14 @@
:decimal_places="account.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="account.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'projected expenses' %}</div> <div class="tw:text-gray-400">{% translate 'projected expenses' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
<div> <div>
{% if account.expense_projected != 0 %} {% if account.expense_projected != 0 %}
<div class="text-end font-monospace tw:text-red-400"> <div class="tw:text-end tw:font-mono tw:text-red-400">
<c-amount.display <c-amount.display
:amount="account.expense_projected" :amount="account.expense_projected"
:prefix="account.currency.prefix" :prefix="account.currency.prefix"
@@ -51,12 +51,12 @@
:decimal_places="account.currency.decimal_places"></c-amount.display> :decimal_places="account.currency.decimal_places"></c-amount.display>
</div> </div>
{% else %} {% else %}
<div class="text-end font-monospace">-</div> <div class="tw:text-end tw:font-mono">-</div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% if account.exchanged and account.exchanged.expense_projected %} {% if account.exchanged and account.exchanged.expense_projected %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="account.exchanged.expense_projected" :amount="account.exchanged.expense_projected"
:prefix="account.exchanged.currency.prefix" :prefix="account.exchanged.currency.prefix"
@@ -64,13 +64,13 @@
:decimal_places="account.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="account.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'projected total' %}</div> <div class="tw:text-gray-400">{% translate 'projected total' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
<div <div
class="text-end font-monospace"> class="tw:text-end tw:font-mono">
<c-amount.display <c-amount.display
:amount="account.total_projected" :amount="account.total_projected"
:prefix="account.currency.prefix" :prefix="account.currency.prefix"
@@ -80,7 +80,7 @@
</div> </div>
</div> </div>
{% if account.exchanged.total_projected and account.exchanged.total_projected %} {% if account.exchanged.total_projected and account.exchanged.total_projected %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="account.exchanged.total_projected" :amount="account.exchanged.total_projected"
:prefix="account.exchanged.currency.prefix" :prefix="account.exchanged.currency.prefix"
@@ -88,14 +88,14 @@
:decimal_places="account.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="account.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<hr class="my-3"> <hr class="tw:my-3">
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'current income' %}</div> <div class="tw:text-gray-400">{% translate 'current income' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
{% if account.income_current != 0 %} {% if account.income_current != 0 %}
<div class="text-end font-monospace tw:text-green-400"> <div class="tw:text-end tw:font-mono tw:text-green-400">
<c-amount.display <c-amount.display
:amount="account.income_current" :amount="account.income_current"
:prefix="account.currency.prefix" :prefix="account.currency.prefix"
@@ -103,11 +103,11 @@
:decimal_places="account.currency.decimal_places"></c-amount.display> :decimal_places="account.currency.decimal_places"></c-amount.display>
</div> </div>
{% else %} {% else %}
<div class="text-end font-monospace">-</div> <div class="tw:text-end tw:font-mono">-</div>
{% endif %} {% endif %}
</div> </div>
{% if account.exchanged and account.exchanged.income_current %} {% if account.exchanged and account.exchanged.income_current %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="account.exchanged.income_current" :amount="account.exchanged.income_current"
:prefix="account.exchanged.currency.prefix" :prefix="account.exchanged.currency.prefix"
@@ -115,13 +115,13 @@
:decimal_places="account.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="account.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'current expenses' %}</div> <div class="tw:text-gray-400">{% translate 'current expenses' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
{% if account.expense_current != 0 %} {% if account.expense_current != 0 %}
<div class="text-end font-monospace tw:text-red-400"> <div class="tw:text-end tw:font-mono tw:text-red-400">
<c-amount.display <c-amount.display
:amount="account.expense_current" :amount="account.expense_current"
:prefix="account.currency.prefix" :prefix="account.currency.prefix"
@@ -129,11 +129,11 @@
:decimal_places="account.currency.decimal_places"></c-amount.display> :decimal_places="account.currency.decimal_places"></c-amount.display>
</div> </div>
{% else %} {% else %}
<div class="text-end font-monospace">-</div> <div class="tw:text-end tw:font-mono">-</div>
{% endif %} {% endif %}
</div> </div>
{% if account.exchanged and account.exchanged.expense_current %} {% if account.exchanged and account.exchanged.expense_current %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="account.exchanged.expense_current" :amount="account.exchanged.expense_current"
:prefix="account.exchanged.currency.prefix" :prefix="account.exchanged.currency.prefix"
@@ -141,12 +141,12 @@
:decimal_places="account.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="account.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'current total' %}</div> <div class="tw:text-gray-400">{% translate 'current total' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<c-amount.display <c-amount.display
:amount="account.total_current" :amount="account.total_current"
:prefix="account.currency.prefix" :prefix="account.currency.prefix"
@@ -156,7 +156,7 @@
</div> </div>
</div> </div>
{% if account.exchanged and account.exchanged.total_current %} {% if account.exchanged and account.exchanged.total_current %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="account.exchanged.total_current" :amount="account.exchanged.total_current"
:prefix="account.exchanged.currency.prefix" :prefix="account.exchanged.currency.prefix"
@@ -165,13 +165,13 @@
</div> </div>
{% endif %} {% endif %}
<div> <div>
<hr class="my-3"> <hr class="tw:my-3">
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'final total' %}</div> <div class="tw:text-gray-400">{% translate 'final total' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<c-amount.display <c-amount.display
:amount="account.total_final" :amount="account.total_final"
:prefix="account.currency.prefix" :prefix="account.currency.prefix"
@@ -181,7 +181,7 @@
</div> </div>
</div> </div>
{% if account.exchanged and account.exchanged.total_final %} {% if account.exchanged and account.exchanged.total_final %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="account.exchanged.total_final" :amount="account.exchanged.total_final"
:prefix="account.exchanged.currency.prefix" :prefix="account.exchanged.currency.prefix"
@@ -191,7 +191,7 @@
{% endif %} {% endif %}
</div> </div>
{% with p=percentages|get_dict_item:account_id %} {% with p=percentages|get_dict_item:account_id %}
<div class="my-3"> <div class="tw:my-3">
<c-ui.percentage-distribution :percentage="p"></c-ui.percentage-distribution> <c-ui.percentage-distribution :percentage="p"></c-ui.percentage-distribution>
</div> </div>
{% endwith %} {% endwith %}

View File

@@ -1,5 +1,5 @@
<div class="card tw:relative h-100 shadow"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:relative tw:h-full">
<div class="card-body"> <div class="tw:card-body">
{{ slot }} {{ slot }}
</div> </div>
</div> </div>

View File

@@ -1,17 +1,17 @@
{% load tools %} {% load tools %}
{% load i18n %} {% load i18n %}
<div class="col card shadow"> <div class="col tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title"> <h5 class="tw:card-title">
{{ currency.currency.name }} {{ currency.currency.name }}
</h5> </h5>
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'projected income' %}</div> <div class="tw:text-gray-400">{% translate 'projected income' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
{% if currency.income_projected != 0 %} {% if currency.income_projected != 0 %}
<div class="text-end font-monospace tw:text-green-400"> <div class="tw:text-end tw:font-mono tw:text-green-400">
<c-amount.display <c-amount.display
:amount="currency.income_projected" :amount="currency.income_projected"
:prefix="currency.currency.prefix" :prefix="currency.currency.prefix"
@@ -19,11 +19,11 @@
:decimal_places="currency.currency.decimal_places"></c-amount.display> :decimal_places="currency.currency.decimal_places"></c-amount.display>
</div> </div>
{% else %} {% else %}
<div class="text-end font-monospace">-</div> <div class="tw:text-end tw:font-mono">-</div>
{% endif %} {% endif %}
</div> </div>
{% if currency.exchanged and currency.exchanged.income_projected %} {% if currency.exchanged and currency.exchanged.income_projected %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="currency.exchanged.income_projected" :amount="currency.exchanged.income_projected"
:prefix="currency.exchanged.currency.prefix" :prefix="currency.exchanged.currency.prefix"
@@ -31,14 +31,14 @@
:decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'projected expenses' %}</div> <div class="tw:text-gray-400">{% translate 'projected expenses' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
<div> <div>
{% if currency.expense_projected != 0 %} {% if currency.expense_projected != 0 %}
<div class="text-end font-monospace tw:text-red-400"> <div class="tw:text-end tw:font-mono tw:text-red-400">
<c-amount.display <c-amount.display
:amount="currency.expense_projected" :amount="currency.expense_projected"
:prefix="currency.currency.prefix" :prefix="currency.currency.prefix"
@@ -46,12 +46,12 @@
:decimal_places="currency.currency.decimal_places"></c-amount.display> :decimal_places="currency.currency.decimal_places"></c-amount.display>
</div> </div>
{% else %} {% else %}
<div class="text-end font-monospace">-</div> <div class="tw:text-end tw:font-mono">-</div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% if currency.exchanged and currency.exchanged.expense_projected %} {% if currency.exchanged and currency.exchanged.expense_projected %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="currency.exchanged.expense_projected" :amount="currency.exchanged.expense_projected"
:prefix="currency.exchanged.currency.prefix" :prefix="currency.exchanged.currency.prefix"
@@ -59,12 +59,12 @@
:decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'projected total' %}</div> <div class="tw:text-gray-400">{% translate 'projected total' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<c-amount.display <c-amount.display
:amount="currency.total_projected" :amount="currency.total_projected"
:prefix="currency.currency.prefix" :prefix="currency.currency.prefix"
@@ -74,7 +74,7 @@
</div> </div>
</div> </div>
{% if currency.exchanged.total_projected and currency.exchanged.total_projected %} {% if currency.exchanged.total_projected and currency.exchanged.total_projected %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="currency.exchanged.total_projected" :amount="currency.exchanged.total_projected"
:prefix="currency.exchanged.currency.prefix" :prefix="currency.exchanged.currency.prefix"
@@ -82,14 +82,14 @@
:decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<hr class="my-3"> <hr class="tw:my-3">
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'current income' %}</div> <div class="tw:text-gray-400">{% translate 'current income' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
{% if currency.income_current != 0 %} {% if currency.income_current != 0 %}
<div class="text-end font-monospace tw:text-green-400"> <div class="tw:text-end tw:font-mono tw:text-green-400">
<c-amount.display <c-amount.display
:amount="currency.income_current" :amount="currency.income_current"
:prefix="currency.currency.prefix" :prefix="currency.currency.prefix"
@@ -97,11 +97,11 @@
:decimal_places="currency.currency.decimal_places"></c-amount.display> :decimal_places="currency.currency.decimal_places"></c-amount.display>
</div> </div>
{% else %} {% else %}
<div class="text-end font-monospace">-</div> <div class="tw:text-end tw:font-mono">-</div>
{% endif %} {% endif %}
</div> </div>
{% if currency.exchanged and currency.exchanged.income_current %} {% if currency.exchanged and currency.exchanged.income_current %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="currency.exchanged.income_current" :amount="currency.exchanged.income_current"
:prefix="currency.exchanged.currency.prefix" :prefix="currency.exchanged.currency.prefix"
@@ -109,13 +109,13 @@
:decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'current expenses' %}</div> <div class="tw:text-gray-400">{% translate 'current expenses' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
{% if currency.expense_current != 0 %} {% if currency.expense_current != 0 %}
<div class="text-end font-monospace tw:text-red-400"> <div class="tw:text-end tw:font-mono tw:text-red-400">
<c-amount.display <c-amount.display
:amount="currency.expense_current" :amount="currency.expense_current"
:prefix="currency.currency.prefix" :prefix="currency.currency.prefix"
@@ -123,11 +123,11 @@
:decimal_places="currency.currency.decimal_places"></c-amount.display> :decimal_places="currency.currency.decimal_places"></c-amount.display>
</div> </div>
{% else %} {% else %}
<div class="text-end font-monospace">-</div> <div class="tw:text-end tw:font-mono">-</div>
{% endif %} {% endif %}
</div> </div>
{% if currency.exchanged and currency.exchanged.expense_current %} {% if currency.exchanged and currency.exchanged.expense_current %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="currency.exchanged.expense_current" :amount="currency.exchanged.expense_current"
:prefix="currency.exchanged.currency.prefix" :prefix="currency.exchanged.currency.prefix"
@@ -135,12 +135,12 @@
:decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display> :decimal_places="currency.exchanged.currency.decimal_places"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'current total' %}</div> <div class="tw:text-gray-400">{% translate 'current total' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<c-amount.display <c-amount.display
:amount="currency.total_current" :amount="currency.total_current"
:prefix="currency.currency.prefix" :prefix="currency.currency.prefix"
@@ -150,7 +150,7 @@
</div> </div>
</div> </div>
{% if currency.exchanged and currency.exchanged.total_current %} {% if currency.exchanged and currency.exchanged.total_current %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="currency.exchanged.total_current" :amount="currency.exchanged.total_current"
:prefix="currency.exchanged.currency.prefix" :prefix="currency.exchanged.currency.prefix"
@@ -159,13 +159,13 @@
</div> </div>
{% endif %} {% endif %}
<div> <div>
<hr class="my-3"> <hr class="tw:my-3">
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="tw:flex tw:justify-between tw:items-baseline tw:mt-2">
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<div class="tw:text-gray-400">{% translate 'final total' %}</div> <div class="tw:text-gray-400">{% translate 'final total' %}</div>
</div> </div>
<div class="dotted-line flex-grow-1"></div> <div class="dotted-line tw:flex-grow"></div>
<div class="text-end font-monospace"> <div class="tw:text-end tw:font-mono">
<c-amount.display <c-amount.display
:amount="currency.total_final" :amount="currency.total_final"
:prefix="currency.currency.prefix" :prefix="currency.currency.prefix"
@@ -175,7 +175,7 @@
</div> </div>
</div> </div>
{% if currency.exchanged and currency.exchanged.total_final %} {% if currency.exchanged and currency.exchanged.total_final %}
<div class="text-end font-monospace tw:text-gray-500"> <div class="tw:text-end tw:font-mono tw:text-gray-500">
<c-amount.display <c-amount.display
:amount="currency.exchanged.total_final" :amount="currency.exchanged.total_final"
:prefix="currency.exchanged.currency.prefix" :prefix="currency.exchanged.currency.prefix"
@@ -185,7 +185,7 @@
{% endif %} {% endif %}
</div> </div>
{% with p=percentages|get_dict_item:currency_id %} {% with p=percentages|get_dict_item:currency_id %}
<div class="my-3"> <div class="tw:my-3">
<c-ui.percentage-distribution :percentage="p"></c-ui.percentage-distribution> <c-ui.percentage-distribution :percentage="p"></c-ui.percentage-distribution>
</div> </div>
{% endwith %} {% endwith %}

View File

@@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
<div class="tw:sticky tw:bottom-4 tw:left-0 tw:right-0 tw:z-50 tw:hidden mx-auto tw:w-fit" id="actions-bar" <div class="tw:sticky tw:bottom-4 tw:left-0 tw:right-0 tw:z-50 tw:hidden tw:mx-auto tw:w-fit" id="actions-bar"
_="on change from #transactions-list or htmx:afterSettle from window _="on change from #transactions-list or htmx:afterSettle from window
if #actions-bar then if #actions-bar then
if no <input[type='checkbox']:checked/> in #transactions-list if no <input[type='checkbox']:checked/> in #transactions-list
@@ -16,38 +16,38 @@
end end
end end
end"> end">
<div class="card slide-in-bottom"> <div class="tw:card tw:bg-base-100 tw:shadow slide-in-bottom">
<div class="card-body p-2 d-flex justify-content-between align-items-center gap-3"> <div class="tw:card-body tw:p-2 tw:flex tw:justify-between tw:items-center tw:gap-3">
{% spaceless %} {% spaceless %}
<div class="dropdown"> <div class="tw:dropdown">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" <button tabindex="0" role="button" class="tw:btn tw:btn-secondary tw:btn-sm" type="button">
aria-expanded="false">
<i class="fa-regular fa-square-check fa-fw"></i> <i class="fa-regular fa-square-check fa-fw"></i>
<i class="fa-solid fa-chevron-down fa-xs"></i>
</button> </button>
<ul class="dropdown-menu"> <ul tabindex="0" class="tw:dropdown-content tw:menu tw:bg-base-100 tw:rounded-box tw:z-[1] tw:w-52 tw:p-2 tw:shadow">
<li> <li>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:cursor-pointer"
_="on click set <#transactions-list input[type='checkbox']/>'s checked to true then call me.blur() then trigger change"> _="on click set <#transactions-list input[type='checkbox']/>'s checked to true then call me.blur() then trigger change">
<i class="fa-regular fa-square-check tw:text-green-400 me-3"></i>{% translate 'Select All' %} <i class="fa-regular fa-square-check tw:text-green-400 tw:me-3"></i>{% translate 'Select All' %}
</div> </a>
</li> </li>
<li> <li>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:cursor-pointer"
_="on click set <#transactions-list input[type='checkbox']/>'s checked to false then call me.blur() then trigger change"> _="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 tw:text-red-400 me-3"></i>{% translate 'Unselect All' %} <i class="fa-regular fa-square tw:text-red-400 tw:me-3"></i>{% translate 'Unselect All' %}
</div> </a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="vr tw:align-middle"></div> <div class="tw:divider tw:divider-horizontal tw:m-0"></div>
<button class="btn btn-secondary btn-sm" <button class="tw:btn tw:btn-secondary tw:btn-sm"
hx-get="{% url 'transactions_bulk_undelete' %}" hx-get="{% url 'transactions_bulk_undelete' %}"
hx-include=".transaction" hx-include=".transaction"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate 'Restore' %}"> data-bs-title="{% translate 'Restore' %}">
<i class="fa-solid fa-trash-arrow-up fa-fw"></i> <i class="fa-solid fa-trash-arrow-up fa-fw"></i>
</button> </button>
<button class="btn btn-secondary btn-sm" <button class="tw:btn tw:btn-secondary tw:btn-sm"
hx-get="{% url 'transactions_bulk_delete' %}" hx-get="{% url 'transactions_bulk_delete' %}"
hx-include=".transaction" hx-include=".transaction"
hx-trigger="confirmed" hx-trigger="confirmed"
@@ -58,10 +58,10 @@
data-text="{% translate "You won't be able to revert this!" %}" data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete them!" %}" data-confirm-text="{% translate "Yes, delete them!" %}"
_="install prompt_swal"> _="install prompt_swal">
<i class="fa-solid fa-trash text-danger"></i> <i class="fa-solid fa-trash tw:text-error"></i>
</button> </button>
<div class="vr tw:align-middle"></div> <div class="tw:divider tw:divider-horizontal tw:m-0"></div>
<div class="btn-group" <div class="tw:dropdown tw:dropdown-end"
_="on selected_transactions_updated from #actions-bar _="on selected_transactions_updated from #actions-bar
set realTotal to math.bignumber(0) set realTotal to math.bignumber(0)
set flatTotal to math.bignumber(0) set flatTotal to math.bignumber(0)
@@ -99,29 +99,28 @@
put mean.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-mean's innerText put mean.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-mean's innerText
put flatAmountValues.length.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-count's innerText put flatAmountValues.length.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-count's innerText
end"> end">
<button class="btn btn-secondary btn-sm" _="on click <button class="tw:btn tw:btn-secondary tw:btn-sm" _="on click
set original_value to #real-total-front's innerText set original_value to #real-total-front's innerText
writeText(original_value) on navigator.clipboard writeText(original_value) on navigator.clipboard
put '{% translate "copied!" %}' into #real-total-front's innerText put '{% translate "copied!" %}' into #real-total-front's innerText
wait 1s wait 1s
put original_value into #real-total-front's innerText put original_value into #real-total-front's innerText
end"> end">
<i class="fa-solid fa-plus fa-fw me-md-2 text-primary"></i> <i class="fa-solid fa-plus fa-fw tw:me-md-2 tw:text-primary"></i>
<span class="d-none d-md-inline-block" id="real-total-front">0</span> <span class="tw:hidden tw:md:inline-block" id="real-total-front">0</span>
</button> </button>
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split" <button type="button" tabindex="0" role="button" class="tw:btn tw:btn-sm tw:btn-secondary">
data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside"> <i class="fa-solid fa-chevron-down fa-xs"></i>
<span class="visually-hidden">{% trans "Toggle Dropdown" %}</span>
</button> </button>
<ul class="dropdown-menu"> <ul tabindex="0" class="tw:dropdown-content tw:menu tw:bg-base-100 tw:rounded-box tw:z-[1] tw:w-52 tw:shadow">
<li> <li>
<div class="dropdown-item-text p-0"> <div class="tw:p-0">
<div> <div>
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
{% trans "Flat Total" %} {% trans "Flat Total" %}
</div> </div>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:px-3 tw:cursor-pointer"
id="calc-menu-flat-total" id="calc-menu-flat-total"
_="on click _="on click
set original_value to my innerText set original_value to my innerText
@@ -131,17 +130,17 @@
put original_value into me put original_value into me
end"> end">
0 0
</div> </a>
</div> </div>
</div> </div>
</li> </li>
<li> <li>
<div class="dropdown-item-text p-0"> <div class="tw:p-0">
<div> <div>
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
{% trans "Real Total" %} {% trans "Real Total" %}
</div> </div>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:px-3 tw:cursor-pointer"
id="calc-menu-real-total" id="calc-menu-real-total"
_="on click _="on click
set original_value to my innerText set original_value to my innerText
@@ -151,17 +150,17 @@
put original_value into me put original_value into me
end"> end">
0 0
</div> </a>
</div> </div>
</div> </div>
</li> </li>
<li> <li>
<div class="dropdown-item-text p-0"> <div class="tw:p-0">
<div> <div>
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
{% trans "Mean" %} {% trans "Mean" %}
</div> </div>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:px-3 tw:cursor-pointer"
id="calc-menu-mean" id="calc-menu-mean"
_="on click _="on click
set original_value to my innerText set original_value to my innerText
@@ -171,17 +170,17 @@
put original_value into me put original_value into me
end"> end">
0 0
</div> </a>
</div> </div>
</div> </div>
</li> </li>
<li> <li>
<div class="dropdown-item-text p-0"> <div class="tw:p-0">
<div> <div>
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
{% trans "Max" %} {% trans "Max" %}
</div> </div>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:px-3 tw:cursor-pointer"
id="calc-menu-max" id="calc-menu-max"
_="on click _="on click
set original_value to my innerText set original_value to my innerText
@@ -191,17 +190,17 @@
put original_value into me put original_value into me
end"> end">
0 0
</div> </a>
</div> </div>
</div> </div>
</li> </li>
<li> <li>
<div class="dropdown-item-text p-0"> <div class="tw:p-0">
<div> <div>
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
{% trans "Min" %} {% trans "Min" %}
</div> </div>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:px-3 tw:cursor-pointer"
id="calc-menu-min" id="calc-menu-min"
_="on click _="on click
set original_value to my innerText set original_value to my innerText
@@ -211,17 +210,17 @@
put original_value into me put original_value into me
end"> end">
0 0
</div> </a>
</div> </div>
</div> </div>
</li> </li>
<li> <li>
<div class="dropdown-item-text p-0"> <div class="tw:p-0">
<div> <div>
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
{% trans "Count" %} {% trans "Count" %}
</div> </div>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:px-3 tw:cursor-pointer"
id="calc-menu-count" id="calc-menu-count"
_="on click _="on click
set original_value to my innerText set original_value to my innerText
@@ -231,7 +230,7 @@
put original_value into me put original_value into me
end"> end">
0 0
</div> </a>
</div> </div>
</div> </div>
</li> </li>

View File

@@ -1,8 +1,8 @@
{% spaceless %} {% spaceless %}
{% load i18n %} {% load i18n %}
<span class="tw:text-xs text-white-50 mx-1" <div class="tw:tooltip" data-tip="{{ content }}">
data-bs-toggle="tooltip" <span class="tw:text-xs tw:text-base-content/50 tw:mx-3">
data-bs-title="{{ content }}">
<i class="{% if not icon %}fa-solid fa-circle-question{% else %}{{ icon }}{% endif %} fa-fw"></i> <i class="{% if not icon %}fa-solid fa-circle-question{% else %}{{ icon }}{% endif %} fa-fw"></i>
</span> </span>
</div>
{% endspaceless %} {% endspaceless %}

View File

@@ -1,9 +1,9 @@
<div class="card tw:relative h-100 shadow"> <div class="tw:card tw:relative tw:h-full tw:shadow tw:bg-base-300">
<div class="tw:absolute tw:h-8 tw:w-8 tw:right-2 tw:top-2 tw:bg-{{ color }}-300 tw:text-{{ color }}-800 text-center align-items-center d-flex justify-content-center rounded-2"> <div class="tw:absolute tw:h-8 tw:w-8 tw:right-2 tw:top-2 tw:bg-{{ color }}-300 tw:text-{{ color }}-800 tw:text-center tw:flex tw:items-center tw:justify-center tw:rounded-lg">
{% if icon %}<i class="{{ icon }}"></i>{% else %}<span class="fw-bold">{{ title.0 }}</span>{% endif %} {% if icon %}<i class="{{ icon }}"></i>{% else %}<span class="tw:font-bold">{{ title.0 }}</span>{% endif %}
</div> </div>
<div class="card-body"> <div class="tw:card-body">
<h5 class="tw:text-{{ color }}-400 fw-bold tw:mr-[50px] {{ title_css_classes }}" {{ attrs }}>{{ title }}{% if help_text %}<c-ui.help-icon :content="help_text" icon=""></c-ui.help-icon>{% endif %}</h5> <h5 class="tw:text-{{ color }}-400 tw:font-bold tw:mr-[50px] {{ title_css_classes }}" {{ attrs }}>{{ title }}{% if help_text %}<c-ui.help-icon :content="help_text" icon=""></c-ui.help-icon>{% endif %}</h5>
{{ slot }} {{ slot }}
</div> </div>
</div> </div>

View File

@@ -1,31 +1,35 @@
{% load i18n %} {% load i18n %}
<div class="progress-stacked"> <div class="tw:flex tw:flex-col">
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Projected Income' %} ({{ percentage.percentages.income_projected|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.income_projected|floatformat:"2u" }}%"> <div class="tw:flex tw:relative" role="progressbar" aria-label="{% trans 'Projected Income' %} ({{ percentage.percentages.income_projected|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.income_projected|floatformat:"2u" }}%">
<div class="progress-bar progress-bar-striped tw:bg-green-300!" <div class="tw:h-6 tw:bg-green-300 tw:bg-striped"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-placement="top" data-bs-placement="top"
title="{% trans 'Projected Income' %} ({{ percentage.percentages.income_projected|floatformat:2 }}%)"> title="{% trans 'Projected Income' %} ({{ percentage.percentages.income_projected|floatformat:2 }}%)"
style="width: 100%">
</div> </div>
</div> </div>
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Current Income' %} ({{ percentage.percentages.income_current|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.income_current|floatformat:"2u" }}%"> <div class="tw:flex tw:relative" role="progressbar" aria-label="{% trans 'Current Income' %} ({{ percentage.percentages.income_current|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.income_current|floatformat:"2u" }}%">
<div class="progress-bar tw:bg-green-400!" <div class="tw:h-6 tw:bg-green-400"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-placement="top" data-bs-placement="top"
title="{% trans 'Current Income' %} ({{ p.percentages.income_current|floatformat:2 }}%)"> title="{% trans 'Current Income' %} ({{ p.percentages.income_current|floatformat:2 }}%)"
style="width: 100%">
</div> </div>
</div> </div>
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Projected Expenses' %} ({{ percentage.percentages.expense_projected|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.expense_projected|floatformat:"2u" }}%"> <div class="tw:flex tw:relative" role="progressbar" aria-label="{% trans 'Projected Expenses' %} ({{ percentage.percentages.expense_projected|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.expense_projected|floatformat:"2u" }}%">
<div class="progress-bar progress-bar-striped tw:bg-red-300!" <div class="tw:h-6 tw:bg-red-300 tw:bg-striped"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-placement="top" data-bs-placement="top"
title="{% trans 'Projected Expenses' %} ({{ percentage.percentages.expense_projected|floatformat:2 }}%)"> title="{% trans 'Projected Expenses' %} ({{ percentage.percentages.expense_projected|floatformat:2 }}%)"
style="width: 100%">
</div> </div>
</div> </div>
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Current Expenses' %} ({{ percentage.percentages.expense_current|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.expense_current|floatformat:"2u" }}%"> <div class="tw:flex tw:relative" role="progressbar" aria-label="{% trans 'Current Expenses' %} ({{ percentage.percentages.expense_current|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.expense_current|floatformat:"2u" }}%">
<div class="progress-bar tw:bg-red-400!" <div class="tw:h-6 tw:bg-red-400"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-placement="top" data-bs-placement="top"
title="{% trans 'Current Expenses' %} ({{ percentage.percentages.expense_current|floatformat:2 }}%)"> title="{% trans 'Current Expenses' %} ({{ percentage.percentages.expense_current|floatformat:2 }}%)"
style="width: 100%">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,49 +1,49 @@
{% load i18n %} {% load i18n %}
<div class="d-grid gap-2 d-xl-flex justify-content-xl-end"> <div class="tw:grid tw:gap-2 tw:grid-cols-1 tw:xl:flex tw:xl:justify-end">
<div class="d-grid gap-2 d-xl-flex flex-wrap justify-content-xl-center"> <div class="tw:grid tw:gap-2 tw:xl:flex tw:flex-wrap tw:xl:justify-center">
<button class="btn btn-sm btn-outline-success" <button class="tw:btn tw:btn-sm tw:btn-outline tw:btn-success"
hx-get="{% url 'transaction_add' %}" hx-get="{% url 'transaction_add' %}"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-trigger="click, add_income from:window" hx-trigger="click, add_income from:window"
hx-vals='{"year": {{ year }}, {% if month %}"month": {{ month }},{% endif %} "type": "IN"}'> hx-vals='{"year": {{ year }}, {% if month %}"month": {{ month }},{% endif %} "type": "IN"}'>
<i class="fa-solid fa-arrow-right-to-bracket me-2"></i> <i class="fa-solid fa-arrow-right-to-bracket tw:me-2"></i>
{% translate "Income" %} {% translate "Income" %}
</button> </button>
<button class="btn btn-sm btn-outline-danger" <button class="tw:btn tw:btn-sm tw:btn-outline tw:btn-error"
hx-get="{% url 'transaction_add' %}" hx-get="{% url 'transaction_add' %}"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-trigger="click, add_expense from:window" hx-trigger="click, add_expense from:window"
hx-vals='{"year": {{ year }}, {% if month %}"month": {{ month }},{% endif %} "type": "EX"}'> hx-vals='{"year": {{ year }}, {% if month %}"month": {{ month }},{% endif %} "type": "EX"}'>
<i class="fa-solid fa-arrow-right-from-bracket me-2"></i> <i class="fa-solid fa-arrow-right-from-bracket tw:me-2"></i>
{% translate "Expense" %} {% translate "Expense" %}
</button> </button>
<button class="btn btn-sm btn-outline-warning" <button class="tw:btn tw:btn-sm tw:btn-outline tw:btn-warning"
hx-get="{% url 'installment_plan_add' %}" hx-get="{% url 'installment_plan_add' %}"
hx-trigger="click, installment from:window" hx-trigger="click, installment from:window"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-divide me-2"></i> <i class="fa-solid fa-divide tw:me-2"></i>
{% translate "Installment" %} {% translate "Installment" %}
</button> </button>
<button class="btn btn-sm btn-outline-warning" <button class="tw:btn tw:btn-sm tw:btn-outline tw:btn-warning"
hx-get="{% url 'recurring_transaction_add' %}" hx-get="{% url 'recurring_transaction_add' %}"
hx-trigger="click, balance from:window" hx-trigger="click, balance from:window"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-repeat me-2"></i> <i class="fa-solid fa-repeat tw:me-2"></i>
{% translate "Recurring" %} {% translate "Recurring" %}
</button> </button>
<button class="btn btn-sm btn-outline-info" <button class="tw:btn tw:btn-sm tw:btn-outline tw:btn-info"
hx-get="{% url 'transactions_transfer' %}" hx-get="{% url 'transactions_transfer' %}"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-trigger="click, add_transfer from:window" hx-trigger="click, add_transfer from:window"
hx-vals='{"year": {{ year }} {% if month %}, "month": {{ month }}{% endif %}}'> hx-vals='{"year": {{ year }} {% if month %}, "month": {{ month }}{% endif %}}'>
<i class="fa-solid fa-money-bill-transfer me-2"></i> <i class="fa-solid fa-money-bill-transfer tw:me-2"></i>
{% translate "Transfer" %} {% translate "Transfer" %}
</button> </button>
<button class="btn btn-sm btn-outline-info" <button class="tw:btn tw:btn-sm tw:btn-outline tw:btn-info"
hx-get="{% url 'account_reconciliation' %}" hx-get="{% url 'account_reconciliation' %}"
hx-trigger="click, balance from:window" hx-trigger="click, balance from:window"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-scale-balanced me-2"></i> <i class="fa-solid fa-scale-balanced tw:me-2"></i>
{% translate "Balance" %} {% translate "Balance" %}
</button> </button>
</div> </div>

View File

@@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
<div class="tw:sticky tw:bottom-4 tw:left-0 tw:right-0 tw:z-50 tw:hidden mx-auto tw:w-fit" id="actions-bar" <div class="tw:sticky tw:bottom-4 tw:left-0 tw:right-0 tw:z-50 tw:hidden tw:mx-auto tw:w-fit" id="actions-bar"
_="on change from #transactions-list or htmx:afterSettle from window _="on change from #transactions-list or htmx:afterSettle from window
if #actions-bar then if #actions-bar then
if no <input[type='checkbox']:checked/> in #transactions-list if no <input[type='checkbox']:checked/> in #transactions-list
@@ -17,34 +17,34 @@
end end
end end
end"> end">
<div class="card slide-in-bottom tw:max-w-[90vw]"> <div class="tw:card tw:bg-base-300 tw:shadow slide-in-bottom tw:max-w-[90vw] tw:card-border">
<div class="card-body p-2 d-flex justify-content-between align-items-center gap-3 tw:overflow-x-auto"> <div class="tw:card-body tw:flex-row tw:p-2 tw:flex tw:justify-between tw:items-center tw:gap-3 tw:overflow-x-auto">
{% spaceless %} {% spaceless %}
<div class="tw:font-bold tw:text-md ms-2" id="selected-count">0</div> <div class="tw:font-bold tw:text-md tw:ms-2" id="selected-count">0</div>
<div class="vr tw:align-middle"></div> <div class="tw:divider tw:divider-horizontal tw:m-0"></div>
<div class="dropdown"> <div class="tw:dropdown tw:dropdown-top tw:dropdown-end">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" <button tabindex="0" role="button" class="tw:btn tw:btn-secondary tw:btn-sm" type="button">
aria-expanded="false" data-bs-popper-config='{"strategy":"fixed"}'>
<i class="fa-regular fa-square-check fa-fw"></i> <i class="fa-regular fa-square-check fa-fw"></i>
<i class="fa-solid fa-chevron-down fa-xs"></i>
</button> </button>
<ul class="dropdown-menu"> <ul tabindex="0" class="tw:dropdown-content tw:menu tw:bg-base-300 tw:rounded-box tw:z-[1] tw:w-full tw:p-2 tw:shadow tw:fixed!">
<li> <li>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw: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"> _="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 tw:text-green-400 me-3"></i>{% translate 'Select All' %} <i class="fa-regular fa-square-check tw:text-green-400 tw:me-3"></i>{% translate 'Select All' %}
</div> </a>
</li> </li>
<li> <li>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:cursor-pointer"
_="on click set <#transactions-list input[type='checkbox']/>'s checked to false then call me.blur() then trigger change"> _="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 tw:text-red-400 me-3"></i>{% translate 'Unselect All' %} <i class="fa-regular fa-square tw:text-red-400 tw:me-3"></i>{% translate 'Unselect All' %}
</div> </a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="vr tw:align-middle"></div> <div class="tw:divider tw:divider-horizontal tw:m-0"></div>
<div class="btn-group"> <div class="tw:join">
<button class="btn btn-secondary btn-sm" <button class="tw:btn tw:btn-secondary tw:join-item tw:btn-sm"
hx-get="{% url 'transactions_bulk_edit' %}" hx-get="{% url 'transactions_bulk_edit' %}"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-include=".transaction" hx-include=".transaction"
@@ -52,37 +52,37 @@
data-bs-title="{% translate 'Edit' %}"> data-bs-title="{% translate 'Edit' %}">
<i class="fa-solid fa-pencil"></i> <i class="fa-solid fa-pencil"></i>
</button> </button>
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split" <div class="tw:dropdown tw:dropdown-top tw:dropdown-end">
data-bs-toggle="dropdown" data-bs-popper-config='{"strategy":"fixed"}' aria-expanded="false" <button type="button" tabindex="0" role="button" class="tw:join-item tw:btn tw:btn-sm tw:btn-secondary">
data-bs-auto-close="outside"> <i class="fa-solid fa-chevron-down fa-xs"></i>
<span class="visually-hidden">{% trans "Toggle Dropdown" %}</span> </button>
</button>
<ul class="dropdown-menu"> <ul tabindex="0" class="tw:dropdown-content tw:fixed! tw:menu tw:bg-base-300 tw:rounded-box tw:z-[1] tw:w-full tw:p-2 tw:shadow">
<li> <li>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:cursor-pointer"
hx-get="{% url 'transactions_bulk_unpay' %}" hx-get="{% url 'transactions_bulk_unpay' %}"
hx-include=".transaction"> hx-include=".transaction">
<i class="fa-regular fa-circle tw:text-red-400 fa-fw me-3"></i>{% translate 'Mark as unpaid' %} <i class="fa-regular fa-circle tw:text-red-400 fa-fw tw:me-3"></i>{% translate 'Mark as unpaid' %}
</div> </a>
</li> </li>
<li> <li>
<div class="dropdown-item px-3 tw:cursor-pointer" <a class="tw:cursor-pointer"
hx-get="{% url 'transactions_bulk_pay' %}" hx-get="{% url 'transactions_bulk_pay' %}"
hx-include=".transaction"> hx-include=".transaction">
<i class="fa-regular fa-circle-check tw:text-green-400 fa-fw me-3"></i>{% translate 'Mark as paid' %} <i class="fa-regular fa-circle-check tw:text-green-400 fa-fw tw:me-3"></i>{% translate 'Mark as paid' %}
</div> </a>
</li> </li>
</ul> </ul>
</div>
</div> </div>
<button class="btn btn-secondary btn-sm" <button class="tw:btn tw:btn-secondary tw:btn-sm"
hx-get="{% url 'transactions_bulk_clone' %}" hx-get="{% url 'transactions_bulk_clone' %}"
hx-include=".transaction" hx-include=".transaction"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate 'Duplicate' %}"> data-bs-title="{% translate 'Duplicate' %}">
<i class="fa-solid fa-clone fa-fw"></i> <i class="fa-solid fa-clone fa-fw"></i>
</button> </button>
<button class="btn btn-secondary btn-sm" <button class="tw:btn tw:btn-secondary tw:btn-sm"
hx-get="{% url 'transactions_bulk_delete' %}" hx-get="{% url 'transactions_bulk_delete' %}"
hx-include=".transaction" hx-include=".transaction"
hx-trigger="confirmed" hx-trigger="confirmed"
@@ -93,10 +93,10 @@
data-text="{% translate "You won't be able to revert this!" %}" data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete them!" %}" data-confirm-text="{% translate "Yes, delete them!" %}"
_="install prompt_swal"> _="install prompt_swal">
<i class="fa-solid fa-trash text-danger"></i> <i class="fa-solid fa-trash tw:text-error"></i>
</button> </button>
<div class="vr tw:align-middle"></div> <div class="tw:divider tw:divider-horizontal tw:m-0"></div>
<div class="btn-group" <div class="tw:join"
_="on selected_transactions_updated from #actions-bar _="on selected_transactions_updated from #actions-bar
set realTotal to math.bignumber(0) set realTotal to math.bignumber(0)
set flatTotal to math.bignumber(0) set flatTotal to math.bignumber(0)
@@ -134,144 +134,145 @@
put mean.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-mean's innerText put mean.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-mean's innerText
put flatAmountValues.length.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-count's innerText put flatAmountValues.length.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-count's innerText
end"> end">
<button class="btn btn-secondary btn-sm" _="on click <button class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
_="on click
set original_value to #real-total-front's innerText set original_value to #real-total-front's innerText
writeText(original_value) on navigator.clipboard writeText(original_value) on navigator.clipboard
put '{% translate "copied!" %}' into #real-total-front's innerText put '{% translate "copied!" %}' into #real-total-front's innerText
wait 1s wait 1s
put original_value into #real-total-front's innerText put original_value into #real-total-front's innerText
end"> end">
<i class="fa-solid fa-plus fa-fw me-md-2 text-primary"></i> <i class="fa-solid fa-plus fa-fw tw:me-md-2 tw:text-primary"></i>
<span class="d-none d-md-inline-block" id="real-total-front">0</span> <span class="tw:hidden tw:md:inline-block" id="real-total-front">0</span>
</button>
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside"
data-bs-popper-config='{"strategy":"fixed"}'>
<span class="visually-hidden">{% trans "Toggle Dropdown" %}</span>
</button> </button>
<div class="tw:dropdown tw:dropdown-end tw:dropdown-top">
<button type="button" tabindex="0" role="button" class="tw:join-item tw:btn tw:btn-sm tw:btn-secondary">
<i class="fa-solid fa-chevron-down fa-xs"></i>
</button>
<ul class="dropdown-menu"> <ul tabindex="0" class="tw:dropdown-content tw:menu tw:bg-base-300 tw:rounded-box tw:z-[1] tw:w-full tw:shadow tw:fixed!">
<li> <li class="tw:cursor-pointer"
<div class="dropdown-item-text p-0"> _="on click
<div> set original_value to #calc-menu-flat-total's innerText
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> writeText(original_value) on navigator.clipboard
{% trans "Flat Total" %} put '{% translate "copied!" %}' into #calc-menu-flat-total
</div> wait 1s
<div class="dropdown-item px-3 tw:cursor-pointer" put original_value into #calc-menu-flat-total
id="calc-menu-flat-total" end">
_="on click <div class="tw:p-0">
set original_value to my innerText <div>
writeText(my innerText) on navigator.clipboard <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
put '{% translate "copied!" %}' into me {% trans "Flat Total" %}
wait 1s </div>
put original_value into me <div class="tw:px-3"
end"> id="calc-menu-flat-total">
0 0
</div>
</div> </div>
</div> </div>
</div> </li>
</li> <li class="tw:cursor-pointer"
<li> _="on click
<div class="dropdown-item-text p-0"> set original_value to #calc-menu-real-total's innerText
<div> writeText(original_value) on navigator.clipboard
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> put '{% translate "copied!" %}' into #calc-menu-real-total
{% trans "Real Total" %} wait 1s
</div> put original_value into #calc-menu-real-total
<div class="dropdown-item px-3 tw:cursor-pointer" end">
id="calc-menu-real-total" <div class="tw:p-0">
_="on click <div>
set original_value to my innerText <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
writeText(my innerText) on navigator.clipboard {% trans "Real Total" %}
put '{% translate "copied!" %}' into me </div>
wait 1s <div class="tw:px-3"
put original_value into me id="calc-menu-real-total">
end"> 0
0 </div>
</div> </div>
</div> </div>
</div> </li>
</li> <li class="tw:cursor-pointer"
<li> _="on click
<div class="dropdown-item-text p-0"> set original_value to #calc-menu-mean's innerText
<div> writeText(original_value) on navigator.clipboard
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> put '{% translate "copied!" %}' into #calc-menu-mean
{% trans "Mean" %} wait 1s
</div> put original_value into #calc-menu-mean
<div class="dropdown-item px-3 tw:cursor-pointer" end">
id="calc-menu-mean" <div class="tw:p-0">
_="on click <div>
set original_value to my innerText <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
writeText(my innerText) on navigator.clipboard {% trans "Mean" %}
put '{% translate "copied!" %}' into me </div>
wait 1s <div class="tw:px-3"
put original_value into me id="calc-menu-mean">
end"> 0
0 </div>
</div> </div>
</div> </div>
</div> </li>
</li> <li class="tw:cursor-pointer"
<li> _="on click
<div class="dropdown-item-text p-0"> set original_value to #calc-menu-max's innerText
<div> writeText(original_value) on navigator.clipboard
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> put '{% translate "copied!" %}' into #calc-menu-max
{% trans "Max" %} wait 1s
</div> put original_value into #calc-menu-max
<div class="dropdown-item px-3 tw:cursor-pointer" end">
id="calc-menu-max" <div class="tw:p-0">
_="on click <div>
set original_value to my innerText <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
writeText(my innerText) on navigator.clipboard {% trans "Max" %}
put '{% translate "copied!" %}' into me </div>
wait 1s <div class="tw:px-3"
put original_value into me id="calc-menu-max">
end"> 0
0 </div>
</div> </div>
</div> </div>
</div> </li>
</li> <li class="tw:cursor-pointer"
<li> _="on click
<div class="dropdown-item-text p-0"> set original_value to #calc-menu-min's innerText
<div> writeText(original_value) on navigator.clipboard
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> put '{% translate "copied!" %}' into #calc-menu-min
{% trans "Min" %} wait 1s
</div> put original_value into #calc-menu-min
<div class="dropdown-item px-3 tw:cursor-pointer" end">
id="calc-menu-min" <div class="tw:p-0">
_="on click <div>
set original_value to my innerText <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
writeText(my innerText) on navigator.clipboard {% trans "Min" %}
put '{% translate "copied!" %}' into me </div>
wait 1s <div class="tw:px-3"
put original_value into me id="calc-menu-min">
end"> 0
0 </div>
</div> </div>
</div> </div>
</div> </li>
</li> <li class="tw:cursor-pointer"
<li> _="on click
<div class="dropdown-item-text p-0"> set original_value to #calc-menu-count's innerText
<div> writeText(original_value) on navigator.clipboard
<div class="text-body-secondary tw:text-xs tw:font-medium px-3"> put '{% translate "copied!" %}' into #calc-menu-count
{% trans "Count" %} wait 1s
</div> put original_value into #calc-menu-count
<div class="dropdown-item px-3 tw:cursor-pointer" end">
id="calc-menu-count" <div class="tw:p-0">
_="on click <div>
set original_value to my innerText <div class="tw:text-base-content/60 tw:text-xs tw:font-medium tw:px-3">
writeText(my innerText) on navigator.clipboard {% trans "Count" %}
put '{% translate "copied!" %}' into me </div>
wait 1s <div class="tw:px-3"
put original_value into me id="calc-menu-count">
end"> 0
0 </div>
</div> </div>
</div> </div>
</div> </li>
</li> </ul>
</ul> </div>
</div> </div>
{% endspaceless %} {% endspaceless %}
</div> </div>

View File

@@ -10,7 +10,7 @@
title="{% translate "Income" %}"></c-components.fab_menu_button> title="{% translate "Income" %}"></c-components.fab_menu_button>
<c-components.fab_menu_button <c-components.fab_menu_button
color="danger" color="error"
hx_target="#generic-offcanvas" hx_target="#generic-offcanvas"
hx_trigger="click, add_income from:window" hx_trigger="click, add_income from:window"
hx_vals='{"year": {{ year }}, {% if month %}"month": {{ month }},{% endif %} "type": "EX"}' hx_vals='{"year": {{ year }}, {% if month %}"month": {{ month }},{% endif %} "type": "EX"}'

View File

@@ -0,0 +1,9 @@
<div class="tw:collapse tw:collapse-arrow tw:bg-base-100 tw:border tw:border-base-300{% if div.css_class %} {{div.css_class}}{% endif %}">
<input type="radio" name="{{ div.data_parent }}" {% if div.active %}checked="checked"{% endif %} />
<div class="tw:collapse-title tw:font-semibold">
{{ div.name }}
</div>
<div class="tw:collapse-content">
{{ fields|safe }}
</div>
</div>

View File

@@ -0,0 +1,3 @@
<div class="tw:join tw:join-vertical tw:w-full{% if accordion.css_class %} {{accordion.css_class}}{% endif %}" id="{{ accordion.css_id }}">
{{ content|safe }}
</div>

View File

@@ -0,0 +1,22 @@
{% for fieldset in form.fieldsets %}
<fieldset class="tw:fieldset fieldset-{{ forloop.counter }} {{ fieldset.classes }}">
{% if fieldset.legend %}
<legend class="tw:fieldset-legend">{{ fieldset.legend }}</legend>
{% endif %}
{% if fieldset.description %}
<p class="tw:text-sm tw:text-base-content/60">{{ fieldset.description }}</p>
{% endif %}
{% for field in fieldset %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% include "crispy-daisyui/field.html" %}
{% endif %}
{% endfor %}
{% if not forloop.last or not fieldset_open %}
</fieldset>
{% endif %}
{% endfor %}

View File

@@ -0,0 +1,9 @@
{% if form.form_html %}
{% if include_media %}{{ form.media }}{% endif %}
{% if form_show_errors %}
{% include "crispy-daisyui/errors.html" %}
{% endif %}
{{ form.form_html }}
{% else %}
{% include "crispy-daisyui/uni_form.html" %}
{% endif %}

View File

@@ -0,0 +1,8 @@
{% if form.non_field_errors %}
<div class="tw:alert tw:alert-error">
{% if form_error_title %}<h4 class="tw:font-bold">{{ form_error_title }}</h4>{% endif %}
<ul class="tw:m-0 tw:list-disc tw:list-inside">
{{ form.non_field_errors|unordered_list }}
</ul>
</div>
{% endif %}

View File

@@ -0,0 +1,9 @@
{% if formset.non_form_errors %}
<div class="tw:alert tw:alert-error">
{% if formset_error_title %}<h4 class="tw:font-bold">{{ formset_error_title }}</h4>{% endif %}
<ul class="tw:m-0 tw:list-disc tw:list-inside">
{{ formset.non_form_errors|unordered_list }}
</ul>
</div>
{% endif %}

View File

@@ -0,0 +1,71 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field|is_checkbox and tag != "td" %}
<div class="tw:mb-3">
{% if label_class %}
<div class="{{ field_class }}">
{% endif %}
{% endif %}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="{% if field|is_checkbox and form_show_labels %}tw:form-control{% else %}tw:mb-3{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and not field|is_checkbox and form_show_labels %}
{% if field.use_fieldset %}<fieldset class="tw:fieldset"{% if field.aria_describedby %} aria-describedby="{{ field.aria_describedby }}"{% endif %}>{% endif %}
<{% if field.use_fieldset %}legend{% else %}label{% endif %}
{% if field.id_for_label %}for="{{ field.id_for_label }}"{% endif %} class="tw:label{% if label_class %} {{ label_class }}{% endif %}{% if field.field.required %} requiredField{% endif %}">
{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</{% if field.use_fieldset %}legend{% else %}label{% endif %}>
{% endif %}
{% if field|is_checkboxselectmultiple or field|is_radioselect %}
{% include 'crispy-daisyui/layout/radio_checkbox_select.html' %}
{% endif %}
{% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
{% if field|is_checkbox and form_show_labels %}
{% if field.errors %}
{% crispy_field field 'class' 'tw:checkbox tw:checkbox-error' %}
{% else %}
{% crispy_field field 'class' 'tw:checkbox' %}
{% endif %}
<label for="{{ field.id_for_label }}" class="tw:label{% if field.field.required %} requiredField{% endif %}">
{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% include 'crispy-daisyui/layout/help_text_and_errors.html' %}
{% else %}
{% if field_class %}<div class="{{ field_class }}">{% endif %}
{% if field|is_file %}
{% include 'crispy-daisyui/layout/field_file.html' %}
{% elif field|is_select %}
{% if field.errors %}
{% crispy_field field 'class' 'tw:select tw:select-bordered tw:select-error tw:w-full' %}
{% else %}
{% crispy_field field 'class' 'tw:select tw:select-bordered tw:w-full' %}
{% endif %}
{% elif field|is_checkbox %}
{% if field.errors %}
{% crispy_field field 'class' 'tw:checkbox tw:checkbox-error' %}
{% else %}
{% crispy_field field 'class' 'tw:checkbox' %}
{% endif %}
{% elif field.errors %}
{% crispy_field field 'class' 'tw:input tw:input-bordered tw:input-error tw:w-full' %}
{% else %}
{% crispy_field field 'class' 'tw:input tw:input-bordered tw:w-full' %}
{% endif %}
{% if not field|is_file %}
{% include 'crispy-daisyui/layout/help_text_and_errors.html' %}
{% endif %}
{% if field_class %}</div>{% endif %}
{% endif %}
{% endif %}
{% if field.use_fieldset and field.label and form_show_labels %}</fieldset>{% endif %}
</{% if tag %}{{ tag }}{% else %}div{% endif %}>
{% if field|is_checkbox and tag != "td" %}
{% if label_class %}
</div>
{% endif %}
</div>
{% endif %}
{% endif %}

View File

@@ -0,0 +1,13 @@
{% if inputs %}
<div class="tw:mb-3">
{% if label_class %}
<div class="aab {{ label_class }}"></div>
{% endif %}
<div class="{{ field_class }}">
{% for input in inputs %}
{% include "crispy-daisyui/layout/baseinput.html" %}
{% endfor %}
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,4 @@
<div class="tw:alert {{ alert.css_class }}" role="alert"{% if alert.css_id %} id="{{ alert.css_id }}"{% endif %}>
{{ content|safe }}
{% if dismiss %}<button type="button" class="tw:btn tw:btn-sm tw:btn-circle tw:btn-ghost" data-bs-dismiss="alert" aria-label="Close"></button>{% endif %}
</div>

View File

@@ -0,0 +1 @@
{% for name, value in widget.attrs.items %}{% if value is not False %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %}

View File

@@ -0,0 +1,9 @@
<input type="{{ input.input_type }}"
name="{% if input.name|wordcount > 1 %}{{ input.name|slugify }}{% else %}{{ input.name }}{% endif %}"
value="{{ input.value }}"
{% if input.input_type != "hidden" %}
class="tw:btn {{ input.field_classes }}"
id="{% if input.id %}{{ input.id }}{% else %}{{ input.input_type }}-id-{{ input.name|slugify }}{% endif %}"
{% endif %}
{{ input.flat_attrs }}
/>

View File

@@ -0,0 +1 @@
<button class="tw:btn" {{ button.flat_attrs }}>{{ button.content|safe }}</button>

View File

@@ -0,0 +1,4 @@
<div {% if buttonholder.css_id %}id="{{ buttonholder.css_id }}"{% endif %}
class="tw:flex tw:gap-2{% if buttonholder.css_class %} {{ buttonholder.css_class }}{% endif %}">
{{ fields_output|safe }}
</div>

View File

@@ -0,0 +1,16 @@
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="tw:mb-3{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label %}
<fieldset class="tw:fieldset"{% if field.aria_describedby %} aria-describedby="{{ field.aria_describedby }}"{% endif %}>
<legend for="{{ field.id_for_label }}" class="tw:fieldset-legend {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</legend>
{% endif %}
{% include 'crispy-daisyui/layout/radio_checkbox_select.html' %}
{% if field.label %}</fieldset>{% endif %}
</div>
{% endif %}

View File

@@ -0,0 +1,6 @@
<div {% if div.css_id %}id="{{ div.css_id }}"{% endif %}
class="tw:col-span-12 {{ div.css_class|default:'' }}" {{ div.flat_attrs }}>
{{ fields|safe }}
</div>

View File

@@ -0,0 +1,4 @@
<div {% if div.css_id %}id="{{ div.css_id }}"{% endif %}
{% if div.css_class %}class="{{ div.css_class }}"{% endif %} {{ div.flat_attrs }}>
{{ fields|safe }}
</div>

View File

@@ -0,0 +1,12 @@
{% if form_show_errors and field.errors %}
{% if field.errors.field_id %}
{# Django 5.2+ #}
<div id="{{field.errors.field_id}}_error" class="tw:text-error tw:text-sm tw:mt-1">
{% else %}
<div id="{{field.auto_id}}_error" class="tw:text-error tw:text-sm tw:mt-1">
{% endif %}
{% for error in field.errors %}
<span id="error_{{ forloop.counter }}_{{ field.auto_id }}"><strong>{{ error }}</strong></span>
{% endfor %}
</div>
{% endif %}

View File

@@ -0,0 +1,12 @@
{% if form_show_errors and field.errors %}
{% if field.errors.field_id %}
{# Django 5.2+ #}
<div id="{{field.errors.field_id}}_error" class="tw:text-error tw:text-sm tw:mt-1">
{% else %}
<div id="{{field.auto_id}}_error" class="tw:text-error tw:text-sm tw:mt-1">
{% endif %}
{% for error in field.errors %}
<p id="error_{{ forloop.counter }}_{{ field.auto_id }}"><strong>{{ error }}</strong></p>
{% endfor %}
</div>
{% endif %}

View File

@@ -0,0 +1,26 @@
{% load crispy_forms_field %}
{% for widget in field.subwidgets %}
{% if widget.data.is_initial %}
<div class="tw:join tw:mb-2 tw:w-full">
<span class="tw:btn tw:btn-disabled tw:join-item">{{ widget.data.initial_text }}</span>
<div class="tw:input tw:input-bordered tw:join-item tw:flex tw:items-center tw:flex-grow">
<span class="tw:break-all tw:flex-grow">
<a href="{{ field.value.url }}" class="tw:link">{{ field.value.name }}</a>
</span>
{% if not widget.data.required %}
<span class="tw:ml-2">
<label class="tw:label tw:cursor-pointer tw:gap-2">
<input type="checkbox" name="{{ widget.data.checkbox_name }}" id="{{ widget.data.checkbox_id }}" class="tw:checkbox"{% if field.field.disabled %} disabled{% endif %} >
<span class="tw:label-text">{{ widget.data.clear_checkbox_label }}</span>
</label>
</span>
{% endif %}
</div>
</div>
{% endif %}
<div{% if field.errors %} class="tw:input-error"{%endif%}>
<input type="{{ widget.data.type }}" name="{{ widget.data.name }}" class="tw:file-input tw:file-input-bordered tw:w-full{% if widget.data.attrs.class %} {{ widget.data.attrs.class }}{% endif %}{% if field.errors %} tw:input-error{%endif%}"{% if field.field.disabled %} disabled{% endif %}{% for name, value in widget.data.attrs.items %}{% if value is not False and name != 'class' %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %}>
{% include 'crispy-daisyui/layout/help_text_and_errors.html' %}
</div>
{% endfor %}

View File

@@ -0,0 +1,39 @@
{% load crispy_forms_field %}
<div{% if div.css_id %} id="{{ div.css_id }}"{% endif %} class="tw:mb-3{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}{% if div.css_class %} {{ div.css_class }}{% endif %}" {{ div.flat_attrs }}>
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}" class="tw:label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<span class="tw:label-text">{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}</span>
</label>
{% endif %}
<div{% if field_class %} class="{{ field_class }}"{% endif %}>
<div class="tw:join tw:w-full{% if input_size %} {{ input_size }}{% endif %}">
{% if field|is_select %}
{% if field.errors %}
{% crispy_field field 'class' 'tw:select tw:select-bordered tw:select-error tw:join-item tw:flex-grow' %}
{% else %}
{% crispy_field field 'class' 'tw:select tw:select-bordered tw:join-item tw:flex-grow' %}
{% endif %}
{% else %}
{% if field.errors %}
{% crispy_field field 'class' 'tw:input tw:input-bordered tw:input-error tw:join-item tw:flex-grow' %}
{% else %}
{% crispy_field field 'class' 'tw:input tw:input-bordered tw:join-item tw:flex-grow' %}
{% endif %}
{% endif %}
{{ buttons|safe }}
</div>
{% if field.errors.field_id %}
{# Django 5.2+ #}
<div id="{{field.errors.field_id}}_error" class="tw:text-error tw:text-sm tw:mt-1">
{% else %}
<div id="{{field.auto_id}}_error" class="tw:text-error tw:text-sm tw:mt-1">
{% endif %}
{% for error in field.errors %}
<p id="error_{{ forloop.counter }}_{{ field.auto_id }}"><small><strong>{{ error }}</strong></small></p>
{% endfor %}
</div>
{% include 'crispy-daisyui/layout/help_text.html' %}
</div>
</div>

View File

@@ -0,0 +1,6 @@
<fieldset {% if fieldset.css_id %}id="{{ fieldset.css_id }}"{% endif %}
class="tw:fieldset{% if fieldset.css_class %} {{ fieldset.css_class }}{% endif %}"
{{ fieldset.flat_attrs }}>
{% if legend %}<legend class="tw:fieldset-legend">{{ legend|safe }}</legend>{% endif %}
{{ fields|safe }}
</fieldset>

View File

@@ -0,0 +1,28 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="tw:mb-3{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<label class="tw:input tw:input-bordered tw:flex tw:items-center tw:gap-2" {% if field.id_for_label %}for="{{ field.id_for_label }}"{% endif %}{% if label_class %} {{ label_class }}{% endif %}>
{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
{% if field|is_select %}
{%if field.errors %}
{% crispy_field field 'class' 'tw:select tw:select-bordered tw:select-error tw:grow' 'placeholder' field.name %}
{% else %}
{% crispy_field field 'class' 'tw:select tw:select-bordered tw:grow' 'placeholder' field.name %}
{% endif %}
{% else %}
{% if field.errors %}
{% crispy_field field 'class' 'tw:grow' 'placeholder' field.name %}
{% else %}
{% crispy_field field 'class' 'tw:grow' 'placeholder' field.name %}
{% endif %}
{% endif %}
</label>
{% include 'crispy-daisyui/layout/help_text_and_errors.html' %}
</{% if tag %}{{ tag }}{% else %}div{% endif %}>
{% endif %}

View File

@@ -0,0 +1,11 @@
<div
{% if formactions.flat_attrs %}{{ formactions.flat_attrs }}{% endif %}
class="tw:mb-3 tw:flex tw:gap-2 {{ formactions.css_class|default:'' }} {{ field_class }}"
{% if formactions.id %} id="{{ formactions.id }}"{% endif %}>
{% if label_class %}
<div class="aab {{ label_class }}"></div>
{% endif %}
<div class="{{ field_class }}">
{{ fields_output|safe }}
</div>
</div>

View File

@@ -0,0 +1,7 @@
{% if field.help_text %}
{% if help_text_inline %}
<span id="{{ field.auto_id }}_helptext" class="tw:text-sm tw:text-base-content/60">{{ field.help_text|safe}}</span>
{% else %}
<div {% if field.auto_id %}id="{{ field.auto_id }}_helptext" {% endif %}class="tw:text-sm tw:text-base-content/60 tw:mt-1">{{ field.help_text|safe }}</div>
{% endif %}
{% endif %}

View File

@@ -0,0 +1,13 @@
{% if help_text_inline and not error_text_inline %}
{% include 'bootstrap5/layout/help_text.html' %}
{% endif %}
{% if error_text_inline %}
{% include 'bootstrap5/layout/field_errors.html' %}
{% else %}
{% include 'bootstrap5/layout/field_errors_block.html' %}
{% endif %}
{% if not help_text_inline %}
{% include 'bootstrap5/layout/help_text.html' %}
{% endif %}

View File

@@ -0,0 +1,26 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field|is_checkbox %}
<div id="div_{{ field.auto_id }}" class="tw:form-control tw:inline-flex{% if wrapper_class %} {{ wrapper_class }}{% endif %}">
<label class="tw:label tw:cursor-pointer tw:gap-2">
{% crispy_field field 'class' 'tw:checkbox' %}
<span class="tw:label-text">{{ field.label }}</span>
</label>
</div>
{% else %}
<div id="div_{{ field.auto_id }}"{% if wrapper_class %} class="{{ wrapper_class }}"{% endif %}>
<label for="{{ field.id_for_label }}" class="tw:sr-only">
{{ field.label }}
</label>
{% if field.errors %}
{% crispy_field field 'class' 'tw:input tw:input-bordered tw:input-error' 'placeholder' field.label %}
{% else %}
{% crispy_field field 'class' 'tw:input tw:input-bordered' 'placeholder' field.label %}
{% endif %}
</div>
{% endif %}
{% endif %}

View File

@@ -0,0 +1,11 @@
<div id="{{ modal.css_id }}" class="tw:modal {{ modal.css_class }}" {{ modal.flat_attrs }}>
<div class="tw:modal-box" role="document">
<form method="dialog">
<button class="tw:btn tw:btn-sm tw:btn-circle tw:btn-ghost tw:absolute tw:right-2 tw:top-2" aria-label="Close"></button>
</form>
<h3 class="tw:font-bold tw:text-lg {{ modal.title_class }}" id="{{ modal.title_id }}-label">{{ modal.title }}</h3>
<div class="tw:py-4">
{{ fields }}
</div>
</div>
</div>

View File

@@ -0,0 +1,27 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field.label %}
<label for="{{ field.id_for_label }}" class="tw:label{% if labelclass %} {{ labelclass }}{% endif %}">
{% endif %}
{% if field|is_checkbox %}
{% crispy_field field %}
{% endif %}
{% if field.label %}
<span class="tw:label-text">{{ field.label }}</span>
{% endif %}
{% if not field|is_checkbox %}
{% crispy_field field %}
{% endif %}
{% if field.label %}
</label>
{% endif %}
{% endif %}

View File

@@ -0,0 +1,50 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="tw:mb-3{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_group_wrapper_class %} {{ form_group_wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} tw:has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}" class="tw:label{{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<span class="tw:label-text">{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}</span>
</label>
{% endif %}
<div {% if field_class %}class="{{ field_class }}"{% endif %}>
<label class="tw:input tw:input-bordered tw:flex tw:items-center tw:gap-2{% if input_size %} {{ input_size }}{% endif %}{% if field.errors %} tw:input-error{% endif %}">
{# prepend #}
{% if crispy_prepended_text %}
<span>{{ crispy_prepended_text }}</span>
{% endif %}
{# input #}
{% if field|is_select %}
{% if field.errors %}
{% crispy_field field 'class' 'tw:select tw:select-bordered tw:select-error tw:w-full' %}
{% else %}
{% crispy_field field 'class' 'tw:select tw:select-bordered tw:w-full' %}
{% endif %}
{% elif field.errors %}
{% crispy_field field 'class' 'tw:grow' %}
{% else %}
{% crispy_field field 'class' 'tw:grow' %}
{% endif %}
{# append #}
{% if crispy_appended_text %}
<span>{{ crispy_appended_text }}</span>
{% endif %}
</label>
{% if error_text_inline %}
{% include 'crispy-daisyui/layout/field_errors.html' %}
{% else %}
{% include 'crispy-daisyui/layout/field_errors_block.html' %}
{% endif %}
{% if not help_text_inline %}
{% include 'crispy-daisyui/layout/help_text.html' %}
{% endif %}
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,34 @@
{% load crispy_forms_filters %}
{% load l10n %}
<div {% if field_class %}class="{{ field_class }}"{% endif %}{% if flat_attrs %} {{ flat_attrs }}{% endif %}>
{% for group, options, index in field|optgroups %}
{% if group %}<strong class="tw:font-bold tw:mb-2 tw:block">{{ group }}</strong>{% endif %}
{% for option in options %}
<div class="tw:form-control{% if inline_class %} tw:inline-flex{% endif %}">
<label class="tw:label tw:cursor-pointer{% if inline_class %} tw:inline-flex{% endif %}">
<input type="{{option.type}}" class="{% if option.type == 'radio' %}tw:radio{% else %}tw:checkbox{% endif %}{% if field.errors %} tw:{% if option.type == 'radio' %}radio{% else %}checkbox{% endif %}-error{% endif %} tw:me-2" name="{{ field.html_name }}" value="{{ option.value|unlocalize }}" {% include "crispy-daisyui/layout/attrs.html" with widget=option %}>
<span class="tw:label-text">{{ option.label|unlocalize }}</span>
</label>
{% if field.errors and forloop.last and not inline_class and forloop.parentloop.last %}
{% include 'crispy-daisyui/layout/field_errors_block.html' %}
{% endif %}
</div>
{% endfor %}
{% endfor %}
</div>
{% if field.errors and inline_class %}
{% if field.errors.field_id %}
{# Django 5.2+ #}
<div id="{{field.errors.field_id}}_error" class="tw:text-error tw:text-sm tw:mt-1">
{% else %}
<div id="{{field.auto_id}}_error" class="tw:text-error tw:text-sm tw:mt-1">
{% endif %}
{% for error in field.errors %}
<p id="error_{{ forloop.counter }}_{{ field.auto_id }}"><strong>{{ error }}</strong></p>
{% endfor %}
</div>
{% endif %}
{% include 'crispy-daisyui/layout/help_text.html' %}

View File

@@ -0,0 +1,16 @@
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="tw:mb-3{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label %}
<fieldset class="tw:fieldset"{% if field.aria_describedby %} aria-describedby="{{ field.aria_describedby }}"{% endif %}>
<legend for="{{ field.id_for_label }}" class="tw:fieldset-legend {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</legend>
{% endif %}
{% include 'crispy-daisyui/layout/radio_checkbox_select.html' %}
{% if field.label %}</fieldset>{% endif %}
</div>
{% endif %}

View File

@@ -0,0 +1,3 @@
<div {% if div.css_id %}id="{{ div.css_id }}"{% endif %} class="tw:grid tw:grid-cols-12 tw:gap-4 {{ div.css_class|default:'' }}" {{ div.flat_attrs }}>
{{ fields|safe }}
</div>

View File

@@ -0,0 +1,19 @@
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="tw:form-control tw:mb-3{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<div class="{{ field_class }}">
{% if field.errors %}
{% crispy_field field 'class' 'tw:toggle tw:toggle-error' 'role' 'switch' %}
{% else %}
{% crispy_field field 'class' 'tw:toggle' 'role' 'switch' %}
{% endif %}
<label for="{{ field.id_for_label }}" class="tw:label{% if field.field.required %} requiredField{% endif %}">
{{ field.label }}
</label>
{% include 'crispy-daisyui/layout/help_text_and_errors.html' %}
</div>
</{% if tag %}{{ tag }}{% else %}div{% endif %}>
{% endif %}

View File

@@ -0,0 +1 @@
<input type="radio" name="{{ link.css_id }}_tabs" role="tab" class="tw:tab{% if 'active' in link.css_class %} tw:tab-active{% endif %}" aria-label="{{ link.name|capfirst }}{% if tab.errors %}!{% endif %}" {% if 'active' in link.css_class %}checked="checked"{% endif %} />

View File

@@ -0,0 +1,4 @@
<div role="tablist" class="tw:tabs tw:tabs-lifted{% if tabs.css_class %} {{ tabs.css_class }}{% endif %}"{% if tabs.css_id %} id="{{ tabs.css_id }}"{% endif %}>
{{ links|safe }}
{{ content|safe }}
</div>

View File

@@ -0,0 +1,12 @@
{% load crispy_forms_field %}
<div id="div_{{ field.auto_id }}" class="tw:mb-3{% if form_show_errors and field.errors %} tw:error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<label class="tw:label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<span class="tw:label-text">{{ field.label }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}</span>
</label>
<div class="{{ field_class }}">
{% crispy_field field 'disabled' 'disabled' %}
{% include 'crispy-daisyui/layout/help_text.html' %}
</div>
</div>

View File

@@ -0,0 +1,57 @@
{% load crispy_forms_tags %}
{% load crispy_forms_utils %}
{% load crispy_forms_field %}
{% specialspaceless %}
{% if formset_tag %}
<form {{ flat_attrs }} method="{{ form_method }}" {% if formset.is_multipart %} enctype="multipart/form-data"{% endif %}>
{% endif %}
{% if formset_method|lower == 'post' and not disable_csrf %}
{% csrf_token %}
{% endif %}
<div>
{{ formset.management_form|crispy }}
</div>
<table{% if form_id %} id="{{ form_id }}_table"{% endif%} class="tw:table tw:table-zebra tw:table-sm">
<thead>
{% if formset.readonly and not formset.queryset.exists %}
{% else %}
<tr>
{% for field in formset.forms.0 %}
{% if field.label and not field.is_hidden %}
<th for="{{ field.auto_id }}" class="{% if field.field.required %}requiredField{% endif %}">
{{ field.label }}{% if field.field.required and not field|is_checkbox %}<span class="asteriskField">*</span>{% endif %}
</th>
{% endif %}
{% endfor %}
</tr>
{% endif %}
</thead>
<tbody>
<tr class="tw:hidden empty-form">
{% for field in formset.empty_form %}
{% include 'crispy-daisyui/field.html' with tag="td" form_show_labels=False %}
{% endfor %}
</tr>
{% for form in formset %}
{% if form_show_errors and not form.is_extra %}
{% include "crispy-daisyui/errors.html" %}
{% endif %}
<tr>
{% for field in form %}
{% include 'crispy-daisyui/field.html' with tag="td" form_show_labels=False %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% include "crispy-daisyui/inputs.html" %}
{% if formset_tag %}</form>{% endif %}
{% endspecialspaceless %}

View File

@@ -0,0 +1,11 @@
{% load crispy_forms_utils %}
{% specialspaceless %}
{% if include_media %}{{ form.media }}{% endif %}
{% if form_show_errors %}
{% include "crispy-daisyui/errors.html" %}
{% endif %}
{% for field in form %}
{% include field_template %}
{% endfor %}
{% endspecialspaceless %}

View File

@@ -0,0 +1,8 @@
{% with formset.management_form as form %}
{% include 'crispy-daisyui/uni_form.html' %}
{% endwith %}
{% for form in formset %}
<div class="tw:mb-4">
{% include 'crispy-daisyui/uni_form.html' %}
</div>
{% endfor %}

View File

@@ -0,0 +1,14 @@
{% load crispy_forms_utils %}
{% specialspaceless %}
{% if form_tag %}<form {{ flat_attrs }} method="{{ form_method }}" {% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>{% endif %}
{% if form_method|lower == 'post' and not disable_csrf %}
{% csrf_token %}
{% endif %}
{% include "crispy-daisyui/display_form.html" %}
{% include "crispy-daisyui/inputs.html" %}
{% if form_tag %}</form>{% endif %}
{% endspecialspaceless %}

View File

@@ -0,0 +1,30 @@
{% load crispy_forms_tags %}
{% load crispy_forms_utils %}
{% specialspaceless %}
{% if formset_tag %}
<form {{ flat_attrs }} method="{{ form_method }}" {% if formset.is_multipart %} enctype="multipart/form-data"{% endif %}>
{% endif %}
{% if formset_method|lower == 'post' and not disable_csrf %}
{% csrf_token %}
{% endif %}
<div>
{{ formset.management_form|crispy }}
</div>
{% include "crispy-daisyui/errors_formset.html" %}
{% for form in formset %}
{% include "crispy-daisyui/display_form.html" %}
{% endfor %}
{% if inputs %}
<div class="tw:flex tw:gap-2 tw:mt-4">
{% for input in inputs %}
{% include "crispy-daisyui/layout/baseinput.html" %}
{% endfor %}
</div>
{% endif %}
{% if formset_tag %}</form>{% endif %}
{% endspecialspaceless %}

View File

@@ -1,9 +1,9 @@
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Currencies' %}<span> <div>{% translate 'Currencies' %}<span>
<a class="text-decoration-none tw:text-2xl p-1 category-action" <a class="tw:no-underline tw:text-2xl tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -14,32 +14,32 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body table-responsive"> <div class="tw:card-body tw:overflow-x-auto">
{% if currencies %} {% if currencies %}
<c-config.search></c-config.search> <c-config.search></c-config.search>
<table class="table table-hover"> <table class="tw:table tw:table-hover">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col-auto">{% translate 'Code' %}</th> <th scope="col" class="tw:w-auto">{% translate 'Code' %}</th>
<th scope="col" class="col">{% translate 'Name' %}</th> <th scope="col">{% translate 'Name' %}</th>
<th scope="col" class="col">{% translate 'Archived' %}</th> <th scope="col">{% translate 'Archived' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for currency in currencies %} {% for currency in currencies %}
<tr class="currency"> <tr class="currency">
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'currency_edit' pk=currency.id %}" hx-get="{% url 'currency_edit' pk=currency.id %}"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -52,9 +52,9 @@
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div> </div>
</td> </td>
<td class="col-auto">{{ currency.code }}</td> <td class="tw:w-auto">{{ currency.code }}</td>
<td class="col">{{ currency.name }}</td> <td>{{ currency.name }}</td>
<td class="col">{% if currency.is_archived %}<i class="fa-solid fa-solid fa-check text-success"></i>{% endif %}</td> <td>{% if currency.is_archived %}<i class="fa-solid fa-solid fa-check tw:text-success"></i>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@@ -1,13 +1,13 @@
{% load currency_display %} {% load currency_display %}
{% load i18n %} {% load i18n %}
<div class="container-fluid px-md-3 py-3 column-gap-5"> <div class="tw:container-fluid tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="d-lg-flex justify-content-between mb-3 w-100"> <div class="tw:lg:flex tw:justify-between tw:mb-3 tw:w-full">
<div class="tw:text-3xl fw-bold font-monospace d-flex align-items-center"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:flex tw:items-center">
{{ strategy.name }} {{ strategy.name }}
</div> </div>
<div class="tw:text-sm text-lg-end mt-2 mt-lg-0"> <div class="tw:text-sm tw:lg:text-right tw:mt-2 tw:lg:mt-0">
<div class="mb-2"> <div class="tw:mb-2">
<span class="badge rounded-pill text-bg-secondary">{{ strategy.payment_currency.name }}</span> x <span class="badge rounded-pill text-bg-secondary">{{ strategy.target_currency.name }}</span> <span class="tw:badge tw:badge-secondary tw:rounded-full">{{ strategy.payment_currency.name }}</span> x <span class="tw:badge tw:badge-secondary tw:rounded-full">{{ strategy.target_currency.name }}</span>
</div> </div>
<div> <div>
{% if strategy.current_price %} {% if strategy.current_price %}
@@ -25,13 +25,13 @@
</div> </div>
</div> </div>
<div class="row gy-3 gx-3"> <div class="tw:grid tw:lg:grid-cols-2 tw:gap-3">
<div class="col-xl-6 col"> <div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body"> <div class="tw:card-body">
{% spaceless %} {% spaceless %}
<div class="card-title tw:text-xl">{% trans "Entries" %}<span> <div class="tw:card-title tw:text-xl">{% trans "Entries" %}<span>
<a class="text-decoration-none p-1 category-action" <a class="tw:no-underline tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -44,8 +44,8 @@
{% endspaceless %} {% endspaceless %}
{% if entries %} {% if entries %}
<div class="table-responsive"> <div class="tw:overflow-x-auto">
<table class="table table-hover text-nowrap"> <table class="tw:table tw:table-hover tw:whitespace-nowrap">
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
@@ -59,9 +59,9 @@
<tbody> <tbody>
{% for entry in entries %} {% for entry in entries %}
<tr> <tr>
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
@@ -69,7 +69,7 @@
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-swap="innerHTML"> hx-swap="innerHTML">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -107,11 +107,11 @@
</td> </td>
<td> <td>
{% if entry.profit_loss_percentage > 0 %} {% if entry.profit_loss_percentage > 0 %}
<span class="badge text-bg-success"><i <span class="tw:badge tw: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 tw:me-2"></i>{{ entry.profit_loss_percentage|floatformat:"2g" }}%</span>
{% elif entry.profit_loss_percentage < 0 %} {% elif entry.profit_loss_percentage < 0 %}
<span class="badge text-bg-danger"><i <span class="tw:badge tw: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 tw:me-2"></i>{{ entry.profit_loss_percentage|floatformat:"2g" }}%</span>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
@@ -127,13 +127,13 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-xl-6 col"> <div>
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 gy-3 gx-3"> <div class="tw:grid tw:grid-cols-1 tw:md:grid-cols-2 tw:xl:grid-cols-3 tw:gap-3">
<div class="col"> <div>
<div class="card h-100"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:h-full">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Total Invested" %}</h5> <h5 class="tw:card-title">{% trans "Total Invested" %}</h5>
<div class="card-text"> <div class="tw:text-base-content">
<c-amount.display <c-amount.display
:amount="strategy.total_invested" :amount="strategy.total_invested"
:prefix="strategy.payment_currency.prefix" :prefix="strategy.payment_currency.prefix"
@@ -143,11 +143,11 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col"> <div>
<div class="card h-100"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:h-full">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Total Received" %}</h5> <h5 class="tw:card-title">{% trans "Total Received" %}</h5>
<div class="card-text"> <div class="tw:text-base-content">
<c-amount.display <c-amount.display
:amount="strategy.total_received" :amount="strategy.total_received"
:prefix="strategy.target_currency.prefix" :prefix="strategy.target_currency.prefix"
@@ -157,11 +157,11 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col"> <div>
<div class="card h-100"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:h-full">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Current Total Value" %}</h5> <h5 class="tw:card-title">{% trans "Current Total Value" %}</h5>
<div class="card-text"> <div class="tw:text-base-content">
<c-amount.display <c-amount.display
:amount="strategy.current_total_value" :amount="strategy.current_total_value"
:prefix="strategy.payment_currency.prefix" :prefix="strategy.payment_currency.prefix"
@@ -171,11 +171,11 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col"> <div>
<div class="card h-100"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:h-full">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Average Entry Price" %}</h5> <h5 class="tw:card-title">{% trans "Average Entry Price" %}</h5>
<div class="card-text"> <div class="tw:text-base-content">
<c-amount.display <c-amount.display
:amount="strategy.average_entry_price" :amount="strategy.average_entry_price"
:prefix="strategy.payment_currency.prefix" :prefix="strategy.payment_currency.prefix"
@@ -185,12 +185,12 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col"> <div>
<div class="card h-100"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:h-full">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Total P/L" %}</h5> <h5 class="tw:card-title">{% trans "Total P/L" %}</h5>
<div <div
class="card-text {% if strategy.total_profit_loss >= 0 %}tw:text-green-400{% else %}tw:text-red-400{% endif %}"> class="tw:text-base-content {% if strategy.total_profit_loss >= 0 %}tw:text-green-400{% else %}tw:text-red-400{% endif %}">
<c-amount.display <c-amount.display
:amount="strategy.total_profit_loss" :amount="strategy.total_profit_loss"
:prefix="strategy.payment_currency.prefix" :prefix="strategy.payment_currency.prefix"
@@ -201,20 +201,20 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col"> <div>
<div class="card h-100"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:h-full">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Total % P/L" %}</h5> <h5 class="tw:card-title">{% trans "Total % P/L" %}</h5>
<div <div
class="card-text {% if strategy.total_profit_loss >= 0 %}tw:text-green-400{% else %}tw:text-red-400{% endif %}"> class="tw:text-base-content {% if strategy.total_profit_loss >= 0 %}tw:text-green-400{% else %}tw:text-red-400{% endif %}">
{{ strategy.total_profit_loss_percentage|floatformat:2 }}% {{ strategy.total_profit_loss_percentage|floatformat:2 }}%
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row mt-4"> <div class="tw:grid tw:mt-4">
<div class="col-12" <div class="tw:col-span-12"
_="on htmx:afterSettle from #strategy-details _="on htmx:afterSettle from #strategy-details
set perfomancectx to #performanceChart.getContext('2d') set perfomancectx to #performanceChart.getContext('2d')
js(perfomancectx) js(perfomancectx)
@@ -283,16 +283,16 @@
}) })
end end
"> ">
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Performance Over Time" %}</h5> <h5 class="tw:card-title">{% trans "Performance Over Time" %}</h5>
<canvas id="performanceChart"></canvas> <canvas id="performanceChart"></canvas>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row mt-4"> <div class="tw:grid tw:mt-4">
<div class="col-12" <div class="tw:col-span-12"
_="on htmx:afterSettle from #strategy-details _="on htmx:afterSettle from #strategy-details
set pricectx to #priceChart.getContext('2d') set pricectx to #priceChart.getContext('2d')
set priceData to {{ price_comparison_data|safe }} set priceData to {{ price_comparison_data|safe }}
@@ -387,16 +387,16 @@
}) })
end end
"> ">
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Entry Price vs Current Price" %}</h5> <h5 class="tw:card-title">{% trans "Entry Price vs Current Price" %}</h5>
<canvas id="priceChart"></canvas> <canvas id="priceChart"></canvas>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row mt-4"> <div class="tw:grid tw:mt-4">
<div class="col-12" <div class="tw:col-span-12"
_="on htmx:afterSettle from #strategy-details _="on htmx:afterSettle from #strategy-details
set frequencyctx to #frequencyChart.getContext('2d') set frequencyctx to #frequencyChart.getContext('2d')
js(frequencyctx) js(frequencyctx)
@@ -450,10 +450,10 @@
}) })
end end
"> ">
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{% trans "Investment Frequency" %}</h5> <h5 class="tw:card-title">{% trans "Investment Frequency" %}</h5>
<p class="card-text tw:text-gray-400"> <p class="tw:text-base-content/60">
{% trans "The straighter the blue line, the more consistent your DCA strategy is." %} {% trans "The straighter the blue line, the more consistent your DCA strategy is." %}
</p> </p>
<canvas id="frequencyChart"></canvas> <canvas id="frequencyChart"></canvas>

View File

@@ -1,9 +1,9 @@
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Dollar Cost Average Strategies' %}<span> <div>{% translate 'Dollar Cost Average Strategies' %}<span>
<a class="text-decoration-none tw:text-2xl p-1 category-action" <a class="tw:no-underline tw:text-2xl tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -14,23 +14,23 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4 gy-3 gx-3"> <div class="tw:grid tw:grid-cols-1 tw:md:grid-cols-2 tw:lg:grid-cols-3 tw:xl:grid-cols-4 tw:gap-3">
{% for strategy in strategies %} {% for strategy in strategies %}
<div class="col"> <div>
<div class="card h-100"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:h-full tw:flex tw:flex-col">
<div class="card-header"> <div class="tw:card-header tw:bg-base-200 tw:p-4">
<span class="badge rounded-pill text-bg-secondary">{{ strategy.payment_currency.name }}</span> x <span <span class="tw:badge tw:badge-secondary tw:rounded-full">{{ strategy.payment_currency.name }}</span> x <span
class="badge rounded-pill text-bg-secondary">{{ strategy.target_currency.name }}</span> class="tw:badge tw:badge-secondary tw:rounded-full">{{ strategy.target_currency.name }}</span>
</div> </div>
<a href="{% url 'dca_strategy_detail_index' strategy_id=strategy.id %}" hx-boost="true" <a href="{% url 'dca_strategy_detail_index' strategy_id=strategy.id %}" hx-boost="true"
class="text-decoration-none card-body"> class="tw:no-underline tw:card-body tw:flex-1">
<div class=""> <div class="">
<div class="card-title tw:text-xl">{{ strategy.name }}</div> <div class="tw:card-title tw:text-xl">{{ strategy.name }}</div>
<div class="card-text tw:text-gray-400">{{ strategy.notes }}</div> <div class="tw:text-base-content/60">{{ strategy.notes }}</div>
</div> </div>
</a> </a>
<div class="card-footer text-end"> <div class="tw:card-footer tw:bg-base-200 tw:p-4 tw:text-right">
<a class="text-decoration-none tw:text-gray-400 p-1" <a class="tw:no-underline tw:text-base-content/60 tw:p-1"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
@@ -38,7 +38,7 @@
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i> <i class="fa-solid fa-pencil fa-fw"></i>
</a> </a>
<a class="text-danger text-decoration-none p-1" <a class="tw:text-error tw:no-underline tw:p-1"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -52,7 +52,7 @@
<i class="fa-solid fa-trash fa-fw"></i> <i class="fa-solid fa-trash fa-fw"></i>
</a> </a>
{% if not strategy.owner %} {% if not strategy.owner %}
<a class="text-primary text-decoration-none p-1" <a class="tw:text-primary tw:no-underline tw:p-1"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}" data-bs-title="{% translate "Take ownership" %}"
@@ -60,7 +60,7 @@
<i class="fa-solid fa-crown fa-fw"></i></a> <i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %} {% endif %}
{% if user == strategy.owner %} {% if user == strategy.owner %}
<a class="text-primary text-decoration-none p-1" <a class="tw:text-primary tw:no-underline tw:p-1"
role="button" role="button"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"

View File

@@ -1,9 +1,9 @@
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Entities' %}<span> <div>{% translate 'Entities' %}<span>
<a class="text-decoration-none tw:text-2xl p-1 category-action" <a class="tw:no-underline tw:text-2xl tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -14,18 +14,14 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-header"> <div class="tw:card-header tw:bg-base-200 tw:p-4">
<ul class="nav nav-pills card-header-pills" id="myTab" role="tablist"> <div role="tablist" class="tw:tabs tw:tabs-lifted">
<li class="nav-item" role="presentation"> <button class="tw:tab tw:tab-active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'entities_table_active' %}" hx-trigger="load, click" hx-target="#entities-table">{% translate 'Active' %}</button>
<button class="nav-link active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'entities_table_active' %}" hx-trigger="load, click" hx-target="#entities-table">{% translate 'Active' %}</button> <button class="tw:tab" hx-get="{% url 'entities_table_archived' %}" hx-target="#entities-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Archived' %}</button>
</li> </div>
<li class="nav-item" role="presentation">
<button class="nav-link" hx-get="{% url 'entities_table_archived' %}" hx-target="#entities-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Archived' %}</button>
</li>
</ul>
</div> </div>
<div class="card-body"> <div class="tw:card-body">
<div id="entities-table"></div> <div id="entities-table"></div>
</div> </div>
</div> </div>

View File

@@ -7,21 +7,21 @@
hx-swap="outerHTML"> hx-swap="outerHTML">
{% endif %} {% endif %}
{% if entities %} {% if entities %}
<div class="table-responsive"> <div class="tw:overflow-x-auto">
<c-config.search></c-config.search> <c-config.search></c-config.search>
<table class="table table-hover"> <table class="tw:table tw:table-hover">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th> <th scope="col">{% translate 'Name' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for entity in entities %} {% for entity in entities %}
<tr class="entity"> <tr class="entity">
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
hx-swap="innerHTML" hx-swap="innerHTML"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
@@ -29,7 +29,7 @@
hx-get="{% url 'entity_edit' entity_id=entity.id %}" hx-get="{% url 'entity_edit' entity_id=entity.id %}"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
hx-swap="innerHTML" hx-swap="innerHTML"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
@@ -42,7 +42,7 @@
data-confirm-text="{% translate "Yes, delete it!" %}" data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not entity.owner %} {% if not entity.owner %}
<a class="btn btn-secondary btn-sm text-warning" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-warning"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}" data-bs-title="{% translate "Take ownership" %}"
@@ -50,7 +50,7 @@
<i class="fa-solid fa-crown fa-fw"></i></a> <i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %} {% endif %}
{% if user == entity.owner %} {% if user == entity.owner %}
<a class="btn btn-secondary btn-sm text-primary" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-primary"
role="button" role="button"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-swap="innerHTML" hx-swap="innerHTML"
@@ -61,7 +61,7 @@
{% endif %} {% endif %}
</div> </div>
</td> </td>
<td class="col">{{ entity.name }}</td> <td>{{ entity.name }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@@ -1,10 +1,10 @@
{% load currency_display %} {% load currency_display %}
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Exchange Rates' %}<span> <div>{% translate 'Exchange Rates' %}<span>
<a class="text-decoration-none tw:text-2xl p-1 category-action" <a class="tw:no-underline tw:text-2xl tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -15,28 +15,24 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-header"> <div class="tw:card-header tw:bg-base-200 tw:p-4">
<ul class="nav nav-pills card-header-pills" id="myTab" role="tablist"> <div role="tablist" class="tw:tabs tw:tabs-lifted">
<li class="nav-item" role="presentation"> <button class="tw:tab tw:tab-active" hx-indicator="#exchange-rates-table" data-bs-toggle="tab" type="button"
<button class="nav-link active" hx-indicator="#exchange-rates-table" data-bs-toggle="tab" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="true"
role="tab" aria-controls="home-tab-pane" aria-selected="true" hx-get="{% url 'exchange_rates_list_pair' %}" hx-trigger="load, click"
hx-get="{% url 'exchange_rates_list_pair' %}" hx-trigger="load, click" hx-target="#exchange-rates-table" aria-controls="#exchange-rates-table">{% translate 'All' %}</button>
hx-target="#exchange-rates-table" aria-controls="#exchange-rates-table">{% translate 'All' %}</button>
</li>
{% for pair in pairings %} {% for pair in pairings %}
<li class="nav-item" role="presentation"> <button class="tw:tab" hx-indicator="#exchange-rates-table"
<button class="nav-link" hx-indicator="#exchange-rates-table" hx-get="{% url 'exchange_rates_list_pair' %}"
hx-get="{% url 'exchange_rates_list_pair' %}" hx-vals='{"from": "{{ pair.1 }}", "to": "{{ pair.2 }}"}'
hx-vals='{"from": "{{ pair.1 }}", "to": "{{ pair.2 }}"}' hx-target="#exchange-rates-table" data-bs-toggle="tab" type="button" role="tab"
hx-target="#exchange-rates-table" data-bs-toggle="tab" type="button" role="tab" aria-controls="#exchange-rates-table" aria-selected="false">{{ pair.0 }}</button>
aria-controls="#exchange-rates-table" aria-selected="false">{{ pair.0 }}</button>
</li>
{% endfor %} {% endfor %}
</ul> </div>
</div> </div>
<div class="card"> <div class="tw:card">
<div id="exchange-rates-table" class="show-loading"></div> <div id="exchange-rates-table" class="show-loading"></div>
</div> </div>

View File

@@ -1,23 +1,23 @@
{% load currency_display %} {% load currency_display %}
{% load i18n %} {% load i18n %}
<div class="card-body show-loading" hx-get="{% url 'exchange_rates_list_pair' %}" hx-trigger="updated from:window" hx-swap="outerHTML" hx-vals='{"page": "{{ page_obj.number }}", "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'> <div class="tw:card-body show-loading" hx-get="{% url 'exchange_rates_list_pair' %}" hx-trigger="updated from:window" hx-swap="outerHTML" hx-vals='{"page": "{{ page_obj.number }}", "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'>
{% if page_obj %} {% if page_obj %}
<div class="table-responsive"> <div class="tw:overflow-x-auto">
<table class="table table-hover text-nowrap"> <table class="tw:table tw:table-hover tw:whitespace-nowrap">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col">{% translate 'Date' %}</th> <th scope="col">{% translate 'Date' %}</th>
<th scope="col" class="col">{% translate 'Pairing' %}</th> <th scope="col">{% translate 'Pairing' %}</th>
<th scope="col" class="col">{% translate 'Rate' %}</th> <th scope="col">{% translate 'Rate' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for exchange_rate in page_obj %} {% for exchange_rate in page_obj %}
<tr class="exchange-rate"> <tr class="exchange-rate">
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
@@ -25,7 +25,7 @@
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-swap="innerHTML"> hx-swap="innerHTML">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -39,9 +39,9 @@
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div> </div>
</td> </td>
<td class="col-3">{{ exchange_rate.date|date:"SHORT_DATETIME_FORMAT" }}</td> <td class="tw:w-1/4">{{ exchange_rate.date|date:"SHORT_DATETIME_FORMAT" }}</td>
<td class="col-3"><span class="badge rounded-pill text-bg-secondary">{{ exchange_rate.from_currency.name }}</span> x <span class="badge rounded-pill text-bg-secondary">{{ exchange_rate.to_currency.name }}</span></td> <td class="tw:w-1/4"><span class="tw:badge tw:badge-secondary tw:rounded-full">{{ exchange_rate.from_currency.name }}</span> x <span class="tw:badge tw:badge-secondary tw:rounded-full">{{ exchange_rate.to_currency.name }}</span></td>
<td class="col-3">1 {{ exchange_rate.from_currency.name }} ≅ {% currency_display amount=exchange_rate.rate prefix=exchange_rate.to_currency.prefix suffix=exchange_rate.to_currency.suffix decimal_places=exchange_rate.to_currency.decimal_places%}</td> <td class="tw:w-1/4">1 {{ exchange_rate.from_currency.name }} ≅ {% currency_display amount=exchange_rate.rate prefix=exchange_rate.to_currency.prefix suffix=exchange_rate.to_currency.suffix decimal_places=exchange_rate.to_currency.decimal_places%}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@@ -52,13 +52,12 @@
{% endif %} {% endif %}
{% if page_obj.has_other_pages %} {% if page_obj.has_other_pages %}
<div class="mt-auto"> <div class="tw:mt-auto">
<input value="{{ page_obj.number }}" name="page" type="hidden" id="page"> <input value="{{ page_obj.number }}" name="page" type="hidden" id="page">
<nav aria-label="{% translate 'Page navigation' %}"> <nav aria-label="{% translate 'Page navigation' %}">
<ul class="pagination justify-content-center mt-5"> <div class="tw:join tw:flex tw:justify-center tw:mt-5">
<li class="page-item"> <button class="tw:join-item tw:btn tw:btn-sm {% if not page_obj.has_previous %}tw:btn-disabled{% endif %}"
<a class="page-link tw:cursor-pointer {% if not page_obj.has_previous %}disabled{% endif %}"
hx-get="{% if page_obj.has_previous %}{% url 'exchange_rates_list_pair' %}{% endif %}" hx-get="{% if page_obj.has_previous %}{% url 'exchange_rates_list_pair' %}{% endif %}"
hx-vals='{"page": 1, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}' hx-vals='{"page": 1, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'
hx-include="#filter, #order" hx-include="#filter, #order"
@@ -66,8 +65,7 @@
aria-label="Primeira página" aria-label="Primeira página"
hx-swap="show:top"> hx-swap="show:top">
<span aria-hidden="true">&laquo;</span> <span aria-hidden="true">&laquo;</span>
</a> </button>
</li>
{% for page_number in page_obj.paginator.page_range %} {% for page_number in page_obj.paginator.page_range %}
{% comment %} {% comment %}
This conditional allows us to display up to 3 pages before and after the current page This conditional allows us to display up to 3 pages before and after the current page
@@ -78,44 +76,35 @@
{% endcomment %} {% endcomment %}
{% if page_number <= page_obj.number|add:3 and page_number >= page_obj.number|add:-3 %} {% if page_number <= page_obj.number|add:3 and page_number >= page_obj.number|add:-3 %}
{% if page_obj.number == page_number %} {% if page_obj.number == page_number %}
<li class="page-item active"> <button class="tw:join-item tw:btn tw:btn-sm tw:btn-active">
<a class="page-link tw:cursor-pointer"> {{ page_number }}
{{ page_number }} </button>
</a>
</li>
{% else %} {% else %}
<li class="page-item"> <button class="tw:join-item tw:btn tw:btn-sm"
<a class="page-link tw:cursor-pointer"
hx-get="{% url 'exchange_rates_list_pair' %}" hx-get="{% url 'exchange_rates_list_pair' %}"
hx-vals='{"page": {{ page_number }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}' hx-vals='{"page": {{ page_number }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'
hx-target="#exchange-rates-table" hx-target="#exchange-rates-table"
hx-swap="show:top"> hx-swap="show:top">
{{ page_number }} {{ page_number }}
</a> </button>
</li>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if page_obj.number|add:3 < page_obj.paginator.num_pages %} {% if page_obj.number|add:3 < page_obj.paginator.num_pages %}
<li class="page-item"> <button class="tw:join-item tw:btn tw:btn-sm tw:btn-disabled"
<a class="page-link disabled"
aria-label="..."> aria-label="...">
<span aria-hidden="true">...</span> <span aria-hidden="true">...</span>
</a> </button>
</li> <button class="tw:join-item tw:btn tw:btn-sm"
<li class="page-item">
<a class="page-link tw:cursor-pointer"
hx-get="{% url 'exchange_rates_list_pair' %}" hx-target="#exchange-rates-table" hx-get="{% url 'exchange_rates_list_pair' %}" hx-target="#exchange-rates-table"
hx-vals='{"page": {{ page_obj.paginator.num_pages }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}' hx-vals='{"page": {{ page_obj.paginator.num_pages }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'
hx-include="#filter, #order" hx-include="#filter, #order"
hx-swap="show:top" hx-swap="show:top"
aria-label="Última página"> aria-label="Última página">
<span aria-hidden="true">{{ page_obj.paginator.num_pages }}</span> <span aria-hidden="true">{{ page_obj.paginator.num_pages }}</span>
</a> </button>
</li>
{% endif %} {% endif %}
<li class="page-item"> <button class="tw:join-item tw:btn tw:btn-sm {% if not page_obj.has_next %}tw:btn-disabled{% endif %}"
<a class="page-link {% if not page_obj.has_next %}disabled{% endif %} tw:cursor-pointer"
hx-get="{% if page_obj.has_next %}{% url 'exchange_rates_list_pair' %}{% endif %}" hx-get="{% if page_obj.has_next %}{% url 'exchange_rates_list_pair' %}{% endif %}"
hx-vals='{"page": {{ page_obj.paginator.num_pages }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}' hx-vals='{"page": {{ page_obj.paginator.num_pages }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'
hx-include="#filter, #order" hx-include="#filter, #order"
@@ -123,9 +112,8 @@
hx-target="#exchange-rates-table" hx-target="#exchange-rates-table"
aria-label="Next"> aria-label="Next">
<span aria-hidden="true">&raquo;</span> <span aria-hidden="true">&raquo;</span>
</a> </button>
</li> </div>
</ul>
</nav> </nav>
</div> </div>
{% endif %} {% endif %}

View File

@@ -1,10 +1,10 @@
{% load currency_display %} {% load currency_display %}
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Automatic Exchange Rates' %}<span> <div>{% translate 'Automatic Exchange Rates' %}<span>
<a class="text-decoration-none tw:text-2xl p-1 category-action" <a class="tw:no-underline tw:text-2xl tw:p-1 category-action"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}" data-bs-title="{% translate "Add" %}"
@@ -15,39 +15,39 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-header text-body-secondary"> <div class="tw:card-header tw:bg-base-200 tw:p-4 tw:text-base-content/70">
<button type="button" hx-get="{% url 'automatic_exchange_rate_force_fetch' %}" <button type="button" hx-get="{% url 'automatic_exchange_rate_force_fetch' %}"
class="btn btn-outline-primary btn-sm">{% trans 'Fetch all' %}</button> class="tw:btn tw:btn-outline tw:btn-primary tw:btn-sm">{% trans 'Fetch all' %}</button>
</div> </div>
<div class="card-body"> <div class="tw:card-body">
{% if services %} {% if services %}
<c-config.search></c-config.search> <c-config.search></c-config.search>
<div class="table-responsive"> <div class="tw:overflow-x-auto">
<table class="table table-hover"> <table class="tw:table tw:table-hover">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col-auto">{% translate 'Name' %}</th> <th scope="col" class="tw:w-auto">{% translate 'Name' %}</th>
<th scope="col" class="col">{% translate 'Service' %}</th> <th scope="col">{% translate 'Service' %}</th>
<th scope="col" class="col">{% translate 'Targeting' %}</th> <th scope="col">{% translate 'Targeting' %}</th>
<th scope="col" class="col">{% translate 'Last fetch' %}</th> <th scope="col">{% translate 'Last fetch' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for service in services %} {% for service in services %}
<tr class="services"> <tr class="services">
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'automatic_exchange_rate_edit' pk=service.id %}" hx-get="{% url 'automatic_exchange_rate_edit' pk=service.id %}"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -60,12 +60,12 @@
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div> </div>
</td> </td>
<td class="col-auto">{% if service.is_active %}<i class="fa-solid fa-circle text-success"></i>{% else %} <td class="tw:w-auto">{% if service.is_active %}<i class="fa-solid fa-circle tw:text-success"></i>{% else %}
<i class="fa-solid fa-circle text-danger"></i>{% endif %}</td> <i class="fa-solid fa-circle tw:text-error"></i>{% endif %}</td>
<td class="col-auto">{{ service.name }}</td> <td class="tw:w-auto">{{ service.name }}</td>
<td class="col">{{ service.get_service_type_display }}</td> <td>{{ service.get_service_type_display }}</td>
<td class="col">{{ service.target_currencies.count }} {% trans 'currencies' %}, {{ service.target_accounts.count }} {% trans 'accounts' %}</td> <td>{{ service.target_currencies.count }} {% trans 'currencies' %}, {{ service.target_accounts.count }} {% trans 'accounts' %}</td>
<td class="col">{{ service.last_fetch|date:"SHORT_DATETIME_FORMAT" }}</td> <td>{{ service.last_fetch|date:"SHORT_DATETIME_FORMAT" }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@@ -1,23 +1,23 @@
{% load currency_display %} {% load currency_display %}
{% load i18n %} {% load i18n %}
<div class="card-body show-loading" hx-get="{% url 'exchange_rates_list_pair' %}" hx-trigger="updated from:window" hx-swap="outerHTML" hx-vals='{"page": "{{ page_obj.number }}", "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'> <div class="tw:card-body show-loading" hx-get="{% url 'exchange_rates_list_pair' %}" hx-trigger="updated from:window" hx-swap="outerHTML" hx-vals='{"page": "{{ page_obj.number }}", "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'>
{% if page_obj %} {% if page_obj %}
<div class="table-responsive"> <div class="tw:overflow-x-auto">
<table class="table table-hover text-nowrap"> <table class="tw:table tw:table-hover tw:whitespace-nowrap">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col">{% translate 'Date' %}</th> <th scope="col">{% translate 'Date' %}</th>
<th scope="col" class="col">{% translate 'Pairing' %}</th> <th scope="col">{% translate 'Pairing' %}</th>
<th scope="col" class="col">{% translate 'Rate' %}</th> <th scope="col">{% translate 'Rate' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for exchange_rate in page_obj %} {% for exchange_rate in page_obj %}
<tr class="exchange-rate"> <tr class="exchange-rate">
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
@@ -25,7 +25,7 @@
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
hx-swap="innerHTML"> hx-swap="innerHTML">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -39,9 +39,9 @@
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div> </div>
</td> </td>
<td class="col-3">{{ exchange_rate.date|date:"SHORT_DATETIME_FORMAT" }}</td> <td class="tw:w-1/4">{{ exchange_rate.date|date:"SHORT_DATETIME_FORMAT" }}</td>
<td class="col-3"><span class="badge rounded-pill text-bg-secondary">{{ exchange_rate.from_currency.name }}</span> x <span class="badge rounded-pill text-bg-secondary">{{ exchange_rate.to_currency.name }}</span></td> <td class="tw:w-1/4"><span class="tw:badge tw:badge-secondary tw:rounded-full">{{ exchange_rate.from_currency.name }}</span> x <span class="tw:badge tw:badge-secondary tw:rounded-full">{{ exchange_rate.to_currency.name }}</span></td>
<td class="col-3">1 {{ exchange_rate.from_currency.name }} ≅ {% currency_display amount=exchange_rate.rate prefix=exchange_rate.to_currency.prefix suffix=exchange_rate.to_currency.suffix decimal_places=exchange_rate.to_currency.decimal_places%}</td> <td class="tw:w-1/4">1 {{ exchange_rate.from_currency.name }} ≅ {% currency_display amount=exchange_rate.rate prefix=exchange_rate.to_currency.prefix suffix=exchange_rate.to_currency.suffix decimal_places=exchange_rate.to_currency.decimal_places%}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@@ -52,13 +52,12 @@
{% endif %} {% endif %}
{% if page_obj.has_other_pages %} {% if page_obj.has_other_pages %}
<div class="mt-auto"> <div class="tw:mt-auto">
<input value="{{ page_obj.number }}" name="page" type="hidden" id="page"> <input value="{{ page_obj.number }}" name="page" type="hidden" id="page">
<nav aria-label="{% translate 'Page navigation' %}"> <nav aria-label="{% translate 'Page navigation' %}">
<ul class="pagination justify-content-center mt-5"> <div class="tw:join tw:flex tw:justify-center tw:mt-5">
<li class="page-item"> <button class="tw:join-item tw:btn tw:btn-sm tw:cursor-pointer {% if not page_obj.has_previous %}tw:btn-disabled{% endif %}"
<a class="page-link tw:cursor-pointer {% if not page_obj.has_previous %}disabled{% endif %}"
hx-get="{% if page_obj.has_previous %}{% url 'exchange_rates_list_pair' %}{% endif %}" hx-get="{% if page_obj.has_previous %}{% url 'exchange_rates_list_pair' %}{% endif %}"
hx-vals='{"page": 1, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}' hx-vals='{"page": 1, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'
hx-include="#filter, #order" hx-include="#filter, #order"
@@ -66,8 +65,7 @@
aria-label="Primeira página" aria-label="Primeira página"
hx-swap="show:top"> hx-swap="show:top">
<span aria-hidden="true">&laquo;</span> <span aria-hidden="true">&laquo;</span>
</a> </button>
</li>
{% for page_number in page_obj.paginator.page_range %} {% for page_number in page_obj.paginator.page_range %}
{% comment %} {% comment %}
This conditional allows us to display up to 3 pages before and after the current page This conditional allows us to display up to 3 pages before and after the current page
@@ -78,44 +76,35 @@
{% endcomment %} {% endcomment %}
{% if page_number <= page_obj.number|add:3 and page_number >= page_obj.number|add:-3 %} {% if page_number <= page_obj.number|add:3 and page_number >= page_obj.number|add:-3 %}
{% if page_obj.number == page_number %} {% if page_obj.number == page_number %}
<li class="page-item active"> <button class="tw:join-item tw:btn tw:btn-sm tw:btn-active tw:cursor-pointer">
<a class="page-link tw:cursor-pointer">
{{ page_number }} {{ page_number }}
</a> </button>
</li>
{% else %} {% else %}
<li class="page-item"> <button class="tw:join-item tw:btn tw:btn-sm tw:cursor-pointer"
<a class="page-link tw:cursor-pointer"
hx-get="{% url 'exchange_rates_list_pair' %}" hx-get="{% url 'exchange_rates_list_pair' %}"
hx-vals='{"page": {{ page_number }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}' hx-vals='{"page": {{ page_number }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'
hx-target="#exchange-rates-table" hx-target="#exchange-rates-table"
hx-swap="show:top"> hx-swap="show:top">
{{ page_number }} {{ page_number }}
</a> </button>
</li>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if page_obj.number|add:3 < page_obj.paginator.num_pages %} {% if page_obj.number|add:3 < page_obj.paginator.num_pages %}
<li class="page-item"> <button class="tw:join-item tw:btn tw:btn-sm tw:btn-disabled"
<a class="page-link disabled"
aria-label="..."> aria-label="...">
<span aria-hidden="true">...</span> <span aria-hidden="true">...</span>
</a> </button>
</li> <button class="tw:join-item tw:btn tw:btn-sm tw:cursor-pointer"
<li class="page-item">
<a class="page-link tw:cursor-pointer"
hx-get="{% url 'exchange_rates_list_pair' %}" hx-target="#exchange-rates-table" hx-get="{% url 'exchange_rates_list_pair' %}" hx-target="#exchange-rates-table"
hx-vals='{"page": {{ page_obj.paginator.num_pages }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}' hx-vals='{"page": {{ page_obj.paginator.num_pages }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'
hx-include="#filter, #order" hx-include="#filter, #order"
hx-swap="show:top" hx-swap="show:top"
aria-label="Última página"> aria-label="Última página">
<span aria-hidden="true">{{ page_obj.paginator.num_pages }}</span> <span aria-hidden="true">{{ page_obj.paginator.num_pages }}</span>
</a> </button>
</li>
{% endif %} {% endif %}
<li class="page-item"> <button class="tw:join-item tw:btn tw:btn-sm {% if not page_obj.has_next %}tw:btn-disabled{% endif %} tw:cursor-pointer"
<a class="page-link {% if not page_obj.has_next %}disabled{% endif %} tw:cursor-pointer"
hx-get="{% if page_obj.has_next %}{% url 'exchange_rates_list_pair' %}{% endif %}" hx-get="{% if page_obj.has_next %}{% url 'exchange_rates_list_pair' %}{% endif %}"
hx-vals='{"page": {{ page_obj.paginator.num_pages }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}' hx-vals='{"page": {{ page_obj.paginator.num_pages }}, "from": "{{ from_currency|default_if_none:"" }}", "to": "{{ to_currency|default_if_none:"" }}"}'
hx-include="#filter, #order" hx-include="#filter, #order"
@@ -123,9 +112,8 @@
hx-target="#exchange-rates-table" hx-target="#exchange-rates-table"
aria-label="Next"> aria-label="Next">
<span aria-hidden="true">&raquo;</span> <span aria-hidden="true">&raquo;</span>
</a> </button>
</li> </div>
</ul>
</nav> </nav>
</div> </div>
{% endif %} {% endif %}

View File

@@ -5,8 +5,8 @@
{% block title %}{% translate 'Export' %}{% endblock %} {% block title %}{% translate 'Export' %}{% endblock %}
{% block body %} {% block body %}
<div class="container p-3"> <div class="tw:container tw:p-3">
<form hx-post="{% url 'export_form' %}" hx-ext="htmx-download" hx-swap="none" id="export-form" class="show-loading px-1" target="_blank"> <form hx-post="{% url 'export_form' %}" hx-ext="htmx-download" hx-swap="none" id="export-form" class="show-loading tw:px-1" target="_blank">
{% crispy form %} {% crispy form %}
</form> </form>
</div> </div>

View File

@@ -5,12 +5,12 @@
{% block title %}{% translate 'Restore' %}{% endblock %} {% block title %}{% translate 'Restore' %}{% endblock %}
{% block body %} {% block body %}
<div class="container p-3"> <div class="tw:container tw:p-3">
<form hx-post="{% url 'restore_form' %}" <form hx-post="{% url 'restore_form' %}"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
id="restore-form" id="restore-form"
enctype="multipart/form-data" enctype="multipart/form-data"
class="show-loading px-1"> class="show-loading tw:px-1">
{% crispy form %} {% crispy form %}
</form> </form>
</div> </div>

View File

@@ -1,8 +1,7 @@
{% load i18n %} {% load i18n %}
{% load webpack_loader %} <div class="offcanvas-header tw:flex tw:justify-between tw:items-center">
<div class="offcanvas-header"> <h5 class="offcanvas-title tw:font-medium tw:text-xl">{% block title %}{% endblock %}</h5>
<h5 class="offcanvas-title">{% block title %}{% endblock %}</h5> <button type="button" class="tw:btn tw:btn-ghost tw:btn-sm tw:btn-circle" aria-label="{% trans 'Close' %}" data-bs-dismiss="offcanvas"><i class="fa-solid fa-xmark"></i></button>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label={% translate 'Close' %}></button>
</div> </div>
<div id="generic-offcanvas-body" class="offcanvas-body" <div id="generic-offcanvas-body" class="offcanvas-body"
_="install init_tom_select _="install init_tom_select

View File

@@ -1,22 +1,20 @@
{% load i18n %} {% load i18n %}
<div class="container px-md-3 py-3 column-gap-5"> <div class="tw:container tw:px-md-3 tw:py-3 tw:column-gap-5">
<div class="tw:text-3xl fw-bold font-monospace tw:w-full mb-3"> <div class="tw:text-3xl tw:font-bold tw:font-mono tw:w-full tw:mb-3">
{% spaceless %} {% spaceless %}
<div>{% translate 'Import Profiles' %}<span> <div>{% translate 'Import Profiles' %}<span>
<span class="dropdown" data-bs-toggle="tooltip" <span class="tw:dropdown" data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"> data-bs-title="{% translate "Add" %}">
<a class="text-decoration-none tw:text-2xl p-1" role="button" <a class="tw:no-underline tw:text-2xl tw:p-1" role="button"
data-bs-toggle="dropdown" data-bs-toggle="dropdown"
data-bs-title="{% translate "Add" %}" aria-expanded="false"> data-bs-title="{% translate "Add" %}" aria-expanded="false">
<i class="fa-solid fa-circle-plus fa-fw"></i> <i class="fa-solid fa-circle-plus fa-fw"></i>
</a> </a>
<ul class="dropdown-menu"> <ul class="tw:dropdown-content tw:menu tw:bg-base-100 tw:rounded-box tw:z-[1] tw:w-52 tw:p-2 tw:shadow">
<li><a class="dropdown-item" <li><a role="button"
role="button"
hx-get="{% url 'import_profiles_add' %}" hx-get="{% url 'import_profiles_add' %}"
hx-target="#generic-offcanvas">{% trans 'New' %}</a></li> hx-target="#generic-offcanvas">{% trans 'New' %}</a></li>
<li><a class="dropdown-item" <li><a role="button"
role="button"
hx-get="{% url 'import_presets_list' %}" hx-get="{% url 'import_presets_list' %}"
hx-target="#persistent-generic-offcanvas-left">{% trans 'From preset' %}</a></li> hx-target="#persistent-generic-offcanvas-left">{% trans 'From preset' %}</a></li>
</ul> </ul>
@@ -25,45 +23,45 @@
{% endspaceless %} {% endspaceless %}
</div> </div>
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body table-responsive"> <div class="tw:card-body tw:overflow-x-auto">
{% if profiles %} {% if profiles %}
<c-config.search></c-config.search> <c-config.search></c-config.search>
<table class="table table-hover text-nowrap"> <table class="tw:table tw:table-hover tw:whitespace-nowrap">
<thead> <thead>
<tr> <tr>
<th scope="col" class="col-auto"></th> <th scope="col" class="tw:w-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th> <th scope="col">{% translate 'Name' %}</th>
<th scope="col" class="col">{% translate 'Version' %}</th> <th scope="col">{% translate 'Version' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for profile in profiles %} {% for profile in profiles %}
<tr class="profile"> <tr class="profile">
<td class="col-auto"> <td class="tw:w-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}"> <div class="tw:join" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}" data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'import_profile_edit' profile_id=profile.id %}" hx-get="{% url 'import_profile_edit' profile_id=profile.id %}"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a> <i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-success" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-success"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Runs" %}" data-bs-title="{% translate "Runs" %}"
hx-get="{% url 'import_profile_runs_list' profile_id=profile.id %}" hx-get="{% url 'import_profile_runs_list' profile_id=profile.id %}"
hx-target="#persistent-generic-offcanvas-left"> hx-target="#persistent-generic-offcanvas-left">
<i class="fa-solid fa-person-running fa-fw"></i></a> <i class="fa-solid fa-person-running fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-primary" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-primary"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Import" %}" data-bs-title="{% translate "Import" %}"
hx-get="{% url 'import_run_add' profile_id=profile.id %}" hx-get="{% url 'import_run_add' profile_id=profile.id %}"
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<i class="fa-solid fa-file-import fa-fw"></i></a> <i class="fa-solid fa-file-import fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger" <a class="tw:btn tw:btn-secondary tw:btn-sm tw:join-item tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"
@@ -76,8 +74,8 @@
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a> _="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div> </div>
</td> </td>
<td class="col">{{ profile.name }}</td> <td>{{ profile.name }}</td>
<td class="col">{{ profile.get_version_display }}</td> <td>{{ profile.get_version_display }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@@ -6,28 +6,28 @@
{% block body %} {% block body %}
{% if presets %} {% if presets %}
<div id="search" class="mb-3"> <div id="search" class="tw:mb-3">
<label class="w-100"> <label class="tw:w-full">
<input type="search" <input type="search"
class="form-control" class="tw:input tw:input-bordered tw:w-full"
placeholder="{% translate 'Search' %}" placeholder="{% translate 'Search' %}"
_="on input or search _="on input or search
show < .col /> in <#items/> show < .col /> in <#items/>
when its textContent.toLowerCase() contains my value.toLowerCase()"/> when its textContent.toLowerCase() contains my value.toLowerCase()"/>
</label> </label>
</div> </div>
<div class="row row-cols-1 g-4" id="items"> <div class="tw:grid tw:grid-cols-1 tw:gap-4" id="items">
{% for preset in presets %} {% for preset in presets %}
<a class="text-decoration-none" <a class="tw:no-underline"
role="button" role="button"
hx-post="{% url 'import_profiles_add' %}" hx-post="{% url 'import_profiles_add' %}"
hx-vals='{"yaml_config": {{ preset.config }}, "name": "{{ preset.name }}", "version": "{{ preset.schema_version }}", "message": {{ preset.message }}}' hx-vals='{"yaml_config": {{ preset.config }}, "name": "{{ preset.name }}", "version": "{{ preset.schema_version }}", "message": {{ preset.message }}}'
hx-target="#generic-offcanvas"> hx-target="#generic-offcanvas">
<div class="col"> <div class="col">
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title">{{ preset.name }}</h5> <h5 class="tw:card-title">{{ preset.name }}</h5>
<hr> <hr>
<p>{{ preset.description }}</p> <p>{{ preset.description }}</p>
<p>{% trans 'By' %} {{ preset.authors|join:", " }}</p> <p>{% trans 'By' %} {{ preset.authors|join:", " }}</p>

View File

@@ -11,21 +11,21 @@
class="show-loading" class="show-loading"
hx-swap="show:none scroll:none"> hx-swap="show:none scroll:none">
{% if runs %} {% if runs %}
<div class="row row-cols-1 g-4"> <div class="tw:grid tw:grid-cols-1 tw:gap-4">
{% for run in runs %} {% for run in runs %}
<div class="col"> <div class="col">
<div class="card"> <div class="tw:card tw:bg-base-100 tw:shadow-xl">
<div class="card-header tw:text-sm {% if run.status == run.Status.QUEUED %}text-body{% elif run.status == run.Status.PROCESSING %}text-warning{% elif run.status == run.Status.FINISHED %}text-success{% else %}text-danger{% endif %}"> <div class="tw:card-header tw:bg-base-200 tw:p-4 tw:text-sm {% if run.status == run.Status.QUEUED %}tw:text-base-content{% elif run.status == run.Status.PROCESSING %}tw:text-warning{% elif run.status == run.Status.FINISHED %}tw:text-success{% else %}tw:text-error{% endif %}">
<span><i class="fa-solid {% if run.status == run.Status.QUEUED %}fa-hourglass-half{% elif run.status == run.Status.PROCESSING %}fa-spinner{% elif run.status == run.Status.FINISHED %}fa-check{% else %}fa-xmark{% endif %} fa-fw me-2"></i>{{ run.get_status_display }}</span> <span><i class="fa-solid {% if run.status == run.Status.QUEUED %}fa-hourglass-half{% elif run.status == run.Status.PROCESSING %}fa-spinner{% elif run.status == run.Status.FINISHED %}fa-check{% else %}fa-xmark{% endif %} fa-fw tw:me-2"></i>{{ run.get_status_display }}</span>
</div> </div>
<div class="card-body"> <div class="tw:card-body">
<h5 class="card-title"><i class="fa-solid fa-hashtag me-1 tw:text-xs tw:text-gray-400"></i>{{ run.id }}<span class="tw:text-xs tw:text-gray-400 ms-1">({{ run.file_name }})</span></h5> <h5 class="tw:card-title"><i class="fa-solid fa-hashtag tw:me-1 tw:text-xs tw:text-gray-400"></i>{{ run.id }}<span class="tw:text-xs tw:text-gray-400 tw:ms-1">({{ run.file_name }})</span></h5>
<hr> <hr>
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 w-100 g-4"> <div class="tw:grid tw:grid-cols-1 tw:md:grid-cols-2 tw:lg:grid-cols-3 tw:w-full tw:gap-4">
<div class="col"> <div class="col">
<div class="d-flex flex-row"> <div class="tw:flex tw:flex-row">
<div class="d-flex flex-column"> <div class="tw:flex tw:flex-col">
<div class="text-body-secondary tw:text-xs tw:font-medium"> <div class="tw:text-base-content/70 tw:text-xs tw:font-medium">
{% trans 'Total Items' %} {% trans 'Total Items' %}
</div> </div>
<div class="tw:text-sm"> <div class="tw:text-sm">
@@ -36,9 +36,9 @@
</div> </div>
<div class="col"> <div class="col">
<div class="d-flex flex-row"> <div class="tw:flex tw:flex-row">
<div class="d-flex flex-column"> <div class="tw:flex tw:flex-col">
<div class="text-body-secondary tw:text-xs tw:font-medium"> <div class="tw:text-base-content/70 tw:text-xs tw:font-medium">
{% trans 'Processed Items' %} {% trans 'Processed Items' %}
</div> </div>
<div class="tw:text-sm"> <div class="tw:text-sm">
@@ -49,9 +49,9 @@
</div> </div>
<div class="col"> <div class="col">
<div class="d-flex flex-row"> <div class="tw:flex tw:flex-row">
<div class="d-flex flex-column"> <div class="tw:flex tw:flex-col">
<div class="text-body-secondary tw:text-xs tw:font-medium"> <div class="tw:text-base-content/70 tw:text-xs tw:font-medium">
{% trans 'Skipped Items' %} {% trans 'Skipped Items' %}
</div> </div>
<div class="tw:text-sm"> <div class="tw:text-sm">
@@ -62,9 +62,9 @@
</div> </div>
<div class="col"> <div class="col">
<div class="d-flex flex-row"> <div class="tw:flex tw:flex-row">
<div class="d-flex flex-column"> <div class="tw:flex tw:flex-col">
<div class="text-body-secondary tw:text-xs tw:font-medium"> <div class="tw:text-base-content/70 tw:text-xs tw:font-medium">
{% trans 'Failed Items' %} {% trans 'Failed Items' %}
</div> </div>
<div class="tw:text-sm"> <div class="tw:text-sm">
@@ -75,9 +75,9 @@
</div> </div>
<div class="col"> <div class="col">
<div class="d-flex flex-row"> <div class="tw:flex tw:flex-row">
<div class="d-flex flex-column"> <div class="tw:flex tw:flex-col">
<div class="text-body-secondary tw:text-xs tw:font-medium"> <div class="tw:text-base-content/70 tw:text-xs tw:font-medium">
{% trans 'Successful Items' %} {% trans 'Successful Items' %}
</div> </div>
<div class="tw:text-sm"> <div class="tw:text-sm">
@@ -89,14 +89,14 @@
</div> </div>
</div> </div>
<div class="card-footer text-body-secondary"> <div class="tw:card-footer tw:bg-base-200 tw:p-4 tw:text-base-content/70">
<a class="text-decoration-none text-info" <a class="tw:no-underline tw:text-info"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Logs" %}" data-bs-title="{% translate "Logs" %}"
hx-get="{% url 'import_run_log' profile_id=profile.id run_id=run.id %}" hx-get="{% url 'import_run_log' profile_id=profile.id run_id=run.id %}"
hx-target="#generic-offcanvas"><i class="fa-solid fa-file-lines"></i></a> hx-target="#generic-offcanvas"><i class="fa-solid fa-file-lines"></i></a>
<a class="text-decoration-none text-danger" <a class="tw:no-underline tw:text-error"
role="button" role="button"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}" data-bs-title="{% translate "Delete" %}"

View File

@@ -5,8 +5,8 @@
{% block title %}{% translate 'Logs for' %} #{{ run.id }}{% endblock %} {% block title %}{% translate 'Logs for' %} #{{ run.id }}{% endblock %}
{% block body %} {% block body %}
<div class="card tw:max-h-full tw:overflow-auto"> <div class="tw:card tw:bg-base-100 tw:shadow-xl tw:max-h-full tw:overflow-auto">
<div class="card-body"> <div class="tw:card-body">
{{ run.logs|linebreaks }} {{ run.logs|linebreaks }}
</div> </div>
</div> </div>

View File

@@ -3,14 +3,16 @@
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% load active_link %} {% load active_link %}
<nav class="navbar border-bottom bg-body-tertiary d-flex d-lg-none" hx-boost="true"> <nav class="tw:navbar tw:border-b tw:border-base-300 tw:bg-base-200 tw:flex tw:lg:hidden" hx-boost="true">
<div class="container-fluid"> <div class="tw:container tw:mx-auto tw:px-4 tw:flex tw:justify-between tw:items-center tw:w-full">
<a class="navbar-brand fw-bold text-primary font-base" href="{% url 'index' %}"> <a class="tw:text-xl tw:font-bold tw:text-primary" href="{% url 'index' %}">
<img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="40" width="40" title="WYGIWYH"/> <img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="40" width="40" title="WYGIWYH"/>
</a> </a>
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebar" <button class="tw:btn tw:btn-ghost tw:lg:hidden" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebar"
aria-controls="sidebar" aria-label={% translate "Toggle navigation" %}> aria-controls="sidebar" aria-label={% translate "Toggle navigation" %}>
<span class="navbar-toggler-icon"></span> <svg class="tw:w-6 tw:h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button> </button>
</div> </div>
</nav> </nav>

View File

@@ -1,24 +1,24 @@
{% load settings %} {% load settings %}
{% load i18n %} {% load i18n %}
<div class="dropdown"> <div class="tw:dropdown tw:dropdown-top tw:dropdown-end">
<div class="btn btn-secondary btn-sm" type="button" data-bs-toggle="dropdown" aria-expanded="false"> <div tabindex="0" role="button" class="tw:btn tw:btn-secondary tw:btn-sm">
<i class="fa-solid fa-cog"></i> <i class="fa-solid fa-cog"></i>
</div> </div>
<ul class="dropdown-menu dropdown-menu-start dropdown-menu-lg-end"> <ul tabindex="0" class="tw:dropdown-content tw:menu tw:bg-base-100 tw:rounded-box tw:z-[1] tw:w-52 tw:p-2 tw:shadow">
<li><a class="dropdown-item" <li><a
hx-get="{% url 'user_settings' %}" hx-get="{% url 'user_settings' %}"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
role="button"> role="button">
<i class="fa-solid fa-gear me-2 fa-fw"></i>{% translate 'Settings' %}</a></li> <i class="fa-solid fa-gear tw:me-2 fa-fw"></i>{% translate 'Settings' %}</a></li>
<li><a class="dropdown-item" <li><a
hx-get="{% url 'user_edit' pk=request.user.id %}" hx-get="{% url 'user_edit' pk=request.user.id %}"
hx-target="#generic-offcanvas" hx-target="#generic-offcanvas"
role="button"> role="button">
<i class="fa-solid fa-user me-2 fa-fw"></i>{% translate 'Edit profile' %}</a></li> <i class="fa-solid fa-user tw:me-2 fa-fw"></i>{% translate 'Edit profile' %}</a></li>
<li><hr class="dropdown-divider"></li> <hr class="tw:my-1 tw:text-base-content/60">
{% spaceless %} {% spaceless %}
<li> <li>
<a class="dropdown-item" hx-get="{% url 'toggle_amount_visibility' %}" role="button"> <a hx-get="{% url 'toggle_amount_visibility' %}" role="button">
{% if user.settings.hide_amounts %} {% if user.settings.hide_amounts %}
{% include 'users/generic/show_amounts.html' %} {% include 'users/generic/show_amounts.html' %}
{% else %} {% else %}
@@ -29,7 +29,7 @@
{% endspaceless %} {% endspaceless %}
{% spaceless %} {% spaceless %}
<li> <li>
<a class="dropdown-item" hx-get="{% url 'toggle_sound_playing' %}" role="button"> <a hx-get="{% url 'toggle_sound_playing' %}" role="button">
{% if user.settings.mute_sounds %} {% if user.settings.mute_sounds %}
{% include 'users/generic/play_sounds.html' %} {% include 'users/generic/play_sounds.html' %}
{% else %} {% else %}
@@ -38,15 +38,15 @@
</a> </a>
</li> </li>
{% endspaceless %} {% endspaceless %}
<li><hr class="dropdown-divider"></li> <hr class="tw:my-1 tw:text-base-content/60">
<li> <li>
<a class="dropdown-item" hx-get="{% url 'invalidate_cache' %}" role="button"> <a hx-get="{% url 'invalidate_cache' %}" role="button">
<i class="fa-solid fa-broom me-2 fa-fw"></i>{% translate 'Clear cache' %} <i class="fa-solid fa-broom tw:me-2 fa-fw"></i>{% translate 'Clear cache' %}
</a> </a>
</li> </li>
<li><a class="dropdown-item" href="{% url 'logout' %}"><i class="fa-solid fa-door-open me-2 fa-fw"></i <li><a href="{% url 'logout' %}"><i class="fa-solid fa-door-open tw:me-2 fa-fw"></i
>{% translate 'Logout' %}</a></li> >{% translate 'Logout' %}</a></li>
<li><hr class="dropdown-divider"></li> <hr class="tw:my-1 tw:text-base-content/60">
<li><a class="dropdown-item" href="https://github.com/eitchtee/WYGIWYH/releases" target="_blank" rel="nofollow">v. {% settings "APP_VERSION" %}</a></li> <li><a href="https://github.com/eitchtee/WYGIWYH/releases" target="_blank" rel="nofollow">v. {% settings "APP_VERSION" %}</a></li>
</ul> </ul>
</div> </div>

View File

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

View File

@@ -12,3 +12,11 @@
<div class="tw:bg-yellow-300"></div> <div class="tw:bg-yellow-300"></div>
<div class="tw:bg-red-300"></div> <div class="tw:bg-red-300"></div>
<div class="tw:bg-green-300"></div> <div class="tw:bg-green-300"></div>
<div class="tw:btn-primary"></div>
<div class="tw:btn-secondary"></div>
<div class="tw:btn-accent"></div>
<div class="tw:btn-neutral"></div>
<div class="tw:btn-info"></div>
<div class="tw:btn-success"></div>
<div class="tw:btn-error"></div>
<div class="tw:btn-warning"></div>

View File

@@ -1,10 +1,12 @@
{% load webpack_loader %} {% load django_vite %}
{% javascript_pack 'bootstrap' attrs="defer" %} {% vite_hmr_client %}
{% javascript_pack 'sweetalert2' attrs="defer" %}
{% javascript_pack 'select' attrs="defer" %} {% vite_asset 'bootstrap' defer=True %}
{% javascript_pack 'datepicker' %} {% vite_asset 'sweetalert2' defer=True %}
{% javascript_pack 'autosize' attrs="defer" %} {% vite_asset 'select' defer=True %}
{% vite_asset 'datepicker' %}
{% vite_asset 'autosize' defer=True %}
{% include 'includes/scripts/hyperscript/init_tom_select.html' %} {% include 'includes/scripts/hyperscript/init_tom_select.html' %}
{% include 'includes/scripts/hyperscript/init_date_picker.html' %} {% include 'includes/scripts/hyperscript/init_date_picker.html' %}
@@ -15,8 +17,10 @@
{% include 'includes/scripts/hyperscript/sounds.html' %} {% include 'includes/scripts/hyperscript/sounds.html' %}
{% include 'includes/scripts/hyperscript/swal.html' %} {% include 'includes/scripts/hyperscript/swal.html' %}
{% javascript_pack 'htmx' attrs="defer" %} {% vite_asset 'htmx' defer=True %}
{% javascript_pack 'charts' %} {% vite_asset 'charts' %}
{% vite_asset 'style' %}
<script> <script>
let tz = Intl.DateTimeFormat().resolvedOptions().timeZone; let tz = Intl.DateTimeFormat().resolvedOptions().timeZone;

View File

@@ -11,18 +11,17 @@
id="sidebar" id="sidebar"
hx-boost="true" hx-boost="true"
hx-swap="transition:true" hx-swap="transition:true"
data-bs-scroll="true" class="offcanvas-lg offcanvas-start tw:lg:flex tw:flex-col tw:fixed tw:top-0 tw:left-0 tw:h-full tw:bg-base-300! tw:shadow-sm tw:z-[1020]">
class="offcanvas-lg offcanvas-start d-lg-flex flex-column position-fixed top-0 start-0 h-100 bg-body-tertiary shadow-sm tw:z-1020"> <div class="tw:hidden tw:lg:flex tw:items-center tw:justify-between tw:pr-4 tw:border-b tw:border-base-content/10 sidebar-submenu-header">
<a href="{% url 'index' %}" class="tw:m-0 tw:hidden tw:lg:flex tw:justify-start tw:p-3 tw:no-underline sidebar-title">
<div class="d-none d-lg-flex tw:justify-between tw:items-center tw:border-b tw:border-gray-600 tw:lg:flex">
<a href="{% url 'index' %}" class="m-0 d-none d-lg-flex tw:justify-start p-3 text-decoration-none sidebar-title">
<img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="30" width="30" title="WYGIWYH"/> <img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="30" width="30" title="WYGIWYH"/>
<span class="fs-4 fw-bold ms-3">WYGIWYH</span> <span class="tw:text-2xl tw:font-bold tw:ml-3">WYGIWYH</span>
</a> </a>
<button <button
id="sidebar-toggle-btn" id="sidebar-toggle-btn"
class="text-secondary-emphasis tw:rounded-full tw:w-12 tw:h-12 tw:flex tw:items-center tw:justify-center tw:transition-all tw:duration-300"
class="tw:btn tw:btn-ghost tw:btn-circle tw:w-12 tw:h-12 tw:flex tw:items-center tw:justify-center tw:transition-all tw:duration-300"
hx-get="{% url 'toggle_sidebar_status' %}" hx-get="{% url 'toggle_sidebar_status' %}"
_="on click _="on click
toggle .sidebar-floating on #sidebar-container toggle .sidebar-floating on #sidebar-container
@@ -36,17 +35,17 @@
</button> </button>
</div> </div>
<div class="offcanvas-header"> <div class="tw:lg:hidden tw:flex tw:justify-between tw:items-center tw:p-4 tw:text-base-content">
<a href="{% url 'index' %}" class="offcanvas-title d-flex tw:justify-start text-decoration-none"> <a href="{% url 'index' %}" class="tw:flex tw:justify-start tw:no-underline">
<img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="30" width="30" title="WYGIWYH"/> <img src="{% static 'img/logo-icon.svg' %}" alt="WYGIWYH Logo" height="30" width="30" title="WYGIWYH"/>
<span class="fs-4 fw-bold ms-3">WYGIWYH</span> <span class="tw:text-2xl tw:font-bold tw:ml-3">WYGIWYH</span>
</a> </a>
<button type="button" class="btn-close" data-bs-target="#sidebar" data-bs-dismiss="offcanvas" <button type="button" class="tw:btn tw:btn-ghost tw:btn-sm tw:btn-circle" data-bs-target="#sidebar" data-bs-dismiss="offcanvas"
aria-label={% translate 'Close' %}></button> aria-label={% translate 'Close' %}><i class="fa-solid fa-xmark"></i></button>
</div> </div>
<hr class="m-0"> <hr class="tw:m-0 tw:text-base-content/60">
<ul class="list-unstyled p-3 d-flex flex-column gap-0 tw:text-nowrap tw:lg:group-hover:animate-[disable-pointer-events]" <ul class="tw:list-none tw:p-3 tw:flex tw:flex-col tw:gap-1 tw:whitespace-nowrap tw:lg:group-hover:animate-[disable-pointer-events]"
style="animation-duration: 100ms"> style="animation-duration: 100ms">
<c-components.sidebar-menu-item <c-components.sidebar-menu-item
@@ -136,42 +135,43 @@
</c-components.sidebar-menu-item> </c-components.sidebar-menu-item>
<div> <div>
<hr> <hr class="tw:border-base-300">
</div> </div>
<div type="button" <div role="button"
data-bs-toggle="collapse" data-bs-toggle="collapse"
data-bs-target="#collapsible-panel" data-bs-target="#collapsible-panel"
aria-expanded="false" aria-expanded="false"
aria-controls="collapsible-panel" aria-controls="collapsible-panel"
class="sidebar-menu-item tw:text-wrap tw:lg:text-nowrap tw:lg:text-sm d-flex align-items-center text-decoration-none p-2 rounded-3 sidebar-item {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index||users_index' css_class="sidebar-active" %}"> class="sidebar-menu-item tw:text-wrap tw:lg:text-nowrap tw:lg:text-sm tw:flex tw:items-center tw:no-underline tw:p-2 tw:rounded-2xl tw:cursor-pointer sidebar-item {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index||users_index' css_class="sidebar-active" %}">
<i class="fa-solid fa-toolbox fa-fw"></i> <i class="fa-solid fa-toolbox fa-fw"></i>
<span class="ms-3 fw-medium tw:lg:group-hover:truncate tw:lg:group-focus:truncate tw:lg:group-hover:text-ellipsis tw:lg:group-focus:text-ellipsis"> <span class="tw:ml-3 tw:font-medium tw:lg:group-hover:truncate tw:lg:group-focus:truncate tw:lg:group-hover:text-ellipsis tw:lg:group-focus:text-ellipsis">
{% translate 'Management' %} {% translate 'Management' %}
</span> </span>
<i class="fa-solid fa-chevron-right fa-fw ms-auto pe-2"></i> <i class="fa-solid fa-chevron-right fa-fw tw:ml-auto tw:pe-2"></i>
</div> </div>
</ul> </ul>
<div class="mt-auto p-2 w-100"> <div class="tw:mt-auto tw:p-2 tw:w-full">
<div id="collapsible-panel" <div id="collapsible-panel"
class="p-0 collapse tw:absolute tw:bottom-0 tw:left-0 tw:w-full tw:z-30 tw:max-h-dvh {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index||users_index' css_class="show" %}"> class="tw:p-0 collapse tw:absolute tw:bottom-0 tw:left-0 tw:w-full tw:z-30 tw: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="tw:h-dvh tw:backdrop-blur-3xl tw:flex tw:flex-col"> <div class="tw:h-dvh tw:backdrop-blur-3xl tw:flex tw:flex-col">
<div <div
class="tw:justify-between tw:items-center tw:p-4 tw:border-b tw:border-gray-600 sidebar-submenu-header"> class="tw:justify-between tw:items-center tw:p-4 tw:border-b tw:border-base-content/10 sidebar-submenu-header tw:text-base-content">
<h5 class="tw:text-lg tw:font-semibold tw:text-gray-800 m-0"> <h5 class="tw:text-lg tw:font-semibold tw:text-base-content tw:m-0">
{% trans 'Management' %} {% trans 'Management' %}
</h5> </h5>
<button type="button" class="btn-close" aria-label="Close" <button type="button" class="tw:btn tw:btn-ghost tw:btn-sm tw:btn-circle" aria-label="{% trans 'Close' %}"
data-bs-toggle="collapse" data-bs-toggle="collapse"
data-bs-target="#collapsible-panel" data-bs-target="#collapsible-panel"
aria-expanded="true" aria-expanded="true"
aria-controls="collapsible-panel"> aria-controls="collapsible-panel">
<i class="fa-solid fa-xmark"></i>
</button> </button>
</div> </div>
<ul class="list-unstyled p-3 d-flex flex-column gap-1 tw:lg:group-hover:animate-[disable-pointer-events] tw:flex-1" <ul class="tw:list-none tw:p-3 tw:flex tw:flex-col tw:gap-2 tw:lg:group-hover:animate-[disable-pointer-events] tw:flex-1"
style="animation-duration: 100ms"> style="animation-duration: 100ms">
<c-components.sidebar-menu-header title="{% translate 'Transactions' %}"></c-components.sidebar-menu-header> <c-components.sidebar-menu-header title="{% translate 'Transactions' %}"></c-components.sidebar-menu-header>
<c-components.sidebar-menu-item <c-components.sidebar-menu-item
@@ -269,16 +269,16 @@
</div> </div>
{% get_update_check as update_check %} {% get_update_check as update_check %}
{% if update_check.update_available %} {% if update_check.update_available %}
<div class="my-3"> <div class="tw:my-3">
<a class="px-3 badge text-bg-primary text-decoration-none tw:cursor-pointer w-100 tw:text-xs!" <a class="tw:px-3 tw:badge tw:badge-primary tw:no-underline tw:cursor-pointer tw:w-full !tw:text-xs"
href="https://github.com/eitchtee/WYGIWYH/releases/latest" target="_blank"><i href="https://github.com/eitchtee/WYGIWYH/releases/latest" target="_blank"><i
class="fa-solid fa-circle-exclamation fa-fw me-2"></i><span class="fa-solid fa-circle-exclamation fa-fw tw:mr-2"></i><span
class="tw:lg:invisible tw:lg:group-hover:visible">v.{{ update_check.latest_version }} {% translate 'is available' %}!</span></a> class="tw:lg:invisible tw:lg:group-hover:visible">v.{{ update_check.latest_version }} {% translate 'is available' %}!</span></a>
</div> </div>
{% endif %} {% endif %}
<div class="btn-group w-100 sidebar-item" role="group"> <div class="tw:btn-group tw:w-full sidebar-item" role="group">
<button type="button" class="btn btn-secondary btn-sm" data-bs-toggle="tooltip" <button type="button" class="tw:btn tw:btn-secondary tw:btn-sm tw:w-full" data-bs-toggle="tooltip"
data-bs-title="{% trans "Calculator" %}" data-bs-title="{% trans "Calculator" %}"
_="on click trigger show on #calculator"> _="on click trigger show on #calculator">
<i class="fa-solid fa-calculator fa-fw"></i> <i class="fa-solid fa-calculator fa-fw"></i>
@@ -287,14 +287,14 @@
</div> </div>
<div> <div>
<hr class="my-1"> <hr class="tw:my-1 tw:border-base-300">
<div <div
class="ps-4 pe-2 py-2 d-flex align-items-center text-decoration-none justify-content-between"> class="tw:ps-4 tw:pe-2 tw:py-2 tw:flex tw:items-center tw:no-underline tw:justify-between">
<div class="d-flex align-items-center" style="min-width: 0;"> <div class="tw:flex tw:items-center" style="min-width: 0;">
<i class="fa-solid fa-circle-user text-body-secondary"></i> <i class="fa-solid fa-circle-user tw:text-base-content/60"></i>
<strong class="mx-2 text-body-secondary text-truncate sidebar-invisible"> <strong class="tw:mx-2 tw:text-base-content/60 tw:truncate sidebar-invisible">
{{ user.email }} {{ user.email }}
</strong> </strong>
</div> </div>

View File

@@ -1,3 +0,0 @@
{% load webpack_loader %}
{% stylesheet_pack 'style' %}

View File

@@ -1,5 +1,5 @@
{% load formats %} {% load formats %}
<div class="tw:hidden tw:w-[60vw] tw:lg:w-[30vw] tw:xl:w-[20vw] position-fixed shadow rounded-3 bg-body tw:border-gray-700 tw:border tw:border-solid tw:text-center tw:align-middle tw:z-[2000] tw:touch-none user-select-none" <div class="tw:hidden tw:w-[60vw] tw:lg:w-[30vw] tw:xl:w-[20vw] tw:fixed tw:shadow tw:rounded-3xl tw:bg-base-100 tw:border-base-300 tw:border tw:border-solid tw:text-center tw:align-middle tw:z-[2000] tw:touch-none tw:select-none"
id="calculator" id="calculator"
hx-preserve hx-preserve
_=" _="
@@ -48,12 +48,12 @@
end"> end">
<div id="calculator-handle" <div id="calculator-handle"
class="position-absolute bg-secondary rounded-top-2 tw:cursor-move d-flex align-items-center justify-content-center tw:top-[-20px] tw:left-[3px] tw:w-[2em] tw:h-[20px]"> class="tw:absolute tw:bg-secondary tw:rounded-t-lg tw:cursor-move tw:flex tw:items-center tw:justify-center tw:top-[-20px] tw:left-[3px] tw:w-[2em] tw:h-[20px]">
<i class="fa-solid fa-grip"></i> <i class="fa-solid fa-grip"></i>
</div> </div>
<input type="search" <input type="search"
class="form-control" class="tw:input tw:w-full"
id="calculator-input" id="calculator-input"
_="on click me.focus() _="on click me.focus()
on input or search on input or search
@@ -91,12 +91,12 @@
end" end"
placeholder="2 + 2"> placeholder="2 + 2">
<div class="tw:hidden" id="calculator-result-container"> <div class="tw:hidden" id="calculator-result-container">
<div class="d-flex flex-row p-2 justify-content-between"> <div class="tw:flex tw:flex-row tw:p-2 tw:justify-between">
<div class="tw:text-gray-400">=</div> <div class="tw:text-base-content/40">=</div>
<div id="calculator-result" class="user-select-all"></div> <div id="calculator-result" class="tw:select-all"></div>
</div> </div>
</div> </div>
<div class="position-absolute tw:cursor-pointer top-0 start-100 translate-middle tw:p-0 text-bg-primary border border-light rounded-circle tw:flex tw:items-center tw:justify-center tw:w-5 tw:h-5" <div class="tw:absolute tw:cursor-pointer tw:top-0 tw:left-full tw:start-100 tw:-translate-x-1/2 tw:-translate-y-1/2 tw:p-0 tw:bg-primary tw:text-primary-content tw:border tw:border-base-100 tw:rounded-full tw:flex tw:items-center tw:justify-center tw:w-5 tw:h-5"
_="on click trigger show on #calculator"> _="on click trigger show on #calculator">
<i class="fa-solid fa-xmark tw:flex tw:items-center tw:justify-center tw:w-full tw:h-full"></i> <i class="fa-solid fa-xmark tw:flex tw:items-center tw:justify-center tw:w-full tw:h-full"></i>
</div> </div>

View File

@@ -1,6 +1,6 @@
{% load i18n %} {% load i18n %}
{% if account_data.labels %} {% if account_data.labels %}
<div class="chart-container" style="position: relative; height:400px; width:100%" <div class="chart-container tw:relative tw:h-[400px] tw:w-full"
_="init call setupAccountChart() end"> _="init call setupAccountChart() end">
<canvas id="accountChart"></canvas> <canvas id="accountChart"></canvas>
</div> </div>

View File

@@ -1,6 +1,6 @@
{% load i18n %} {% load i18n %}
{% if currency_data.labels %} {% if currency_data.labels %}
<div class="chart-container" style="position: relative; height:400px; width:100%" <div class="chart-container tw:relative tw:h-[400px] tw:w-full"
_="init call setupCurrencyChart() end"> _="init call setupCurrencyChart() end">
<canvas id="currencyChart"></canvas> <canvas id="currencyChart"></canvas>
</div> </div>

Some files were not shown because too many files have changed in this diff Show More