Compare commits

..

No commits in common. 'cb5616c81f6c18c2f486bfcc074f1e547b7a66d0' and '9124e66e284bb88e67188109670cf561e83959ac' have entirely different histories.

4
.gitignore vendored

@ -1,9 +1,5 @@
/target /target
/resources
/.env /.env
/*.db /*.db
/*.db-shm /*.db-shm
/*.db-wal /*.db-wal
/node_modules
/*.lockb

@ -13,8 +13,5 @@
</option> </option>
<option name="myCustomValuesEnabled" value="true" /> <option name="myCustomValuesEnabled" value="true" />
</inspection_tool> </inspection_tool>
<inspection_tool class="RsUnusedImport" enabled="true" level="WARNING" enabled_by_default="true">
<option name="enableOnlyIfProcMacrosEnabled" value="false" />
</inspection_tool>
</profile> </profile>
</component> </component>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$" libraries="{alpinejs}" />
</component>
</project>

@ -1,3 +0,0 @@
{
"plugins": ["prettier-plugin-tailwindcss"]
}

@ -1,21 +0,0 @@
# inventory-app
## Prerequisites
1. Rust & Cargo
1. [bun.sh](https://bun.sh/)
## Setup
To install dependencies:
```bash
bun install
```
To run:
```bash
bun run index.ts
```

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@ -1,42 +0,0 @@
use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=templates");
println!("cargo:rerun-if-changed=assets");
println!("cargo:rerun-if-changed=tailwind.config.js");
std::fs::remove_dir_all("resources").unwrap_or_default();
Command::new("bun")
.args([
"run",
"tailwindcss",
"-c",
"tailwind.config.js",
"-i",
"assets/public/css/tailwind.css",
"-o",
"resources/main.css",
"--minify",
])
.status()
.expect("failed to run tailwindcss");
copy_files("assets/static");
}
fn copy_files(dir: &str) {
for entry in std::fs::read_dir(dir).expect("failed to read dir `public`") {
let entry = entry.expect("failed to read entry");
if entry.file_type().unwrap().is_dir() {
copy_files(entry.path().to_str().unwrap());
} else {
let path = entry.path();
let filename = path.file_name().unwrap().to_str().unwrap();
let dest = format!("resources/{}", filename);
std::fs::copy(path, dest).expect("failed to copy file");
}
}
}

@ -1,11 +0,0 @@
{
"name": "inventory-app",
"dependencies": {},
"devDependencies": {
"@types/bun": "latest",
"prettier": "^3.4.2",
"prettier-plugin-tailwindcss": "^0.6.11",
"tailwindcss": "^3.4.17"
},
"type": "module"
}

@ -4,7 +4,8 @@ use crate::app::routes::AppState;
pub fn routes() -> Router<AppState> { pub fn routes() -> Router<AppState> {
Router::new() Router::new()
.nest_service("/css/main.css", ServeFile::new("resources/main.css")) .nest_service("/css/pico.min.css", ServeFile::new("static/css/pico.min.css"))
.nest_service("/js/htmx.min.js", ServeFile::new("resources/htmx.min.js")) .nest_service("/css/custom.css", ServeFile::new("static/css/custom.css"))
.nest_service("/js/htmx.min.js", ServeFile::new("static/js/htmx.min.js"))
.nest_service("/favicon.ico", ServeFile::new("static/favicon.ico")) .nest_service("/favicon.ico", ServeFile::new("static/favicon.ico"))
} }

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

@ -1,19 +0,0 @@
export const content = ["./templates/**/*.html"]
export const theme = {
fontFamily: {
sans: ['Graphik', 'sans-serif'],
serif: ['Merriweather', 'serif'],
},
extend: {
colors: {
'space-cadet':'#1f2041ff',
'english-violet':'#4b3f72ff',
'sunglow':'#ffc857ff',
'dark-cyan':'#119da4ff',
'paynes-gray':'#19647eff',
'cerise': '#da4167ff',
'orchid-pink': '#f0bcd4ff'
}
},
plugins: [],
}

@ -1,6 +1,10 @@
{% extends "problem.html" %} {% block content %} {% extends "problem.html" %}
{% block content %}
<h1>Error</h1> <h1>Error</h1>
<p>Oops, something went wrong. Press the back button to try again.</p> <p>
Oops, something went wrong. Press the back button to try again.
</p>
{% endblock %} {% endblock %}

