align read-only directory tables
This commit is contained in:
@@ -16,4 +16,4 @@ const book=database.prepare("SELECT * FROM collections WHERE id=? AND deleted_at
|
||||
const recipes=database.prepare("SELECT r.id,r.title,cr.position,cr.recipe_id IS NOT NULL included FROM recipes r LEFT JOIN collection_recipes cr ON cr.recipe_id=r.id AND cr.collection_id=? WHERE r.deleted_at IS NULL ORDER BY coalesce(cr.position,999999),r.title").all(id) as any[];
|
||||
database.close();
|
||||
---
|
||||
<BaseLayout title={book.name} immersive><section class="entity-detail-shell recipe-book-detail"><DetailUtility/><header class="entity-detail-header"><div><p class="entity-breadcrumb"><a href="/app/?type=book">← Recipe books</a></p><h1>{book.name}</h1><p>{recipes.filter(x=>x.included).length} recipes</p></div>{!readOnlyMode&&<a class="edit-command" href={editing?`/app/recipe-books/${id}/`:`/app/recipe-books/${id}/?edit=1`}>{editing?"✓ Done":"✎ Edit"}</a>}</header>{error&&<p class="notice">{error}</p>}<main class="book-workspace">{editing&&<form method="post" class="book-details-form"><input type="hidden" name="intent" value="details"/><label><span>Name</span><input name="name" value={book.name} required/></label><label><span>Description</span><input name="description" value={book.description??""}/></label><button>Save details</button></form>}<form method="post" class="book-membership"><input type="hidden" name="intent" value="membership"/><header><div><h2>Recipes</h2><p>{editing?"Choose the recipes included in this book.":book.description}</p></div>{editing&&<button>Save recipes</button>}</header>{recipes.filter(recipe=>editing||recipe.included).map(recipe=><label class="book-recipe-row">{editing&&<input type="checkbox" name="recipe_id" value={recipe.id} checked={recipe.included}/>}<span class="workspace-pill-icon recipe">▦</span><a href={`/app/recipes/${recipe.id}/`}><strong>{recipe.title}</strong></a></label>)}</form></main></section></BaseLayout>
|
||||
<BaseLayout title={book.name} immersive><section class="entity-detail-shell recipe-book-detail"><DetailUtility/><header class="entity-detail-header"><div><p class="entity-breadcrumb"><a href="/app/?type=book">← Recipe books</a></p><h1>{book.name}</h1><p>{recipes.filter(x=>x.included).length} recipes</p></div>{!readOnlyMode&&<a class="edit-command" href={editing?`/app/recipe-books/${id}/`:`/app/recipe-books/${id}/?edit=1`}>{editing?"✓ Done":"✎ Edit"}</a>}</header>{error&&<p class="notice">{error}</p>}<main class="book-workspace">{editing&&<form method="post" class="book-details-form"><input type="hidden" name="intent" value="details"/><label><span>Name</span><input name="name" value={book.name} required/></label><label><span>Description</span><input name="description" value={book.description??""}/></label><button>Save details</button></form>}<form method="post" class:list={["book-membership",{"read-only":!editing}]}><input type="hidden" name="intent" value="membership"/><header><div><h2>Recipes</h2><p>{editing?"Choose the recipes included in this book.":book.description}</p></div>{editing&&<button>Save recipes</button>}</header>{recipes.filter(recipe=>editing||recipe.included).map(recipe=><label class="book-recipe-row">{editing&&<input type="checkbox" name="recipe_id" value={recipe.id} checked={recipe.included}/>}<span class="workspace-pill-icon recipe">▦</span><a href={`/app/recipes/${recipe.id}/`}><strong>{recipe.title}</strong></a></label>)}</form></main></section></BaseLayout>
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function EntityDirectory({rows,entityType,emptyMessage,readOnly=f
|
||||
if(!response.ok){setError(result.error??"Unable to delete selection.");setDeleting(false);dialog.current?.close();return;}
|
||||
location.reload();
|
||||
};
|
||||
return <section class="entity-directory-table">
|
||||
return <section class={`entity-directory-table${readOnly?" read-only":""}`}>
|
||||
{!readOnly&&<div class="entity-directory-toolbar">
|
||||
<input aria-label={`Select all ${entityType} items`} type="checkbox" checked={allSelected} ref={input=>{if(input)input.indeterminate=selected.length>0&&!allSelected;}} onChange={()=>setSelected(allSelected?[]:rows.map(row=>row.id))}/>
|
||||
<strong>{selected.length?`${selected.length} selected`:""}</strong>
|
||||
|
||||
@@ -349,6 +349,7 @@ th { font-size:.7rem; letter-spacing:.06em; }
|
||||
.application-body .entity-directory-toolbar button { color:#647df8; font-size:13px; }
|
||||
.application-body .entity-directory-toolbar .bulk-delete { color:#f63d48; }
|
||||
.application-body .entity-directory-row,.application-body .entity-directory-row.columns-1,.application-body .entity-directory-row.columns-2,.application-body .entity-directory-row.columns-3 { grid-template-columns:24px 30px minmax(14rem,1fr) 28px; gap:14px; min-height:60px; padding:0 20px; border-bottom:1px solid #eeeef3; }
|
||||
.application-body .entity-directory-table.read-only .entity-directory-row { grid-template-columns:30px minmax(0,1fr); }
|
||||
.application-body .entity-directory-row:hover { background:#f8faff; }
|
||||
.application-body .entity-directory-row.selected { background:#f1f5fe; }
|
||||
.application-body .entity-directory-name a,.application-body .entity-directory-name strong { color:#050841; font-size:14px; font-weight:500; }
|
||||
@@ -430,6 +431,7 @@ th { font-size:.7rem; letter-spacing:.06em; }
|
||||
.application-body .detail-actions-menu button { display:block; width:100%; min-height:42px; padding:10px 18px; color:#202962; background:transparent; border:0; border-radius:0; cursor:pointer; font-size:14px; text-align:left; }
|
||||
.application-body .detail-actions-menu button:hover { background:#f1f5fe; }
|
||||
.application-body .book-workspace { width:min(900px,calc(100% - 48px)); min-height:600px; margin:0 auto; padding:42px 0; }.application-body .book-details-form { display:grid; grid-template-columns:1fr 1.4fr auto; align-items:end; gap:12px; margin-bottom:32px; }.application-body .book-details-form label { display:grid; gap:5px; }.application-body .book-details-form input { padding:9px; }.application-body .book-details-form button,.application-body .book-membership header button { padding:9px 14px; color:#fff; background:#3d5df6; border:0; }.application-body .book-membership > header { display:flex; justify-content:space-between; align-items:start; padding-bottom:18px; border-bottom:1px solid #eeeef3; }.application-body .book-membership h2 { margin:0; font-size:20px; }.application-body .book-membership p { margin:4px 0 0; color:#a5a9c1; }.application-body .book-recipe-row { display:grid; grid-template-columns:24px 28px 1fr; align-items:center; gap:12px; min-height:60px; border-bottom:1px solid #eeeef3; }.application-body .book-recipe-row > a { display:flex; flex-direction:column; text-decoration:none; }.application-body .book-recipe-row small { color:#a5a9c1; }
|
||||
.application-body .book-membership.read-only .book-recipe-row { grid-template-columns:28px minmax(0,1fr); }
|
||||
.application-body .recipe-additional-editor { width:min(800px,calc(100% - 76px)); margin:36px 38px; padding-top:28px; border-top:1px solid #eeeef3; }.application-body .recipe-additional-editor > form { display:grid; gap:14px; }.application-body .recipe-additional-editor label { display:grid; gap:5px; }.application-body .recipe-additional-editor input,.application-body .recipe-additional-editor textarea,.application-body .recipe-additional-editor select { padding:9px; }.application-body .recipe-additional-editor fieldset { display:grid; grid-template-columns:120px 120px 1fr; gap:10px; border:1px solid #eeeef3; }.application-body .recipe-additional-editor button { justify-self:start; padding:9px 14px; color:#fff; background:#3d5df6; border:0; }
|
||||
.application-body .nutrition-ingredient-list { margin-top:16px; border-top:1px solid #eeeef3; }
|
||||
.application-body .nutrition-list-heading { display:flex; justify-content:space-between; gap:20px; padding:14px 4px 10px; color:#202962; }
|
||||
|
||||
Reference in New Issue
Block a user