From 4ffc68d5f25b7d2648aa058e1029f090fdca9907 Mon Sep 17 00:00:00 2001 From: candifloss <candifloss@candifloss.cc> Date: Thu, 3 Apr 2025 11:33:57 +0530 Subject: [PATCH] Add: Branding config - App name - Tagline - Large Logo (for Login page) - Small Logo (for header) --- config.sample.py | 10 +++++++++- routes/create.py | 11 ++++++----- routes/delete.py | 4 +++- routes/homepage.py | 3 ++- routes/update.py | 11 ++++++----- routes/upload.py | 7 +++++-- routes/viewall.py | 4 +++- static/images/logo_large.png | Bin 0 -> 4863 bytes static/images/logo_small.png | Bin 0 -> 8975 bytes templates/header.html | 7 ++++++- templates/login.html | 10 ++++++---- 11 files changed, 46 insertions(+), 21 deletions(-) create mode 100644 static/images/logo_large.png create mode 100644 static/images/logo_small.png diff --git a/config.sample.py b/config.sample.py index fcbcf6f..b13cf30 100644 --- a/config.sample.py +++ b/config.sample.py @@ -1,6 +1,14 @@ from definitions.attributes import * - +# Branding Configuration +class BrandingConfig: + APP_NAME = "Inventory Manager" + TAGLINE = "Inventory management system" + + # Logo paths (relative to static folder) + LOGIN_LOGO = "images/logo_large.png" # ~400x200px recommended + HEADER_LOGO = "images/logo_small.png" # ~100x50px recommended + # MySQL information class sql_conf: SQL_USER = "assetadmin" diff --git a/routes/create.py b/routes/create.py index e939956..21fab5f 100644 --- a/routes/create.py +++ b/routes/create.py @@ -4,6 +4,7 @@ from config import item_attributes from sqlalchemy import exc # Import exc for database exceptions from functions.validate_values import validate_values # Form validation from functions.auth import login_required +from config import BrandingConfig addasset_bp = Blueprint('addasset', __name__) @@ -12,7 +13,7 @@ addasset_bp = Blueprint('addasset', __name__) def create(): if request.method == 'GET': # Render the "add item" form - return render_template('item_form.html', item_attributes=item_attributes, item=None) + return render_template('item_form.html', item_attributes=item_attributes, item=None, brandingconfig=BrandingConfig) # Process submitted form if request.method == 'POST': @@ -22,7 +23,7 @@ def create(): # Form validation error = validate_values(form_data) if error: - return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error) + return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error, brandingconfig=BrandingConfig) # Create the Asset object item = Asset(**form_data) @@ -37,15 +38,15 @@ def create(): error = f"An entry with {primary_attrib.display_name} '{form_data[primary_attrib.attrib_name]}' already exists." else: error = "An entry with the same primary key already exists." - return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error) + return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error, brandingconfig=BrandingConfig) except exc.StatementError as e: # Handle other database errors error = f"Database error: {str(e)}" - return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error) + return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error, brandingconfig=BrandingConfig) except Exception as e: # Handle unexpected errors error = f"An unexpected error occurred: {str(e)}" - return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error) + return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error, brandingconfig=BrandingConfig) # Redirect to /viewall on success return redirect('/viewall') \ No newline at end of file diff --git a/routes/delete.py b/routes/delete.py index 374d022..fc8404d 100644 --- a/routes/delete.py +++ b/routes/delete.py @@ -2,6 +2,7 @@ from flask import Blueprint, request, render_template, redirect, flash from definitions.models import Asset, db from config import item_attributes from functions.auth import login_required +from config import BrandingConfig delete_bp = Blueprint('deleteasset', __name__) @@ -34,5 +35,6 @@ def delete(primary_value): return render_template( 'delete.html', item=item, - item_attributes=item_attributes + item_attributes=item_attributes, + brandingconfig=BrandingConfig ) \ No newline at end of file diff --git a/routes/homepage.py b/routes/homepage.py index fb89d01..d258f9a 100644 --- a/routes/homepage.py +++ b/routes/homepage.py @@ -1,5 +1,6 @@ from flask import Blueprint, render_template, redirect, url_for, session, request, flash from definitions.models import db, User +from config import BrandingConfig homepage_bp = Blueprint('homepage', __name__) @@ -31,7 +32,7 @@ def login(): else: flash('Invalid username or password', 'error') - return render_template('login.html') + return render_template('login.html', brandingconfig=BrandingConfig) @homepage_bp.route('/logout/') def logout(): diff --git a/routes/update.py b/routes/update.py index b41b3e6..bd04e59 100644 --- a/routes/update.py +++ b/routes/update.py @@ -4,6 +4,7 @@ from config import item_attributes from sqlalchemy import exc # Import exc for database exceptions from functions.validate_values import validate_values # Form validation from functions.auth import login_required +from config import BrandingConfig update_bp = Blueprint('editasset', __name__) @@ -22,7 +23,7 @@ def update(primary_value): if request.method == 'GET': # Render the update form with the current item data - return render_template('item_form.html', item=item, item_attributes=item_attributes) + return render_template('item_form.html', item=item, item_attributes=item_attributes, brandingconfig=BrandingConfig) if request.method == 'POST': # Get data from form @@ -31,7 +32,7 @@ def update(primary_value): # Form validation error = validate_values(form_data) if error: - return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error) + return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error, brandingconfig=BrandingConfig) # Update the item with the new data for attrib in item_attributes: @@ -42,15 +43,15 @@ def update(primary_value): except exc.IntegrityError: # Handle duplicate primary key or unique constraint errors error = f"An entry with {primary_attrib.display_name} '{form_data[primary_attrib.attrib_name]}' already exists." - return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error) + return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error, brandingconfig=BrandingConfig) except exc.StatementError as e: # Handle other database errors error = f"Database error: {str(e)}" - return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error) + return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error, brandingconfig=BrandingConfig) except Exception as e: # Handle unexpected errors error = f"An unexpected error occurred: {str(e)}" - return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error) + return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error, brandingconfig=BrandingConfig) # Redirect to /viewall on success return redirect('/viewall') \ No newline at end of file diff --git a/routes/upload.py b/routes/upload.py index a60929f..dd9416f 100644 --- a/routes/upload.py +++ b/routes/upload.py @@ -4,6 +4,7 @@ from functions.process_csv import get_csv_data from functions.validate_values import validate_values from config import item_attributes from functions.auth import login_required +from config import BrandingConfig upload_bp = Blueprint('uploadcsv', __name__) @@ -89,7 +90,8 @@ def import_from_csv(): mode='import', new_entries=result['new_entries'], invalid_entries=result['invalid_entries'], - item_attributes=item_attributes + item_attributes=item_attributes, + brandingconfig=BrandingConfig ) # Render the upload page for GET requests @@ -129,7 +131,8 @@ def edit_using_csv(): mode='edit', existing_entries=result['existing_entries'], invalid_entries=result['invalid_entries'], - item_attributes=item_attributes + item_attributes=item_attributes, + brandingconfig=BrandingConfig ) # Render the upload page for GET requests diff --git a/routes/viewall.py b/routes/viewall.py index 9f97a39..5477110 100644 --- a/routes/viewall.py +++ b/routes/viewall.py @@ -2,6 +2,7 @@ from flask import Blueprint, render_template from definitions.models import Asset from config import item_attributes from functions.auth import login_required +from config import BrandingConfig viewall_bp = Blueprint('viewall', __name__) @@ -21,5 +22,6 @@ def view_list(): 'viewList.html', items=items, item_attributes=item_attributes, - primary_attrib=primary_attrib.attrib_name + primary_attrib=primary_attrib.attrib_name, + brandingconfig=BrandingConfig ) \ No newline at end of file diff --git a/static/images/logo_large.png b/static/images/logo_large.png new file mode 100644 index 0000000000000000000000000000000000000000..a513dda08d1e3ec732012db657b89b6a29c48bd2 GIT binary patch literal 4863 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 literal 0 HcmV?d00001 diff --git a/static/images/logo_small.png b/static/images/logo_small.png new file mode 100644 index 0000000000000000000000000000000000000000..d8dd1376b2ae55e9efc5019803eee92c7b4978a2 GIT binary patch literal 8975 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®Lip7t}E_ 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 literal 0 HcmV?d00001 diff --git a/templates/header.html b/templates/header.html index 29f2c22..f9e006a 100644 --- a/templates/header.html +++ b/templates/header.html @@ -1,6 +1,11 @@ <!-- Header bar --> <div class="header"> - <h1 class="appname">Inventory Manager</h1> + <div class="branding"> + <img src="{{ url_for('static', filename=brandingconfig.HEADER_LOGO) }}" + alt="{{ brandingconfig.APP_NAME }} Logo" + class="header-logo"> + <h1 class="appname">{{ brandingconfig.APP_NAME }}</h1> + </div> <div class="buttons"> <form action="/create" method="get"> <button type="submit">Add New Item</button> diff --git a/templates/login.html b/templates/login.html index 2af868c..f3c0369 100644 --- a/templates/login.html +++ b/templates/login.html @@ -3,14 +3,16 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Login Page</title> + <title>{{ brandingconfig.APP_NAME }} - Login</title> </head> <body> <div class="left-container"> - <img src="../images/logo2.png" alt="Company Logo" class="logo"> - <h1>Inventory Manager</h1> - <p>Inventory management system</p> + <img src="{{ url_for('static', filename=brandingconfig.LOGIN_LOGO) }}" + alt="{{ brandingconfig.APP_NAME }} Logo" + class="logo"> + <h1>{{ brandingconfig.APP_NAME }}</h1> + <p>{{ brandingconfig.TAGLINE }}</p> </div> {% with messages = get_flashed_messages(with_categories=true) %}