@ -1,50 +1,27 @@
{% extends "main.html" %} {% block title %} Items {% endblock %} {% block {% extends "main.html" %}
content %}
<div class="mx-auto mb-4 px-4"> {% block title %} Items {% endblock %}
<label
for="item-filter" {% block content %}
class="sr-only mb-2 text-sm font-medium text-gray-900 dark:text-white"
>Search</label <div class="container">
> <p class="container d-flex justify-content-center">
<div class="relative mb-4 max-w-56 content-center"> <input id="search" class="form-control"
<div type="search" name="q"
class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3" placeholder="Filter"
> aria-label="Search"
<svg value='{{ query.search.as_deref().unwrap_or("") }}'
class="h-4 w-4 text-gray-500 dark:text-gray-400" hx-get="/items"
aria-hidden="true" hx-trigger="search, keyup delay:500ms changed"
xmlns="http://www.w3.org/2000/svg" hx-target="#items"
fill="none" hx-push-url="true"
viewBox="0 0 20 20"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
/> />
</svg> </p>
<div id="items" class="container">
{% include "catalog_item_fragment.html" %}
</div> </div>
<input
id="item-filter"
class="block w-full rounded-lg border border-gray-300 bg-slate-100 p-4 ps-10 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:bg-neutral-900 dark:text-slate-100"
type="search"
name="q"
placeholder="Filter"
aria-label="Filter"
value='{{ query.search.as_deref().unwrap_or("") }}'
hx-get="/items"
hx-trigger="search, keyup delay:500ms changed"
hx-target="#items"
hx-push-url="true"
/>
</div>
<div id="items" class="container">
{% include "catalog_item_fragment.html" %}
</div>
</div> </div>
{% endblock %} {% endblock %}

@ -1,17 +1,11 @@
<div class="mx-auto"> <div class="card">
<div class="flex flex-col"> <ul class="list-group list-group-flush">
{% for item in items %} {% for item in items %}
<div class="mx-1 mb-4 flex flex-row"> <li id="item-{{item.id}}-entry" class="list-group-item">
<div class="basis-1/2"> <div class="row">
<a <div class="col-6"><a href="/item/{{item.id}}/" hx-push-url="true">{{ item.name }}</a></div>
class="font-medium text-paynes-gray hover:underline dark:text-paynes-gray"
href="/item/{{item.id}}/"
hx-push-url="true"
>
{{ item.name }}
</a>
</div> </div>
</div> </li>
{% endfor %} {% endfor %}
</div> </ul>
</div> </div>

@ -1,10 +1,11 @@
{% extends "problem.html" %} {% block content %} {% extends "problem.html" %}
{% block content %}
<h1>Forbidden</h1> <h1>Forbidden</h1>
<p> <p>
You are forbidden from accessing this resource. Please contact your supervisor You are forbidden from accessing this resource. Please contact your supervisor or <a href="/auth/logout">logout</a>
or <a href="/auth/logout">logout</a> and log back in with a different user.
and log back in with a different user.
</p> </p>
{% endblock %} {% endblock %}

@ -1,64 +1,38 @@
{% extends "main.html" %} {% block title %} Audit Log {% endblock %} {% block {% extends "main.html" %}
content %}
<h1 class="mb-4 text-4xl font-extrabold uppercase">Audit Log (Coming soon)</h1> {% block title %} Audit Log {% endblock %}
<section class="mb-4"> {% block content %}
<form
action="/history" <h1>Audit Log (Coming soon)</h1>
hx-get="/history"
hx-trigger="change" <section class="container mb-4">
hx-target="#items" <form action="/history" hx-get="/history" hx-trigger="change" hx-target="#items">
> <div class="row">
<div class="flex between"> <div class="col-sm-2">
<div class="px-2"> <label for="start-date" class="form-label">Start Date</label>
<label for="start-date" class="block">Start Date</label> <input type="date" id="start-date" name="start-date" value="{{ start_date }}" class="form-control" />
<input </div>
type="date" <div class="col-sm-2">
id="start-date" <label for="start-time" class="form-label">Start Time</label>
name="start-date" <input type="time" id="start-time" name="start-time" value="{{ start_time }}" class="form-control"/>
value="{{ start_date }}" <small class="form-text">Timezone {{ time_zone }}</small>
class="block" </div>
/> <div class="col-sm-2">
</div> <label for="end-date" class="form-label">End Date</label>
<div class="px-2"> <input type="date" id="end-date" name="end-date" value="{{ end_date }}" class="form-control"/>
<label for="start-time" class="block">Start Time</label> </div>
<input <div class="col-sm-2">
type="time" <label for="end-time" class="form-label">End Time</label>
id="start-time" <input type="time" id="end-time" name="end-time" value="{{ end_time }}" class="form-control"/>
name="start-time" <small class="form-text">Timezone {{ time_zone }}</small>
value="{{ start_time }}" </div>
class="block" </div>
/> </form>
<small class="block text-sm">Timezone {{ time_zone }}</small>
</div>
<div class="px-2">
<label for="end-date" class="block">End Date</label>
<input
type="date"
id="end-date"
name="end-date"
value="{{ end_date }}"
class="block"
/>
</div>
<div class="px-2">
<label for="end-time" class="form-label">End Time</label>
<input
type="time"
id="end-time"
name="end-time"
value="{{ end_time }}"
class="block"
/>
<small class="text-sm block">Timezone {{ time_zone }}</small>
</div>
</div>
</form>
</section> </section>
<section id="items" class="mb-4"> <section id="items" class="container">
{% include "history_item_fragment.html" %} {% include "history_item_fragment.html" %}
</section> </section>
{% endblock %} {% endblock %}

