fix(directory): reduce 3-dot menu size and unify single filter button with exact Meez SVG

This commit is contained in:
2026-08-18 12:48:14 -05:00
parent 189fed7168
commit c07342eb38
2 changed files with 60 additions and 21 deletions
+2 -11
View File
@@ -43,7 +43,7 @@ const attention=Astro.url.searchParams.get("attention")==="1", missingCost=Astro
const filtering=attention||missingCost||noUsda||unused||emptyRecipe||placeholderSteps;
const filteredIngredients=ingredients.filter((ingredient)=>{if(!filtering)return true;const selected=[missingCost&&ingredient.price_count===0,noUsda&&ingredient.nutrition_count===0,unused&&ingredient.recipe_count===0].filter(Boolean);return missingCost||noUsda||unused?selected.length>0:ingredient.price_count===0||ingredient.nutrition_count===0||ingredient.recipe_count===0;});
const filteredRecipes=recipes.filter(recipe=>!filtering||(emptyRecipe&&recipe.item_count===0)||(placeholderSteps&&recipe.placeholder_count>0)||(!emptyRecipe&&!placeholderSteps&&(recipe.item_count===0||recipe.placeholder_count>0)));
const FILTER_ICON_PATH="M18 6.0201C18 4.81608 17.1873 3.79266 16.0736 3.46156L16.0736 0.722412C16.0736 0.301005 15.7425 -9.86801e-08 15.3211 -1.171e-07C14.8996 -1.35521e-07 14.5685 0.331105 14.5685 0.752512L14.5685 3.49166C13.4548 3.79266 12.6421 4.84618 12.6421 6.0502C12.6421 7.28432 13.4548 8.30774 14.5685 8.63884L14.5685 19.7459C14.5685 20.1673 14.8996 20.4984 15.3211 20.4984C15.7425 20.4984 16.0736 20.1673 16.0736 19.7459L16.0736 8.63884C17.1873 8.27764 18 7.25422 18 6.0201ZM16.495 6.0502C16.495 6.68231 15.9833 7.22412 15.3211 7.22412C14.6588 7.22412 14.1471 6.68231 14.1471 6.0502C14.1471 5.41809 14.6588 4.87628 15.3211 4.87628C15.9833 4.87628 16.495 5.41809 16.495 6.0502Z";
const FILTER_ICON_PATH="M18 6.0201C18 4.81608 17.1873 3.79266 16.0736 3.46156L16.0736 0.722412C16.0736 0.301005 15.7425 0 15.3211 0C14.8996 0 14.5685 0.331105 14.5685 0.752512L14.5685 3.49166C13.4548 3.79266 12.6421 4.84618 12.6421 6.0502C12.6421 7.28432 13.4548 8.30774 14.5685 8.63884L14.5685 19.7459C14.5685 20.1673 14.8996 20.4984 15.3211 20.4984C15.7425 20.4984 16.0736 20.1673 16.0736 19.7459L16.0736 8.63884C17.1873 8.27764 18 7.25422 18 6.0201ZM16.495 6.0502C16.495 6.68231 15.9833 7.22412 15.3211 7.22412C14.6588 7.22412 14.1471 6.68231 14.1471 6.0502C14.1471 5.41809 14.6588 4.87628 15.3211 4.87628C15.9833 4.87628 16.495 5.41809 16.495 6.0502ZM5.35789 14.4799C5.35789 13.2759 4.54521 12.2525 3.43147 11.9214L3.43147 0.752512C3.43147 0.331105 3.10042 0 2.67895 0C2.25747 0 1.92642 0.331105 1.92642 0.752512L1.92642 11.9214C0.812684 12.2525 0 13.2759 0 14.4799C0 15.714 0.812684 16.7374 1.92642 17.0685L1.92642 19.7459C1.92642 20.1673 2.25747 20.4984 2.67895 20.4984C3.10042 20.4984 3.43147 20.1673 3.43147 19.7459L3.43147 17.0685C4.54521 16.7374 5.35789 15.714 5.35789 14.4799ZM3.85289 14.4799C3.85289 15.112 3.34116 15.6538 2.67895 15.6538C2.01674 15.6538 1.50505 15.112 1.50505 14.4799C1.50505 13.8478 2.01674 13.306 2.67895 13.306C3.34116 13.306 3.85289 13.8478 3.85289 14.4799Z";
const tabs:Array<{type:string;label:string;count:number;kind:"recipe"|"ingredient"|"book"|"purchase"|"inventory";href?:string}>=[
{type:"recipe",label:"Recipes",count:recipes.length,kind:"recipe"},
{type:"ingredient",label:"Ingredients",count:ingredients.length,kind:"ingredient"},
@@ -72,16 +72,6 @@ const purchaseRows=purchases.map(item=>({id:item.id,name:item.name,href:`/app/in
<input type="search" name="q" value={query} placeholder="Search " aria-label="Search all items" autofocus={Boolean(query)}/>
{query&&<a href={type?`/app/?type=${type}`:"/app/"} aria-label="Clear search">×</a>}
</form>
<details class="search-type-filter" open={filteringSearchTypes}>
<summary><svg class="filter-icon" viewBox="0 0 18 21" aria-hidden="true"><path fill="currentColor" d={FILTER_ICON_PATH}/></svg>Item type{filteringSearchTypes?` · ${selectedSearchTypes.length}`:""}</summary>
<form method="get" action="/app/"><input type="hidden" name="type" value={type??""}/><input type="hidden" name="q" value={query}/>
<label><input type="checkbox" name="item_type" value="recipe" checked={selectedSearchTypes.includes("recipe")}/> Recipes</label>
<label><input type="checkbox" name="item_type" value="ingredient" checked={selectedSearchTypes.includes("ingredient")}/> Ingredients</label>
<label><input type="checkbox" name="item_type" value="book" checked={selectedSearchTypes.includes("book")}/> Recipe books</label>
<label><input type="checkbox" name="item_type" value="purchase" checked={selectedSearchTypes.includes("purchase")}/> Purchase items</label>
<div><button>Apply</button>{filteringSearchTypes&&<a href={type?`/app/?type=${type}&q=${encodeURIComponent(query)}`:`/app/?q=${encodeURIComponent(query)}`}>All types</a>}</div>
</form>
</details>
{!readOnlyMode&&<details class="workspace-new-menu">
<summary><span class="new-trigger-plus" aria-hidden="true"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg></span><span class="new-trigger-label">New</span></summary>
<nav aria-label="Create new item">
@@ -101,6 +91,7 @@ const purchaseRows=purchases.map(item=>({id:item.id,name:item.name,href:`/app/in
{tabs.map((tab)=><a class:list={{active:type===tab.type}} href={tab.href ?? `/app/?type=${tab.type}`}><span class={`workspace-pill-icon ${tab.kind}`}><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d={TYPE_ICONS[tab.kind]} style={TYPE_ICON_TRANSFORMS[tab.kind]?{transform:TYPE_ICON_TRANSFORMS[tab.kind]}:undefined}/></svg></span><span>{tab.label}</span><small>{tab.count}</small></a>)}
{type==="ingredient"&&<details class="filter-menu" open={filtering}><summary><svg class="filter-icon" viewBox="0 0 18 21" aria-hidden="true"><path fill="currentColor" d={FILTER_ICON_PATH}/></svg>Filter{filtering?` · ${filteredIngredients.length}`:""}</summary><form method="get"><input type="hidden" name="type" value="ingredient"/><label><input type="checkbox" name="attention" value="1" checked={attention}/> Needs attention</label><fieldset><legend>Attention reasons</legend><label><input type="checkbox" name="missing_cost" value="1" checked={missingCost}/> Missing cost</label><label><input type="checkbox" name="no_usda" value="1" checked={noUsda}/> No USDA map</label><label><input type="checkbox" name="unused" value="1" checked={unused}/> Unused ingredient</label></fieldset><div><button>Apply filter</button>{filtering&&<a href="/app/?type=ingredient">Clear</a>}</div></form></details>}
{type==="recipe"&&<details class="filter-menu" open={filtering}><summary><svg class="filter-icon" viewBox="0 0 18 21" aria-hidden="true"><path fill="currentColor" d={FILTER_ICON_PATH}/></svg>Filter{filtering?` · ${filteredRecipes.length}`:""}</summary><form method="get"><input type="hidden" name="type" value="recipe"/><label><input type="checkbox" name="attention" value="1" checked={attention}/> Needs attention</label><fieldset><legend>Attention reasons</legend><label><input type="checkbox" name="empty_recipe" value="1" checked={emptyRecipe}/> Empty recipe</label><label><input type="checkbox" name="placeholder_steps" value="1" checked={placeholderSteps}/> Placeholder instructions</label></fieldset><div><button>Apply filter</button>{filtering&&<a href="/app/?type=recipe">Clear</a>}</div></form></details>}
{(!type || query)&&<details class="filter-menu" open={filteringSearchTypes}><summary><svg class="filter-icon" viewBox="0 0 18 21" aria-hidden="true"><path fill="currentColor" d={FILTER_ICON_PATH}/></svg>Filter{filteringSearchTypes?` · ${selectedSearchTypes.length}`:""}</summary><form method="get"><input type="hidden" name="type" value={type??""}/><input type="hidden" name="q" value={query}/><label><input type="checkbox" name="item_type" value="recipe" checked={selectedSearchTypes.includes("recipe")}/> Recipes</label><label><input type="checkbox" name="item_type" value="ingredient" checked={selectedSearchTypes.includes("ingredient")}/> Ingredients</label><label><input type="checkbox" name="item_type" value="book" checked={selectedSearchTypes.includes("book")}/> Recipe books</label><label><input type="checkbox" name="item_type" value="purchase" checked={selectedSearchTypes.includes("purchase")}/> Purchase items</label><div><button>Apply filter</button>{filteringSearchTypes&&<a href={type?`/app/?type=${type}&q=${encodeURIComponent(query)}`:`/app/?q=${encodeURIComponent(query)}`}>Clear</a>}</div></form></details>}
</nav>
</div>
{query?<section class="workspace-search-results" aria-live="polite"><p><strong>{searchResults.length}</strong> {searchResults.length===1?"result":"results"} for “{query}”{filteringSearchTypes&&` · ${selectedSearchTypes.length} item ${selectedSearchTypes.length===1?"type":"types"}`}</p>{searchRows.length?<EntityDirectory client:load rows={searchRows} emptyMessage="No items of the selected types match this search." readOnly={readOnlyMode}/>:<div class="empty-state">No items of the selected types match this search.</div>}</section>:<>
+58 -10
View File
@@ -89,10 +89,46 @@ input[type="search"]::-webkit-search-results-decoration,
.application-body .search-type-filter button,.application-body .filter-menu button { padding:8px 13px; color:#fff; background:#3d5df6; border:0; border-radius:4px; font-size:13px; font-weight:600; }
.application-body .search-type-filter form a,.application-body .filter-menu form a { color:#647df8; font-size:13px; text-decoration:none; }
.application-body .entity-row-actions > div { width:275px; padding:8px 0; border:0; border-radius:4px; box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12); }
.application-body .entity-row-actions a,.application-body .entity-row-actions button { min-height:47px; padding:10px 30px; color:#202962; font-size:16px; font-weight:500; }
.application-body .entity-row-actions button { color:#f63d48; }
.application-body .entity-row-actions a:hover,.application-body .entity-row-actions button:hover { background:#f1f5fe; transition:background-color .15s cubic-bezier(0.4,0,0.2,1); }
.application-body .entity-row-actions > div {
position: absolute;
z-index: 50;
top: calc(100% + 4px);
right: 0;
width: 140px;
padding: 4px 0;
background: #ffffff;
border: 1px solid #edf0f5;
border-radius: 6px;
box-shadow: 0 8px 24px rgba(5, 8, 65, 0.12);
}
.application-body .entity-row-actions a,
.application-body .entity-row-actions button {
display: flex;
align-items: center;
width: 100%;
min-height: 34px;
padding: 6px 14px;
color: #050841;
background: transparent;
border: 0;
border-radius: 0;
font-family: var(--meez-font-sans);
font-size: 13px;
font-weight: 500;
text-align: left;
cursor: pointer;
transition: background-color 0.12s ease;
}
.application-body .entity-row-actions button {
color: #f63d48;
}
.application-body .entity-row-actions a:hover,
.application-body .entity-row-actions button:hover {
background: #fef2f2;
}
.application-body .identity-edit > form { border-color:#e6e7ee; border-radius:4px; box-shadow:0 2px 5px rgba(5,8,65,.18); }
.application-body .workspace-nav-block {
display: flex;
@@ -217,15 +253,27 @@ input[type="search"]::-webkit-search-results-decoration,
.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:36px 64px minmax(14rem,1fr) 36px; gap:8px; min-height:57px; padding:0; border-bottom:1px solid #edf0f5; }
.application-body .entity-directory-table.read-only .entity-directory-row { grid-template-columns:30px minmax(0,1fr); }
.application-body .entity-directory-row.selected { background:#f1f5fe; }
.application-body .entity-directory-name a,.application-body .entity-directory-name strong { color:#050841; font-size:15px; font-weight:500; }
.application-body .entity-row-actions > summary { display:grid; place-items:center; width:24px; height:24px; color:#a5a9c1; background:transparent; border-radius:50%; font-size:18px; }
.application-body .entity-row-actions > summary:hover { background:rgba(0,0,0,0.04); }
.application-body .entity-row-actions > summary {
display: grid;
place-items: center;
width: 24px;
height: 24px;
color: #a5a9c1;
background: transparent;
border-radius: 50%;
cursor: pointer;
list-style: none;
transition: all 0.15s ease;
}
.application-body .entity-row-actions > summary::-webkit-details-marker { display: none; }
.application-body .entity-row-actions > summary:hover {
color: #050841;
background: rgba(5, 8, 65, 0.05);
}
.application-body .entity-directory-row .workspace-pill-icon { width:24px; height:24px; display:flex; align-items:center; justify-content:center; justify-self:start; margin-left:2px; background:#3c4679; border-radius:50%; color:#fff; }
.application-body .entity-directory-row .workspace-pill-icon.ingredient { background:#3f908a; }
.application-body .entity-directory-row .workspace-pill-icon.book { background:#f3a642; }
.application-body .entity-directory-row .workspace-pill-icon.purchase { background:#3f908a; }
.application-body .entity-row-actions > div { border:0; border-radius:4px; box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12); }
.application-body .entity-row-actions button { color:#f63d48; }
.visually-hidden {
position: absolute !important;
width: 1px !important;
@@ -243,7 +291,7 @@ input[type="search"]::-webkit-search-results-decoration,
.application-body .entity-directory-toolbar input[type="checkbox"]:checked::after,.application-body .entity-directory-row > input[type="checkbox"]:checked::after { content:""; display:block; width:5px; height:9px; margin:1px 0 0 5px; border:solid #fff; border-width:0 2px 2px 0; transform:rotate(45deg); }
.application-body .entity-directory-toolbar input[type="checkbox"]:indeterminate,.application-body .entity-directory-row > input[type="checkbox"]:indeterminate { background:#3d5df6; border-color:#3d5df6; }
.application-body .entity-directory-toolbar input[type="checkbox"]:indeterminate::after,.application-body .entity-directory-row > input[type="checkbox"]:indeterminate::after { content:""; display:block; width:10px; height:2px; margin:7px 0 0 3px; background:#fff; }
.application-body .entity-row-actions > summary svg { display:block; width:24px; height:24px; }
.application-body .entity-row-actions > summary svg { display:block; width:16px; height:16px; }
.application-body .workspace-pill-icon svg { display:block; width:20px; height:20px; }
.application-body .workspace-pills > a .workspace-pill-icon svg { width:20px; height:20px; padding:1.5px; }
.application-body .directory-error { padding:11px 20px; color:#f63d48; background:#fff1f2; border-bottom:1px solid #ffd7d9; }