Clarify account, theme, and pagination controls
This commit is contained in:
+1
-1
@@ -116,7 +116,7 @@ function showPasswordChange(user){
|
||||
state.user=user;document.body.className="auth-required";$("#authBody").innerHTML=`<h1>Change your password</h1><p>Your temporary password must be replaced before you can use Stockroom.</p><form id="passwordForm"><label>Current password<input name="currentPassword" type="password" autocomplete="current-password" required></label><label>New password<input name="newPassword" type="password" minlength="8" autocomplete="new-password" required></label><label>Confirm new password<input name="confirmPassword" type="password" minlength="8" autocomplete="new-password" required></label><small>Passwords must contain at least 8 characters.</small><button class="primary auth-submit">Save password</button></form><button class="secondary auth-logout" id="changeLogout">Log out</button>`;
|
||||
$("#passwordForm").onsubmit=async e=>{e.preventDefault();try{await api("/api/auth/change-password",{method:"POST",body:JSON.stringify(Object.fromEntries(new FormData(e.currentTarget)))});await enterApp({...user,mustChangePassword:false});}catch(error){toast(error.message);}};$("#changeLogout").onclick=logout;
|
||||
}
|
||||
async function enterApp(user){state.user=user;document.body.className=user.role==="admin"?"role-admin":"role-readonly";const account=$("#currentUser"),menu=$(".user-menu");account.innerHTML=`<strong>${esc(user.username)}</strong><small>${user.role==="admin"?"Admin":"Read-Only"}</small>`;account.style.width="96px";account.style.textAlign="right";menu.style.marginLeft="auto";menu.style.minWidth="210px";menu.style.justifyContent="flex-end";const adminTab=document.querySelector('[data-tab="admin"]');adminTab.hidden=user.role!=="admin";adminTab.style.display=user.role==="admin"?"":"none";document.querySelectorAll(".edit-only").forEach(el=>{el.hidden=user.role!=="admin";el.style.display=user.role==="admin"?"":"none";});if(user.role!=="admin"&&state.tab==="admin")state.tab="available";await load();}
|
||||
async function enterApp(user){state.user=user;document.body.className=user.role==="admin"?"role-admin":"role-readonly";const account=$("#currentUser"),menu=$(".user-menu");account.innerHTML=`<small>Logged in as</small><strong>${esc(user.username)}</strong><small>${user.role==="admin"?"Admin":"Read-Only"}</small>`;account.style.width="104px";account.style.textAlign="right";menu.style.marginLeft="auto";menu.style.minWidth="280px";menu.style.justifyContent="flex-end";const adminTab=document.querySelector('[data-tab="admin"]');adminTab.hidden=user.role!=="admin";adminTab.style.display=user.role==="admin"?"":"none";document.querySelectorAll(".edit-only").forEach(el=>{el.hidden=user.role!=="admin";el.style.display=user.role==="admin"?"":"none";});if(user.role!=="admin"&&state.tab==="admin")state.tab="available";await load();}
|
||||
async function logout(){try{await api("/api/auth/logout",{method:"POST",body:"{}"});}catch{}showLogin();}
|
||||
async function initialize(){try{const response=await fetch("/api/auth/me"),data=await response.json();if(!response.ok)return showLogin();data.mustChangePassword?showPasswordChange(data):await enterApp(data);}catch{showLogin("Unable to connect to Stockroom.");}}
|
||||
document.querySelectorAll("[data-tab]").forEach(b=>b.onclick=()=>{state.tab=b.dataset.tab;state.page=1;render();});
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><meta name="theme-color" content="#f5f7fb"><title>vSeeBox Stockroom</title><script>try{const t=localStorage.getItem("stockroom-theme")||"system",d=t==="dark"||(t==="system"&&matchMedia("(prefers-color-scheme:dark)").matches);document.documentElement.dataset.theme=d?"dark":"light"}catch{}</script><link rel="stylesheet" href="/style.css"><link rel="stylesheet" href="/extras.css"><link rel="stylesheet" href="/theme.css"></head>
|
||||
<body class="auth-pending"><section id="authScreen" class="auth-screen"><div class="auth-card"><div class="brand auth-brand"><b>S</b><span>Stockroom</span></div><div id="authBody"></div></div></section><div id="appShell"><header><div class="brand"><b>S</b><span>Stockroom</span></div><input id="search" type="search" aria-label="Search inventory, sales, and customers" placeholder="Search UID, SN, MAC, model, customer…"><div class="actions edit-only"><button class="secondary" data-open="receive">+ Receive product</button><button class="primary" data-open="sell">Record a sale</button></div><div class="user-menu"><span id="currentUser"></span><select id="themeSelect" aria-label="Color theme"><option value="system">System</option><option value="light">Light</option><option value="dark">Dark</option></select><button class="secondary" id="logout">Log out</button></div></header>
|
||||
<body class="auth-pending"><section id="authScreen" class="auth-screen"><div class="auth-card"><div class="brand auth-brand"><b>S</b><span>Stockroom</span></div><div id="authBody"></div></div></section><div id="appShell"><header><div class="brand"><b>S</b><span>Stockroom</span></div><input id="search" type="search" aria-label="Search inventory, sales, and customers" placeholder="Search UID, SN, MAC, model, customer…"><div class="actions edit-only"><button class="secondary" data-open="receive">+ Receive product</button><button class="primary" data-open="sell">Record a sale</button></div><div class="user-menu"><span id="currentUser"></span><label class="theme-control"><span>Theme</span><select id="themeSelect" aria-label="Color theme"><option value="system">System</option><option value="light">Light</option><option value="dark">Dark</option></select></label><button class="secondary" id="logout">Log out</button></div></header>
|
||||
<main><div class="intro"><h1>Inventory Overview</h1><span id="date"></span></div><section class="stats"><article><span>Available products</span><strong id="availableCount">0</strong><small>Ready to sell</small></article><article><span>Sold this month</span><strong id="soldCount">0</strong><small id="revenue">No sales recorded</small></article><article><span>Inventory value</span><strong id="value">$0</strong><small>Based on purchase cost</small></article></section>
|
||||
<section class="records"><nav><button class="tab active" data-tab="available">Available inventory <i id="availableBadge">0</i></button><button class="tab" data-tab="sold">Sales history <i id="soldBadge">0</i></button><button class="tab" data-tab="customers">Customers <i id="customerBadge">0</i></button><button class="tab" data-tab="admin">Admin</button><span id="storageStatus" class="storage-status connecting" role="status" aria-live="polite"><i></i><b>Connecting to database</b></span></nav><div class="table-wrap"><table><thead id="thead"></thead><tbody id="rows"></tbody></table><div id="empty" hidden></div></div><div id="adminPanel" hidden></div><footer id="pagination"></footer></section></main>
|
||||
<dialog id="modal"><button class="close" aria-label="Close">×</button><div id="modalBody"></div></dialog><div id="toast" hidden></div></div><script type="module" src="/app.js"></script></body></html>
|
||||
|
||||
+4
-3
@@ -28,7 +28,8 @@ th{background:var(--surface-table);color:var(--muted-2)}th,td,.records nav,.back
|
||||
.auth-screen{background:linear-gradient(145deg,color-mix(in srgb,var(--blue) 10%,var(--page)),var(--page))}.auth-card{box-shadow:0 22px 60px var(--shadow)}
|
||||
dialog{max-height:min(90dvh,900px);overflow:auto}dialog::backdrop{background:#050914aa}.close{color:var(--muted)}
|
||||
#toast{background:var(--text-strong);color:var(--surface);box-shadow:0 12px 30px var(--shadow)}
|
||||
.user-menu select{width:118px;border:1px solid var(--border-strong);border-radius:9px;padding:9px 30px 9px 10px;font-size:12px;font-weight:650}
|
||||
.theme-control{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:6px;margin:0;color:var(--muted);font-size:11px}.user-menu select{width:92px;border:1px solid var(--border-strong);border-radius:9px;padding:9px 26px 9px 9px;font-size:12px;font-weight:650}
|
||||
#pagination button{background:var(--surface-soft);border-color:var(--border-strong);color:var(--text)}#pagination button:not(:disabled):hover{background:var(--blue-soft);color:var(--blue-text)}#pagination button:disabled{background:var(--surface-soft);color:var(--text);opacity:1;cursor:not-allowed}
|
||||
button,.button,input,select,textarea{-webkit-tap-highlight-color:transparent}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:3px solid color-mix(in srgb,var(--blue) 45%,transparent);outline-offset:2px}
|
||||
@media (prefers-reduced-motion:reduce){*,*::before,*::after{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}
|
||||
@media (pointer:coarse){button,.button,.upload-backup,.user-menu select{min-height:44px}}
|
||||
@@ -38,7 +39,7 @@ button,.button,input,select,textarea{-webkit-tap-highlight-color:transparent}but
|
||||
}
|
||||
@media (max-width:820px){
|
||||
header{position:relative;display:grid;grid-template-columns:auto 1fr auto;height:auto;padding:12px max(14px,env(safe-area-inset-right)) 12px max(14px,env(safe-area-inset-left));gap:10px}
|
||||
header .brand{grid-column:1}.user-menu{grid-column:2/4;grid-row:1;margin-left:auto!important;min-width:0!important;padding-left:0;border-left:0}.user-menu #currentUser{display:grid!important;width:auto!important;min-width:70px}
|
||||
header .brand{grid-column:1}.user-menu{grid-column:2/4;grid-row:1;margin-left:auto!important;min-width:0!important;padding-left:0;border-left:0}.user-menu #currentUser{display:grid!important;width:auto!important;min-width:78px}.theme-control{grid-template-columns:1fr}.theme-control>span{font-size:10px;text-align:center}
|
||||
header #search{grid-column:1/-1;grid-row:2;order:initial}.actions{grid-column:1/-1;grid-row:3;width:100%;margin:0}.actions button{font-size:14px!important;flex:1}.actions button::first-letter{font-size:inherit!important}
|
||||
main{width:min(100% - 24px,1400px);margin:14px auto 28px}.intro h1{font-size:23px}.intro>span{font-size:12px}.stats{gap:10px;margin:14px 0}.stats article{padding:16px}.stats strong{font-size:26px}
|
||||
.records{overflow:visible}.records nav{display:grid;grid-template-columns:1fr 1fr;overflow:visible;height:auto;padding:0 10px;gap:0}.records nav .tab{width:100%;height:50px;white-space:nowrap;padding-inline:6px;font-size:12px}.storage-status{grid-column:1/-1;min-width:100%;margin:0!important;padding:10px 4px!important;border-top:1px solid var(--border)}
|
||||
@@ -49,7 +50,7 @@ button,.button,input,select,textarea{-webkit-tap-highlight-color:transparent}but
|
||||
.auth-screen{padding:16px}.auth-card{padding:25px 20px}.auth-brand span{display:inline}
|
||||
}
|
||||
@media (max-width:430px){
|
||||
.user-menu{width:100%;justify-content:flex-end!important}.user-menu select{width:88px;max-width:88px;padding-inline:8px}.user-menu #currentUser small{font-size:10px}.user-menu #logout{padding-inline:10px}
|
||||
.user-menu{width:100%;justify-content:flex-end!important}.user-menu select{width:72px;max-width:72px;padding-inline:7px}.user-menu #currentUser small{font-size:10px}.user-menu #logout{padding-inline:10px}
|
||||
.intro{align-items:flex-start}.intro h1{margin:8px 0}.intro>span{padding:7px 8px}.stats{grid-template-columns:1fr}.stats article{grid-template-columns:1fr auto}.stats article strong{grid-column:2;grid-row:1/3}.stats article small{grid-column:1}
|
||||
td{grid-template-columns:82px 1fr}.backup-list article>div:last-child,.user-list article>div:last-child{grid-template-columns:1fr}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user