@ -1,29 +1,22 @@
<table class="table-auto">
<thead>
<tr class="mb-2">
<th>Date</th>
<th>Item</th>
<th>User</th>
<th>Desc</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr class="mb-2">
<td class="px-2">{{ item.create_date }}</td>
<td class="px-2">{{ item.item_name }}</td>
<td class="px-2">{{ item.user_name }}</td>
<td class="px-2">
{% match item.item_type %}
{% when HistoryItemEntry::PositiveAdjustment with (entry) %}
{{ entry.amount }} @ {{ entry.unit_value }}
{% when HistoryItemEntry::NegativeAdjustment with (entry) %}
{{ entry.amount }} {{ entry.reason }}
{% endmatch %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="card">
<ul class="list-group list-group-flush">
{% for item in items %}
<li class="list-group-item">
<div class="row">
<p class="col">{{ item.create_date }}</p>
<p class="col">{{ item.item_name }}</p>
<p class="col">{{ item.user_name }}</p>
<p class="col">
{% match item.item_type %}
{% when HistoryItemEntry::PositiveAdjustment with (entry) %}
{{ entry.amount }} @ {{ entry.unit_value }}
{% when HistoryItemEntry::NegativeAdjustment with (entry) %}
{{ entry.amount }} {{ entry.reason }}
{% endmatch %}
</p>
</div>
</li>
{% endfor %}
</ul>
</div>

@ -1,50 +1,27 @@
{% extends "main.html" %} {% block title %} Home {% endblock %} {% block content {% extends "main.html" %}
%}
<div class="mx-auto mb-4 px-4"> {% block title %} Home {% endblock %}
<label
for="default-search" {% block content %}
class="sr-only mb-2 text-sm font-medium text-gray-900 dark:text-white"
>Search</label <div class="container">
> <p class="container d-flex justify-content-center">
<div class="relative mb-4 max-w-56 content-center"> <input id="search"
<div class="form-control"
class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3" type="search" name="q"
> placeholder="Search"
<svg aria-label="Search"
class="h-4 w-4 text-gray-500 dark:text-gray-400" value='{{ query.search.as_deref().unwrap_or("") }}'
aria-hidden="true" hx-get="/home/search"
xmlns="http://www.w3.org/2000/svg" hx-trigger="search, keyup delay:500ms changed"
fill="none" hx-target="#items"
viewBox="0 0 20 20" hx-push-url="true"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
/> />
</svg> </p>
</div>
<input
id="default-search"
class="block w-full rounded-lg border border-gray-300 bg-slate-100 p-4 ps-10 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:bg-neutral-900 dark:text-slate-100"
type="search"
name="q"
placeholder="Search"
aria-label="Search"
value='{{ query.search.as_deref().unwrap_or("") }}'
hx-get="/home/search"
hx-trigger="search, keyup delay:500ms changed"
hx-target="#items"
hx-push-url="true"
/>
</div>
<div id="items" class="container"> <div id="items" class="container">
{% include "home_search_item_fragment.html" %} {% include "home_search_item_fragment.html" %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

@ -1,29 +1,16 @@
{% if items.len() > 0 %} {% if items.len() > 0 %}
<div class="mx-auto"> <div class="card">
<div class="flex flex-col"> <ul class="list-group list-group-flush">
{% for item in items %} {% for item in items %}
<div class="mx-1 mb-4 flex flex-row"> <li id="item-{{item.id}}-entry" class="list-group-item">
<div class="basis-1/2"> <div class="row">
<a <div class="col-6"><a href="/item/{{item.id}}/" hx-push-url="true">{{ item.name }}</a></div>
class="font-medium text-paynes-gray hover:underline dark:text-paynes-gray" <div class="col">Count: <span id="item-{{item.id}}-count" hx-get="/item/{{item.id}}/count" hx-trigger="load">0</span></div>
href="/item/{{item.id}}/" <div class="col">Reorder Point: {{ item.reorder_point }}</div>
hx-push-url="true"
>
{{ item.name }}
</a>
</div>
<div class="basis-1/4">
Count:
<span
id="item-{{item.id}}-count"
hx-get="/item/{{item.id}}/count"
hx-trigger="load"
>0</span
>
</div>
<div class="basis-1/4">Reorder Point: {{ item.reorder_point }}</div>
</div> </div>
{% endfor %} </li>
</div> {% endfor %}
</ul>
</div> </div>
{% endif %} {% endif %}

@ -1,31 +1,25 @@
<table
class="w-full text-left text-sm rtl:text-right" <table class="table" hx-get="/item/{{item_id}}/adjustments" hx-trigger="new-adjustment from:body" hx-swap="outerHTML">
hx-get="/item/{{item_id}}/adjustments" <thead>
hx-trigger="new-adjustment from:body"
hx-swap="outerHTML"
>
<thead
class="bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-400"
>
<tr> <tr>
<th class="px-6 py-3" scope="col">Date</th> <th scope="col">Date</th>
<th class="px-6 py-3" scope="col">Amount</th> <th scope="col">Amount</th>
<th class="px-6 py-3" scope="col">Reason</th> <th scope="col">Reason</th>
<th class="px-6 py-3" scope="col">Unit Value</th> <th scope="col">Unit Value</th>
<th class="px-6 py-3" scope="col">Running Total</th> <th scope="col">Running Total</th>
<th class="px-6 py-3" scope="col">Running Value</th> <th scope="col">Running Value</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in adjustments %} {% for item in adjustments %}
<tr> <tr>
<td class="px-6 py-4">{{ item.date }}</td> <td>{{ item.date }}</td>
<td class="px-6 py-4">{{ item.amount }}</td> <td>{{ item.amount }}</td>
<td class="px-6 py-4">{{ item.reason }}</td> <td>{{ item.reason }}</td>
<td class="px-6 py-4">{{ item.unit_value }}</td> <td>{{ item.unit_value }}</td>
<td class="px-6 py-4">{{ item.tally }}</td> <td>{{ item.tally }}</td>
<td class="px-6 py-4">{{ item.tally_value }}</td> <td>{{ item.tally_value }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>

@ -1,119 +1,65 @@
<form <form hx-post="/item/{{item_id}}/adjustment/negative"
hx-post="/item/{{item_id}}/adjustment/negative" hx-target="this" hx-swap="outerHTML"
hx-target="this" x-ref="formNegativeAdjustment"
hx-swap="outerHTML" x-data="{ reason: 'Sale' }">
x-ref="formNegativeAdjustment" <input id="reason" name="reason" type="hidden" x-model="reason"/>
x-data="{ reason: 'Sale', reason_dropdown_show: false }" <div class="row">
> <div class="col">
<div class="mb-5"> <!--<label for="amount" class="form-label">Amount</label>-->
<label for="amount" class="mb-2 block text-sm font-medium">Amount</label> <input type="number"
<input id="amount"
type="number" name="amount"
id="amount" step="0.01"
name="amount" class="form-control"
step="0.01" placeholder="Amount"
class="block max-w-56 rounded-lg border border-neutral-900 p-2.5 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:text-slate-100" aria-label="amount"
placeholder="Amount" required
aria-label="amount" {% if !amount_error.is_empty() -%}
required aria-invalid="true"
{% aria-describedby="invalid-amount"
if {% endif -%}
!amount_error.is_empty() />
-%} {% if !amount_error.is_empty() -%}
aria-invalid="true" <small id="invalid-amount" class="invalid-feedback">{{ amount_error }}</small>
aria-describedby="invalid-amount" {% endif -%}
{% </div>
endif <div class="col">
-%} <button class="btn btn-primary" x-text="reason">Sale</button>
/>
{% if !amount_error.is_empty() -%} </div>
<small id="invalid-amount" class="mt-2 text-sm text-cerise"> <div class="col">
{{ amount_error }} <div class="dropdown">
</small> <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown"
{% endif -%} aria-expanded="false">
</div> <span class="visually-hidden">Other</span>
<div class="mb-5 flex justify-start"> </button>
<button <ul class="dropdown-menu">
class="rounded-l-lg bg-english-violet px-5 py-2.5 text-sm font-medium text-slate-100 hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan" <li>
x-text="reason" <a class="dropdown-item"
> @click="reason = 'Sale'">
Sale Sale
</button> </a>
<div </li>
x-data="{ isOpen: false, openedWithKeyboard: false }" <li>
class="relative w-fit" <a class="dropdown-item"
x-on:keydown.esc.window="isOpen = false; openedWithKeyboard = false" @click="reason = 'Destruction'">
> Destruction
<button </a>
type="button" </li>
x-on:click="isOpen = ! isOpen" <li>
class="rounded-radius inline-flex items-center whitespace-nowrap rounded-r-lg border-l-2 border-slate-100 bg-english-violet px-3.5 py-3.5 text-sm font-medium tracking-wide text-slate-100 transition hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan dark:border-neutral-900" <a class="dropdown-item"
aria-haspopup="true" @click="reason = 'Expiration'">
x-on:keydown.space.prevent="openedWithKeyboard = true" Expiration
x-on:keydown.enter.prevent="openedWithKeyboard = true" </a>
x-on:keydown.down.prevent="openedWithKeyboard = true" </li>
x-bind:class="isOpen || openedWithKeyboard ? 'text-on-surface-strong dark:text-on-surface-dark-strong' : 'text-on-surface dark:text-on-surface-dark'" <li>
x-bind:aria-expanded="isOpen || openedWithKeyboard" <a class="dropdown-item"
> @click="reason = 'Theft'">
<span class="sr-only">Reason Options</span> Theft
<svg </a>
aria-hidden="true" </li>
fill="none" </ul>
xmlns="http://www.w3.org/2000/svg" </div>
viewBox="0 0 24 24" </div>
stroke-width="2"
stroke="currentColor"
class="size-4 rotate-0"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M19.5 8.25l-7.5 7.5-7.5-7.5"
/>
</svg>
</button>
<!-- Dropdown Menu -->
<div
x-cloak
x-show="isOpen || openedWithKeyboard"
x-transition
x-trap="openedWithKeyboard"
x-on:click.outside="isOpen = false, openedWithKeyboard = false"
x-on:keydown.down.prevent="$focus.wrap().next()"
x-on:keydown.up.prevent="$focus.wrap().previous()"
class="rounded-radius border-outline absolute left-0 top-11 flex w-fit min-w-48 flex-col overflow-hidden border border-neutral-900 bg-slate-100 dark:border-slate-100 dark:bg-neutral-900"
role="menu"
>
<a
class="focus-visible:outline-hidden px-4 py-2 text-sm hover:bg-dark-cyan hover:font-semibold focus-visible:bg-dark-cyan focus-visible:font-semibold"
role="menuitem"
@click="reason = 'Sale'; isOpen = false"
>
Sale
</a>
<a
class="focus-visible:outline-hidden px-4 py-2 text-sm hover:bg-dark-cyan hover:font-semibold focus-visible:bg-dark-cyan focus-visible:font-semibold"
role="menuitem"
@click="reason = 'Destruction'; isOpen = false"
>
Destruction
</a>
<a
class="focus-visible:outline-hidden px-4 py-2 text-sm hover:bg-dark-cyan hover:font-semibold focus-visible:bg-dark-cyan focus-visible:font-semibold"
role="menuitem"
@click="reason = 'Expiration'; isOpen = false"
>
Expiration
</a>
<a
class="focus-visible:outline-hidden px-4 py-2 text-sm hover:bg-dark-cyan hover:font-semibold focus-visible:bg-dark-cyan focus-visible:font-semibold"
role="menuitem"
@click="reason = 'Theft'; isOpen = false"
>
Theft
</a>
</div>
</div> </div>
</div>
<input id="reason" name="reason" type="hidden" x-model="reason" />
</form> </form>

@ -1,66 +1,43 @@
<form
hx-post="/item/{{item_id}}/adjustment/positive" <form hx-post="/item/{{item_id}}/adjustment/positive" hx-target="this" hx-swap="outerHTML" >
hx-target="this" <div class="row">
hx-swap="outerHTML" <div class="col">
> <input type="number"
<div class="mb-5"> id="amount"
<label for="amount" class="mb-2 block text-sm font-medium">Amount</label> name="amount"
<input step="0.01"
type="number" class="form-control"
id="amount" placeholder="Amount"
name="amount" aria-label="amount"
class="block max-w-56 rounded-lg border border-neutral-900 p-2.5 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:text-slate-100" required
step="0.01" {% if !amount_error.is_empty() -%}
placeholder="Amount" aria-invalid="true"
aria-label="amount" aria-describedby="invalid-amount"
required {% endif -%}
{% />
if {% if !amount_error.is_empty() -%}
!amount_error.is_empty() <small id="invalid-amount" class="invalid-feedback">{{ amount_error }}</small>
-%} {% endif -%}
aria-invalid="true" </div>
aria-describedby="invalid-amount" <div class="col">
{% <input type="text"
endif id="price"
-%} name="price"
/> placeholder="Price"
{% if !amount_error.is_empty() -%} class="form-control"
<small id="invalid-amount" class="mt-2 text-sm text-cerise"> aria-label="price"
{{ amount_error }} required
</small> {% if !price_error.is_empty() -%}
{% endif -%} aria-invalid="true"
</div> aria-describedby="invalid-price"
<div class="mb-5"> {% endif -%}
<label for="price" class="mb-2 block text-sm font-medium">Price</label> />
<input {% if !price_error.is_empty() -%}
type="text" <small id="invalid-price" class="invalid-feedback">{{ price_error }}</small>
id="price" {% endif -%}
name="price" </div>
class="block max-w-56 rounded-lg border border-neutral-900 p-2.5 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:text-slate-100" <div class="col">
placeholder="Price" <button class="btn btn-primary">Add</button>
aria-label="price" </div>
required </div>
{%
if
!price_error.is_empty()
-%}
aria-invalid="true"
aria-describedby="invalid-price"
{%
endif
-%}
/>
{% if !price_error.is_empty() -%}
<small id="invalid-price" class="mt-2 text-sm text-cerise"
>{{ price_error }}</small
>
{% endif -%}
</div>
<div class="mb-5">
<button
class="mb-2 me-2 rounded-lg bg-english-violet px-5 py-2.5 text-sm font-medium text-slate-100 hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan"
>
Add
</button>
</div>
</form> </form>

@ -1,66 +1,53 @@
{% extends "main.html" %} {% block title %} Items {% endblock %} {% block {% extends "main.html" %}
content %}
<h2 class="mb-4 flex items-center text-4xl font-extrabold"> {% block title %} Items {% endblock %}
{{item.name}} {% if !item.active %}
<span
class="me-2 ms-2 rounded border border-cerise bg-orchid-pink px-2.5 py-0.5 text-2xl font-semibold text-cerise"
>
Inactive
</span>
{% endif %}
</h2>
<section {% block content %}
hx-get="/item/{{item_id}}/stats"
hx-trigger="load" <div class="container mb-5">
hx-swap="outerHTML" <h2>{{item.name}} {% if !item.active %}<span class="badge text-bg-danger">Inactive</span> {% endif %}</h2>
></section> </div>
<section class="container">
<div hx-get="/item/{{item_id}}/stats" hx-trigger="load" hx-swap="outerHTML">
</div>
</section>
{% if item.active %} {% if item.active %}
<section <section class="container-fluid">
class="mx-auto mb-5"
x-data="{ negative_form_open: false, positive_form_open: false }"
>
<div class="flex justify-evenly">
<button
class="mb-2 me-2 rounded-lg bg-paynes-gray px-5 py-2.5 text-sm font-medium text-slate-100 hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan"
@click="negative_form_open = ! negative_form_open"
>
Minus
</button>
<button
class="mb-2 me-2 rounded-lg bg-paynes-gray px-5 py-2.5 text-sm font-medium text-slate-100 hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan"
@click="positive_form_open = ! positive_form_open"
>
Plus
</button>
</div>
<div x-show="negative_form_open" @click.outside="negative_form_open = false"> <div x-data="{ open: false }" class="mb-3">
<div <div class="d-flex justify-content-start">
hx-get="/item/{{item_id}}/adjustment/negative" <div class="me-3">
hx-trigger="load" <button class="btn btn-primary display-6" @click="open = ! open">
hx-swap="outerHTML" Minus
></div> </button>
</div> </div>
<div x-show="open" @click.outside="open = false">
<div hx-get="/item/{{item_id}}/adjustment/negative" hx-trigger="load" hx-swap="outerHTML"></div>
</div>
</div>
</div>
<div x-show="positive_form_open" @click.outside="positive_form_open = false"> <div x-data="{ open: false }" class="mb-3">
<div <div class="d-flex justify-content-start">
hx-get="/item/{{item_id}}/adjustment/positive" <div class="me-3">
hx-trigger="load" <button class="btn btn-primary" @click="open = ! open">
hx-swap="outerHTML" Plus
></div> </button>
</div> </div>
<div x-show="open" @click.outside="open = false">
<div hx-get="/item/{{item_id}}/adjustment/positive" hx-trigger="load" hx-swap="outerHTML">
</div>
</div>
</div>
</div>
</section> </section>
{% endif %} {% endif %}
<section class="mx-auto"> <section class="container">
<div <div hx-get="/item/{{item_id}}/adjustments" hx-trigger="load" hx-swap="outerHTML">
hx-get="/item/{{item_id}}/adjustments" </div>
hx-trigger="load"
hx-swap="outerHTML"
></div>
</section> </section>
{% endblock %} {% endblock %}

@ -1,25 +1,36 @@
<section
hx-get="/item/{{item_id}}/stats" <section hx-get="/item/{{item_id}}/stats" hx-trigger="new-adjustment from:body" hx-swap="outerHTML" class="mb-4">
hx-trigger="new-adjustment from:body" <div class="row">
hx-swap="outerHTML" <div class="col-md-3">
class="mb-4" <div class="card text-center mb-1">
> <div class="card-header">
<div class="flex justify-start"> <p class="text-bolder text-uppercase">Stock</p>
<div class="me-4 rounded border border-space-cadet px-4 py-4"> </div>
<p class="text-center text-xl uppercase">Stock</p> <div class="card-body">
<p class="text-center text-xl"> <p class="display-6">{{item.amount}} {{item.display_unit_short}}</p>
{{item.amount}} {{item.display_unit_short}} </div>
</p> </div>
</div>
<div class="col-md-3">
<div class="card text-center mb-1">
<div class="card-header">
<p class="text-bolder text-uppercase">Reorder Point</p>
</div>
<div class="card-body">
<p class="display-6">{{item.reorder_point}} {{item.display_unit_short}}</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center mb-1">
<div class="card-header">
<p class="text-bolder text-uppercase">Value</p>
</div>
<div class="card-body">
<p class="display-6">{{value}}</p>
</div>
</div>
</div>
</div> </div>
<div class="me-4 rounded border border-space-cadet px-4 py-4">
<p class="text-center text-xl uppercase">Reorder</p>
<p class="text-center text-xl">
{{item.reorder_point}} {{item.display_unit_short}}
</p>
</div>
<div class="me-4 rounded border border-space-cadet px-4 py-4">
<p class="text-center text-xl uppercase">Value</p>
<p class="text-center text-xl">{{value}}</p>
</div>
</div>
</section> </section>

@ -1,7 +1,9 @@
{% extends "main.html" %} {% block content %} {% extends "main.html" %}
{% block content %}
<h1>Logged out</h1> <h1>Logged out</h1>
<p>You have been logged out</p> <p>You have been logged out</p>
<p><a href="/auth/login">Log In</a></p> <p><a href="/auth/login">Log In</a></p>
{% endblock %} {% endblock %}

@ -1,83 +1,53 @@
<!doctype html> <!DOCTYPE html>
<html lang="en"> <html lang="en" data-bs-theme="dark">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark" /> <meta name="color-scheme" content="light dark">
<link rel="stylesheet" href="/css/main.css" /> <!-- <link rel="stylesheet" href="/css/pico.min.css" > -->
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1">
<!--TODO Vendor css-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="/js/htmx.min.js"></script> <script src="/js/htmx.min.js"></script>
<!--TODO Vendor this script --> <!--TODO Vendor this script -->
<script <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
defer <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"
></script>
<title>{% block title %}Title{% endblock %}</title> <title>{% block title %}Title{% endblock %}</title>
</head> </head>
<body <body>
class="min-h-screen bg-slate-100 text-neutral-900 dark:bg-neutral-900 dark:text-slate-100" <header class="container mb-4">
> <nav class="navbar navbar-expand-lg bg-body-tertiary">
<header class="top-0 w-full mb-4 bg-space-cadet font-sans"> <div class="container-fluid">
<nav <a class="navbar-brand" href="/home">Inventory App</a>
class="mx-auto flex max-w-7xl justify-between gap-2 px-2 py-4 sm:px-6 lg:px-8" <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
> <span class="navbar-toggler-icon"></span>
<div> </button>
<a <div class="collapse navbar-collapse justify-content-end" id="navbarNav">
href="/home" <ul class="navbar-nav ">
class="rounded-md bg-english-violet px-3 py-2 text-sm font-medium text-white" <li class="nav-item"><h1></h1></li>
> <li class="nav-item"><a class="nav-link" href="/overview">Overview</a></li>
Inventory App <li class="nav-item"><a class="nav-link" href="/catalog">Catalog</a></li>
</a> <li class="nav-item"><a class="nav-link" href="/upload">Upload</a></li>
<li class="nav-item"><a class="nav-link" href="/reports">Reports</a></li>
<li class="nav-item"><a class="nav-link" href="/history">History</a></li>
</ul>
<div class="d-flex">
<a class="btn btn-primary" href="/auth/logout">Logout</a>
</div>
</div>
</div> </div>
<div> </nav>
<a </header>
href="/overview" <main class="container">
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white" {% block content %}<p>Content Missing</p>{% endblock %}
> </main>
Overview <footer class="container-fluid">
</a>
<a
href="/catalog"
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
>
Catalog
</a>
<a
href="/upload"
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
>
Upload
</a>
<a
href="/reports"
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
>
Reports
</a>
<a
href="/history"
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
>
History
</a>
</div>
</nav>
</header>
<main
class="relative mx-auto max-w-[68.75rem] w-[95vw] bg-slate-100 px-1 text-neutral-900 dark:bg-neutral-900 dark:text-slate-100"
>
{% block content %}
<p>Content Missing</p>
{% endblock %}
</main>
<footer>
<!--
<script> <script>
// Needed for nice bootstrap dropdowns // Needed for nice bootstrap dropdowns
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="dropdown"]'); const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="dropdown"]');
const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl)) const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl))
</script> </script>
--></footer> </footer>
</body> </body>
</html> </html>

