1.00
This commit is contained in:
parent
27bd5182e3
commit
f6917d7012
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
core/__pycache__/forms.cpython-311.pyc
Normal file
BIN
core/__pycache__/forms.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,3 +1,15 @@
|
||||
from django.contrib import admin
|
||||
from .models import Category, Transaction
|
||||
|
||||
# Register your models here.
|
||||
@admin.register(Category)
|
||||
class CategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'type', 'icon')
|
||||
list_filter = ('type',)
|
||||
search_fields = ('name',)
|
||||
|
||||
@admin.register(Transaction)
|
||||
class TransactionAdmin(admin.ModelAdmin):
|
||||
list_display = ('date', 'type', 'amount', 'category', 'description')
|
||||
list_filter = ('type', 'category', 'date')
|
||||
search_fields = ('description',)
|
||||
date_hierarchy = 'date'
|
||||
18
core/forms.py
Normal file
18
core/forms.py
Normal file
@ -0,0 +1,18 @@
|
||||
from django import forms
|
||||
from .models import Transaction, Category
|
||||
|
||||
class TransactionForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Transaction
|
||||
fields = ['amount', 'type', 'category', 'date', 'description']
|
||||
widgets = {
|
||||
'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
||||
'amount': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'placeholder': '0.00'}),
|
||||
'type': forms.Select(attrs={'class': 'form-select'}),
|
||||
'category': forms.Select(attrs={'class': 'form-select'}),
|
||||
'description': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'What was this for?'}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['category'].queryset = Category.objects.all()
|
||||
40
core/migrations/0001_initial.py
Normal file
40
core/migrations/0001_initial.py
Normal file
@ -0,0 +1,40 @@
|
||||
# Generated by Django 5.2.7 on 2026-02-01 13:44
|
||||
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Category',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('type', models.CharField(choices=[('income', 'Income'), ('expense', 'Expense')], default='expense', max_length=10)),
|
||||
('icon', models.CharField(blank=True, help_text='FontAwesome icon name (e.g., fa-utensils)', max_length=50, null=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Categories',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Transaction',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('amount', models.DecimalField(decimal_places=2, max_digits=10)),
|
||||
('date', models.DateField(default=django.utils.timezone.now)),
|
||||
('description', models.CharField(blank=True, max_length=255)),
|
||||
('type', models.CharField(choices=[('income', 'Income'), ('expense', 'Expense')], default='expense', max_length=10)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transactions', to='core.category')),
|
||||
],
|
||||
),
|
||||
]
|
||||
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
@ -1,3 +1,32 @@
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
# Create your models here.
|
||||
class Category(models.Model):
|
||||
TRANSACTION_TYPES = [
|
||||
('income', 'Income'),
|
||||
('expense', 'Expense'),
|
||||
]
|
||||
name = models.CharField(max_length=100)
|
||||
type = models.CharField(max_length=10, choices=TRANSACTION_TYPES, default='expense')
|
||||
icon = models.CharField(max_length=50, blank=True, null=True, help_text="FontAwesome icon name (e.g., fa-utensils)")
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Categories"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.get_type_display()})"
|
||||
|
||||
class Transaction(models.Model):
|
||||
TYPES = [
|
||||
('income', 'Income'),
|
||||
('expense', 'Expense'),
|
||||
]
|
||||
amount = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='transactions')
|
||||
date = models.DateField(default=timezone.now)
|
||||
description = models.CharField(max_length=255, blank=True)
|
||||
type = models.CharField(max_length=10, choices=TYPES, default='expense')
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_type_display()}: {self.amount} - {self.description[:20]}"
|
||||
@ -1,25 +1,72 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Knowledge Base{% endblock %}</title>
|
||||
{% if project_description %}
|
||||
<meta name="description" content="{{ project_description }}">
|
||||
<meta property="og:description" content="{{ project_description }}">
|
||||
<meta property="twitter:description" content="{{ project_description }}">
|
||||
{% endif %}
|
||||
{% if project_image_url %}
|
||||
<meta property="og:image" content="{{ project_image_url }}">
|
||||
<meta property="twitter:image" content="{{ project_image_url }}">
|
||||
{% endif %}
|
||||
{% load static %}
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
||||
{% block head %}{% endblock %}
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}BudgetTracker{% endblock %}</title>
|
||||
|
||||
{% if project_description %}
|
||||
<meta name="description" content="{{ project_description }}">
|
||||
<meta property="og:description" content="{{ project_description }}">
|
||||
<meta property="twitter:description" content="{{ project_description }}">
|
||||
{% endif %}
|
||||
{% if project_image_url %}
|
||||
<meta property="og:image" content="{{ project_image_url }}">
|
||||
<meta property="twitter:image" content="{{ project_image_url }}">
|
||||
{% endif %}
|
||||
|
||||
{% load static %}
|
||||
<!-- Bootstrap 5 CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- FontAwesome -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<!-- Custom CSS -->
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
||||
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block content %}{% endblock %}
|
||||
</body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-white border-bottom sticky-top py-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand fw-bold d-flex align-items-center" href="{% url 'home' %}">
|
||||
<div class="bg-primary bg-opacity-10 p-2 rounded-3 me-2">
|
||||
<i class="fas fa-piggy-bank text-primary"></i>
|
||||
</div>
|
||||
BudgetTracker
|
||||
</a>
|
||||
<button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto align-items-center">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3" href="{% url 'home' %}">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3" href="/admin/core/category/">Categories</a>
|
||||
</li>
|
||||
<li class="nav-item ms-lg-3">
|
||||
<a class="btn btn-dark rounded-pill px-4" href="/admin/">
|
||||
Admin <i class="fas fa-user-cog ms-1 small"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</html>
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="py-5 bg-white border-top mt-5">
|
||||
<div class="container text-center">
|
||||
<p class="text-muted mb-0">© 2026 BudgetTracker. Built with Django & Flatlogic.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap 5 Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@ -1,145 +1,147 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ project_name }}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@keyframes bg-pan {
|
||||
0% {
|
||||
background-position: 0% 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2.5rem 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
|
||||
font-weight: 700;
|
||||
margin: 0 0 1.2rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.loader {
|
||||
margin: 1.5rem auto;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.runtime code {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
padding: 0.15rem 0.45rem;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your app…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
<div class="hero-gradient">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h1 class="display-5 mb-2">Hello! Here's your budget overview.</h1>
|
||||
<p class="lead opacity-75">Tracking your finances for {{ current_month }}</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<button class="btn btn-light btn-lg rounded-pill px-4 shadow-sm" data-bs-toggle="modal" data-bs-target="#addTransactionModal">
|
||||
<i class="fas fa-plus me-2"></i> Add Transaction
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
|
||||
<p class="runtime">
|
||||
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
|
||||
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
|
||||
</footer>
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
<div class="container py-5">
|
||||
<!-- Stats Row -->
|
||||
<div class="row g-4 mb-5">
|
||||
<div class="col-md-4">
|
||||
<div class="stats-card p-4">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="bg-primary bg-opacity-10 p-3 rounded-circle me-3">
|
||||
<i class="fas fa-wallet text-primary fs-4"></i>
|
||||
</div>
|
||||
<span class="text-muted fw-medium">Total Balance</span>
|
||||
</div>
|
||||
<h2 class="mb-0 {% if balance >= 0 %}income-text{% else %}expense-text{% endif %}">
|
||||
${{ balance|floatformat:2 }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="stats-card p-4">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="bg-success bg-opacity-10 p-3 rounded-circle me-3">
|
||||
<i class="fas fa-arrow-down text-success fs-4"></i>
|
||||
</div>
|
||||
<span class="text-muted fw-medium">Monthly Income</span>
|
||||
</div>
|
||||
<h2 class="mb-0 income-text">${{ monthly_income|floatformat:2 }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="stats-card p-4">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="bg-danger bg-opacity-10 p-3 rounded-circle me-3">
|
||||
<i class="fas fa-arrow-up text-danger fs-4"></i>
|
||||
</div>
|
||||
<span class="text-muted fw-medium">Monthly Expenses</span>
|
||||
</div>
|
||||
<h2 class="mb-0 expense-text">${{ monthly_expense|floatformat:2 }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transactions List -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h3 class="mb-0">Recent Transactions</h3>
|
||||
<a href="/admin/core/transaction/" class="text-decoration-none text-muted fw-medium">
|
||||
View All <i class="fas fa-chevron-right ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for transaction in recent_transactions %}
|
||||
<tr class="transaction-row {{ transaction.type }} shadow-sm">
|
||||
<td width="15%">
|
||||
<div class="fw-bold">{{ transaction.date|date:"M d" }}</div>
|
||||
<small class="text-muted">{{ transaction.date|date:"Y" }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-semibold">{{ transaction.description|default:"No description" }}</div>
|
||||
<span class="badge bg-light text-dark rounded-pill">{{ transaction.category.name|default:"Uncategorized" }}</span>
|
||||
</td>
|
||||
<td class="text-end" width="20%">
|
||||
<h5 class="mb-0 {% if transaction.type == 'income' %}income-text{% else %}expense-text{% endif %}">
|
||||
{% if transaction.type == 'income' %}+{% else %}-{% endif %}${{ transaction.amount|floatformat:2 }}
|
||||
</h5>
|
||||
<small class="text-muted">{{ transaction.get_type_display }}</small>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="3" class="text-center py-5">
|
||||
<img src="https://illustrations.popsy.co/gray/saving-money.svg" alt="Empty" style="width: 200px;" class="mb-3">
|
||||
<p class="text-muted">No transactions yet. Start by adding one!</p>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Transaction Modal -->
|
||||
<div class="modal fade" id="addTransactionModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow-lg" style="border-radius: 1.5rem;">
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h4 class="modal-title px-3 pt-3">New Entry</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small text-uppercase fw-bold">Amount</label>
|
||||
{{ form.amount }}
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col">
|
||||
<label class="form-label text-muted small text-uppercase fw-bold">Type</label>
|
||||
{{ form.type }}
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label text-muted small text-uppercase fw-bold">Category</label>
|
||||
{{ form.category }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small text-uppercase fw-bold">Date</label>
|
||||
{{ form.date }}
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label text-muted small text-uppercase fw-bold">Description</label>
|
||||
{{ form.description }}
|
||||
</div>
|
||||
<div class="px-2">
|
||||
<button type="submit" class="btn btn-primary-gradient w-100 shadow">Save Transaction</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@ -1,25 +1,40 @@
|
||||
import os
|
||||
import platform
|
||||
|
||||
from django import get_version as django_version
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import render, redirect
|
||||
from django.db.models import Sum
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import Transaction, Category
|
||||
from .forms import TransactionForm
|
||||
import datetime
|
||||
|
||||
def home(request):
|
||||
"""Render the landing screen with loader and environment details."""
|
||||
host_name = request.get_host().lower()
|
||||
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
|
||||
now = timezone.now()
|
||||
|
||||
today = timezone.now().date()
|
||||
first_day_of_month = today.replace(day=1)
|
||||
|
||||
# Calculate stats
|
||||
total_income = Transaction.objects.filter(type='income').aggregate(Sum('amount'))['amount__sum'] or 0
|
||||
total_expense = Transaction.objects.filter(type='expense').aggregate(Sum('amount'))['amount__sum'] or 0
|
||||
balance = total_income - total_expense
|
||||
|
||||
monthly_income = Transaction.objects.filter(type='income', date__gte=first_day_of_month).aggregate(Sum('amount'))['amount__sum'] or 0
|
||||
monthly_expense = Transaction.objects.filter(type='expense', date__gte=first_day_of_month).aggregate(Sum('amount'))['amount__sum'] or 0
|
||||
|
||||
recent_transactions = Transaction.objects.select_related('category').order_by('-date', '-created_at')[:10]
|
||||
|
||||
if request.method == 'POST':
|
||||
form = TransactionForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect('home')
|
||||
else:
|
||||
form = TransactionForm()
|
||||
|
||||
context = {
|
||||
"project_name": "New Style",
|
||||
"agent_brand": agent_brand,
|
||||
"django_version": django_version(),
|
||||
"python_version": platform.python_version(),
|
||||
"current_time": now,
|
||||
"host_name": host_name,
|
||||
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
|
||||
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
|
||||
'total_income': total_income,
|
||||
'total_expense': total_expense,
|
||||
'balance': balance,
|
||||
'monthly_income': monthly_income,
|
||||
'monthly_expense': monthly_expense,
|
||||
'recent_transactions': recent_transactions,
|
||||
'form': form,
|
||||
'current_month': today.strftime('%B %Y'),
|
||||
}
|
||||
return render(request, "core/index.html", context)
|
||||
return render(request, 'core/index.html', context)
|
||||
@ -1,4 +1,86 @@
|
||||
/* Custom styles for the application */
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@600;700&display=swap');
|
||||
|
||||
:root {
|
||||
--bg-color: #F8FAFC;
|
||||
--slate-800: #1E293B;
|
||||
--slate-500: #64748B;
|
||||
--emerald: #10B981;
|
||||
--rose: #F43F5E;
|
||||
--indigo: #6366F1;
|
||||
--violet: #8B5CF6;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
font-family: 'Inter', sans-serif;
|
||||
color: var(--slate-800);
|
||||
}
|
||||
|
||||
h1, h2, h3, .h1, .h2, .h3 {
|
||||
font-family: 'Outfit', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hero-gradient {
|
||||
background: linear-gradient(135deg, var(--indigo) 0%, var(--violet) 100%);
|
||||
color: white;
|
||||
padding: 3rem 0;
|
||||
border-radius: 0 0 2rem 2rem;
|
||||
margin-bottom: -4rem;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 1.25rem;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.stats-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.income-text { color: var(--emerald); }
|
||||
.expense-text { color: var(--rose); }
|
||||
|
||||
.btn-primary-gradient {
|
||||
background: linear-gradient(135deg, var(--indigo) 0%, var(--violet) 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.btn-primary-gradient:hover {
|
||||
opacity: 0.9;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.transaction-row {
|
||||
border-left: 4px solid transparent;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.transaction-row.income { border-left-color: var(--emerald); }
|
||||
.transaction-row.expense { border-left-color: var(--rose); }
|
||||
|
||||
.table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0 0.5rem;
|
||||
}
|
||||
|
||||
.table tr {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.table td {
|
||||
padding: 1rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table td:first-child { border-radius: 0.75rem 0 0 0.75rem; }
|
||||
.table td:last-child { border-radius: 0 0.75rem 0.75rem 0; }
|
||||
@ -1,21 +1,86 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@600;700&display=swap');
|
||||
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
--bg-color: #F8FAFC;
|
||||
--slate-800: #1E293B;
|
||||
--slate-500: #64748B;
|
||||
--emerald: #10B981;
|
||||
--rose: #F43F5E;
|
||||
--indigo: #6366F1;
|
||||
--violet: #8B5CF6;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: var(--bg-color);
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
color: var(--slate-800);
|
||||
}
|
||||
|
||||
h1, h2, h3, .h1, .h2, .h3 {
|
||||
font-family: 'Outfit', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hero-gradient {
|
||||
background: linear-gradient(135deg, var(--indigo) 0%, var(--violet) 100%);
|
||||
color: white;
|
||||
padding: 3rem 0;
|
||||
border-radius: 0 0 2rem 2rem;
|
||||
margin-bottom: -4rem;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 1.25rem;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.stats-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.income-text { color: var(--emerald); }
|
||||
.expense-text { color: var(--rose); }
|
||||
|
||||
.btn-primary-gradient {
|
||||
background: linear-gradient(135deg, var(--indigo) 0%, var(--violet) 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.btn-primary-gradient:hover {
|
||||
opacity: 0.9;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.transaction-row {
|
||||
border-left: 4px solid transparent;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.transaction-row.income { border-left-color: var(--emerald); }
|
||||
.transaction-row.expense { border-left-color: var(--rose); }
|
||||
|
||||
.table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0 0.5rem;
|
||||
}
|
||||
|
||||
.table tr {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.table td {
|
||||
padding: 1rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table td:first-child { border-radius: 0.75rem 0 0 0.75rem; }
|
||||
.table td:last-child { border-radius: 0 0.75rem 0.75rem 0; }
|
||||
Loading…
x
Reference in New Issue
Block a user