Compare commits

..

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

4
.gitignore vendored

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

@ -13,8 +13,5 @@
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
<inspection_tool class="RsUnusedImport" enabled="true" level="WARNING" enabled_by_default="true">
<option name="enableOnlyIfProcMacrosEnabled" value="false" />
</inspection_tool>
</profile>
</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> {
Router::new()
.nest_service("/css/main.css", ServeFile::new("resources/main.css"))
.nest_service("/js/htmx.min.js", ServeFile::new("resources/htmx.min.js"))
.nest_service("/css/pico.min.css", ServeFile::new("static/css/pico.min.css"))
.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"))
}

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>
<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 %}

@ -1,50 +1,27 @@
{% extends "main.html" %} {% block title %} Items {% endblock %} {% block
content %}
{% extends "main.html" %}
<div class="mx-auto mb-4 px-4">
<label
for="item-filter"
class="sr-only mb-2 text-sm font-medium text-gray-900 dark:text-white"
>Search</label
>
<div class="relative mb-4 max-w-56 content-center">
<div
class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3"
>
<svg
class="h-4 w-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
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>
</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"
{% block title %} Items {% endblock %}
{% block content %}
<div class="container">
<p class="container d-flex justify-content-center">
<input id="search" class="form-control"
type="search" name="q"
placeholder="Filter"
aria-label="Filter"
aria-label="Search"
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>
</p>
<div id="items" class="container">
{% include "catalog_item_fragment.html" %}
</div>
</div>
{% endblock %}

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

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

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

@ -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>
<div class="card">
<ul class="list-group list-group-flush">
{% 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">
<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 %}
</td>
</tr>
</p>
</div>
</li>
{% endfor %}
</tbody>
</table>
</ul>
</div>

@ -1,37 +1,14 @@
{% extends "main.html" %} {% block title %} Home {% endblock %} {% block content
%}
{% extends "main.html" %}
<div class="mx-auto mb-4 px-4">
<label
for="default-search"
class="sr-only mb-2 text-sm font-medium text-gray-900 dark:text-white"
>Search</label
>
<div class="relative mb-4 max-w-56 content-center">
<div
class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3"
>
<svg
class="h-4 w-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
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>
</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"
{% block title %} Home {% endblock %}
{% block content %}
<div class="container">
<p class="container d-flex justify-content-center">
<input id="search"
class="form-control"
type="search" name="q"
placeholder="Search"
aria-label="Search"
value='{{ query.search.as_deref().unwrap_or("") }}'
@ -40,7 +17,7 @@
hx-target="#items"
hx-push-url="true"
/>
</div>
</p>
<div id="items" class="container">
{% include "home_search_item_fragment.html" %}

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

@ -1,30 +1,24 @@
<table
class="w-full text-left text-sm rtl:text-right"
hx-get="/item/{{item_id}}/adjustments"
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"
>
<table class="table" hx-get="/item/{{item_id}}/adjustments" hx-trigger="new-adjustment from:body" hx-swap="outerHTML">
<thead>
<tr>
<th class="px-6 py-3" scope="col">Date</th>
<th class="px-6 py-3" scope="col">Amount</th>
<th class="px-6 py-3" scope="col">Reason</th>
<th class="px-6 py-3" scope="col">Unit Value</th>
<th class="px-6 py-3" scope="col">Running Total</th>
<th class="px-6 py-3" scope="col">Running Value</th>
<th scope="col">Date</th>
<th scope="col">Amount</th>
<th scope="col">Reason</th>
<th scope="col">Unit Value</th>
<th scope="col">Running Total</th>
<th scope="col">Running Value</th>
</tr>
</thead>
<tbody>
{% for item in adjustments %}
<tr>
<td class="px-6 py-4">{{ item.date }}</td>
<td class="px-6 py-4">{{ item.amount }}</td>
<td class="px-6 py-4">{{ item.reason }}</td>
<td class="px-6 py-4">{{ item.unit_value }}</td>
<td class="px-6 py-4">{{ item.tally }}</td>
<td class="px-6 py-4">{{ item.tally_value }}</td>
<td>{{ item.date }}</td>
<td>{{ item.amount }}</td>
<td>{{ item.reason }}</td>
<td>{{ item.unit_value }}</td>
<td>{{ item.tally }}</td>
<td>{{ item.tally_value }}</td>
</tr>
{% endfor %}
</tbody>