@ -1,10 +1,11 @@
{% extends "problem.html" %} {% block content %} {% extends "problem.html" %}
{% block content %}
<h1>Not Found</h1> <h1>Not Found</h1>
<p> <p>
Sorry, we can't seem to find the page you're looking for. Please press back Sorry, we can't seem to find the page you're looking for. Please press back button or return
button or return <a href="/">home</a>.
<a href="/">home</a>.
</p> </p>
{% endblock %} {% endblock %}

@ -1,6 +1,9 @@
{% extends "main.html" %} {% block title %} Overview {% endblock %} {% block {% extends "main.html" %}
content %}
{% block title %} Overview {% endblock %}
{% block content %}
<h1>Overview (Coming soon)</h1> <h1>Overview (Coming soon)</h1>
{% endblock %} {% endblock %}

@ -1,18 +1,16 @@
<!doctype html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark" /> <meta name="color-scheme" content="light dark">
<link rel="stylesheet" href="/css/pico.min.css" /> <link rel="stylesheet" href="/css/pico.min.css">
<script src="/js/htmx.min.js"></script> <script src="/js/htmx.min.js"></script>
<title>Problem</title> <title>Problem</title>
</head> </head>
<body> <body>
<main class="container"> <main class="container">
{% block content %} {% block content %}<p>Something went wrong</p>{% endblock %}
<p>Something went wrong</p> </main>
{% endblock %} </body>
</main> </html>
</body>
</html>