@ -1,119 +1,65 @@
<form
hx-post="/item/{{item_id}}/adjustment/negative"
hx-target="this"
hx-swap="outerHTML"
<form hx-post="/item/{{item_id}}/adjustment/negative"
hx-target="this" hx-swap="outerHTML"
x-ref="formNegativeAdjustment"
x-data="{ reason: 'Sale', reason_dropdown_show: false }"
>
<div class="mb-5">
<label for="amount" class="mb-2 block text-sm font-medium">Amount</label>
<input
type="number"
x-data="{ reason: 'Sale' }">
<input id="reason" name="reason" type="hidden" x-model="reason"/>
<div class="row">
<div class="col">
<!--<label for="amount" class="form-label">Amount</label>-->
<input type="number"
id="amount"
name="amount"
step="0.01"
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"
class="form-control"
placeholder="Amount"
aria-label="amount"
required
{%
if
!amount_error.is_empty()
-%}
{% if !amount_error.is_empty() -%}
aria-invalid="true"
aria-describedby="invalid-amount"
{%
endif
-%}
{% endif -%}
/>
{% if !amount_error.is_empty() -%}
<small id="invalid-amount" class="mt-2 text-sm text-cerise">
{{ amount_error }}
</small>
<small id="invalid-amount" class="invalid-feedback">{{ amount_error }}</small>
{% endif -%}
</div>
<div class="mb-5 flex justify-start">
<button
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"
x-text="reason"
>
Sale
</button>
<div
x-data="{ isOpen: false, openedWithKeyboard: false }"
class="relative w-fit"
x-on:keydown.esc.window="isOpen = false; openedWithKeyboard = false"
>
<button
type="button"
x-on:click="isOpen = ! isOpen"
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"
aria-haspopup="true"
x-on:keydown.space.prevent="openedWithKeyboard = true"
x-on:keydown.enter.prevent="openedWithKeyboard = true"
x-on:keydown.down.prevent="openedWithKeyboard = true"
x-bind:class="isOpen || openedWithKeyboard ? 'text-on-surface-strong dark:text-on-surface-dark-strong' : 'text-on-surface dark:text-on-surface-dark'"
x-bind:aria-expanded="isOpen || openedWithKeyboard"
>
<span class="sr-only">Reason Options</span>
<svg
aria-hidden="true"
fill="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
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>
<div class="col">
<button class="btn btn-primary" x-text="reason">Sale</button>
</div>
<div class="col">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown"
aria-expanded="false">
<span class="visually-hidden">Other</span>
</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"
>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item"
@click="reason = 'Sale'">
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"
>
</li>
<li>
<a class="dropdown-item"
@click="reason = 'Destruction'">
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"
>
</li>
<li>
<a class="dropdown-item"
@click="reason = 'Expiration'">
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"
>
</li>
<li>
<a class="dropdown-item"
@click="reason = 'Theft'">
Theft
</a>
</li>
</ul>
</div>
</div>
</div>
<input id="reason" name="reason" type="hidden" x-model="reason" />
</form>

@ -1,66 +1,43 @@
<form
hx-post="/item/{{item_id}}/adjustment/positive"
hx-target="this"
hx-swap="outerHTML"
>
<div class="mb-5">
<label for="amount" class="mb-2 block text-sm font-medium">Amount</label>
<input
type="number"
<form hx-post="/item/{{item_id}}/adjustment/positive" hx-target="this" hx-swap="outerHTML" >
<div class="row">
<div class="col">
<input type="number"
id="amount"
name="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"
step="0.01"
class="form-control"
placeholder="Amount"
aria-label="amount"
required
{%
if
!amount_error.is_empty()
-%}
{% if !amount_error.is_empty() -%}
aria-invalid="true"
aria-describedby="invalid-amount"
{%
endif
-%}
{% endif -%}
/>
{% if !amount_error.is_empty() -%}
<small id="invalid-amount" class="mt-2 text-sm text-cerise">
{{ amount_error }}
</small>
<small id="invalid-amount" class="invalid-feedback">{{ amount_error }}</small>
{% endif -%}
</div>
<div class="mb-5">
<label for="price" class="mb-2 block text-sm font-medium">Price</label>
<input
type="text"
<div class="col">
<input type="text"
id="price"
name="price"
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"
placeholder="Price"
class="form-control"
aria-label="price"
required
{%
if
!price_error.is_empty()
-%}
{% if !price_error.is_empty() -%}
aria-invalid="true"
aria-describedby="invalid-price"
{%
endif
-%}
{% endif -%}
/>
{% if !price_error.is_empty() -%}
<small id="invalid-price" class="mt-2 text-sm text-cerise"
>{{ price_error }}</small
>
<small id="invalid-price" class="invalid-feedback">{{ 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 class="col">
<button class="btn btn-primary">Add</button>
</div>
</div>
</form>

@ -1,66 +1,53 @@
{% extends "main.html" %} {% block title %} Items {% endblock %} {% block
content %}
{% extends "main.html" %}
<h2 class="mb-4 flex items-center text-4xl font-extrabold">
{{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>
{% block title %} Items {% endblock %}
{% block content %}
<section
hx-get="/item/{{item_id}}/stats"
hx-trigger="load"
hx-swap="outerHTML"
></section>
<div class="container mb-5">
<h2>{{item.name}} {% if !item.active %}<span class="badge text-bg-danger">Inactive</span> {% endif %}</h2>
</div>
<section class="container">
<div hx-get="/item/{{item_id}}/stats" hx-trigger="load" hx-swap="outerHTML">
</div>
</section>
{% if item.active %}
<section
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"
>
<section class="container-fluid">
<div x-data="{ open: false }" class="mb-3">
<div class="d-flex justify-content-start">
<div class="me-3">
<button class="btn btn-primary display-6" @click="open = ! 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"
>
</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-data="{ open: false }" class="mb-3">
<div class="d-flex justify-content-start">
<div class="me-3">
<button class="btn btn-primary" @click="open = ! open">
Plus
</button>
</div>
<div x-show="negative_form_open" @click.outside="negative_form_open = false">
<div
hx-get="/item/{{item_id}}/adjustment/negative"
hx-trigger="load"
hx-swap="outerHTML"
></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 x-show="positive_form_open" @click.outside="positive_form_open = false">
<div
hx-get="/item/{{item_id}}/adjustment/positive"
hx-trigger="load"
hx-swap="outerHTML"
></div>
</div>
</section>
{% endif %}
<section class="mx-auto">
<div
hx-get="/item/{{item_id}}/adjustments"
hx-trigger="load"
hx-swap="outerHTML"
></div>
<section class="container">
<div hx-get="/item/{{item_id}}/adjustments" hx-trigger="load" hx-swap="outerHTML">
</div>
</section>
{% endblock %}

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

@ -1,4 +1,6 @@
{% extends "main.html" %} {% block content %}
{% extends "main.html" %}
{% block content %}
<h1>Logged out</h1>
<p>You have been logged out</p>

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

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

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

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

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

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

Loading…
Cancel
Save

Powered by TurnKey Linux.