@ -1,6 +1,9 @@
{% extends "main.html" %} {% block title %} Reports {% endblock %} {% block {% extends "main.html" %}
content %}
{% block title %} Reports {% endblock %}
{% block content %}
<h1>Reports (Coming soon)</h1> <h1>Reports (Coming soon)</h1>
{% endblock %} {% endblock %}

@ -1,27 +1,19 @@
{% extends "main.html" %} {% block title %} Upload {% endblock %} {% block {% extends "main.html" %}
content %}
<form {% block title %} Upload {% endblock %}
action="/upload/catalog"
method="post" {% block content %}
enctype="multipart/form-data"
x-data="{ file: '' }" <form action="/upload/catalog" method="post" enctype="multipart/form-data" x-data="{ file: '' }">
> <fieldset class="grid">
<fieldset class="grid"> <h3>Catalog Import</h3>
<h3>Catalog Import</h3> <label role="button" class="secondary" x-show="!file">
<label role="button" class="secondary" x-show="!file"> Choose File
Choose File <input type="file" name="file" x-model="file" style="display: none" required />
<input </label>
type="file" <input type="submit" value="Upload" x-show="file">
name="file" <input type="reset" value="Cancel" x-show="file">
x-model="file" </fieldset>
style="display: none"
required
/>
</label>
<input type="submit" value="Upload" x-show="file" />
<input type="reset" value="Cancel" x-show="file" />
</fieldset>
</form> </form>
{% endblock %} {% endblock %}
Loading…
Cancel
Save

Powered by TurnKey Linux.