ai cooking
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #124 from paulgmiller/collapse

hide details

authored by

Paul Miller and committed by
GitHub
e7dcc9df e14990e1

+61 -26
+3
internal/recipes/buttons_test.go
··· 66 66 if !strings.Contains(html, `Dismiss`) { 67 67 t.Error("HTML should contain Dismiss label text") 68 68 } 69 + if !strings.Contains(html, `Details`) { 70 + t.Error("HTML should contain Details button text") 71 + } 69 72 70 73 // Check that "Regenerate" button exists 71 74 if !strings.Contains(html, `Regenerate`) {
+58 -26
internal/templates/chat.html
··· 69 69 <p class="mt-1 text-sm text-gray-500">{{.Description}}</p> 70 70 </div> 71 71 <div class="flex flex-wrap items-center gap-3"> 72 - <input type="radio" {{if .Saved}}checked{{end}} name="recipe-{{.ComputeHash}}" value="save" id="save-{{.ComputeHash}}" class="peer/save hidden" onchange="document.getElementById('saved-{{.ComputeHash}}').value = '{{.ComputeHash}}'; document.getElementById('dismissed-{{.ComputeHash}}').value = '';" /> 72 + <input type="radio" {{if .Saved}}checked{{end}} name="recipe-{{.ComputeHash}}" value="save" id="save-{{.ComputeHash}}" class="peer/save hidden" onchange="document.getElementById('saved-{{.ComputeHash}}').value = '{{.ComputeHash}}'; document.getElementById('dismissed-{{.ComputeHash}}').value = ''; setRecipeDetailsVisible('{{.ComputeHash}}', false);" /> 73 73 <label for="save-{{.ComputeHash}}" class="inline-flex items-center justify-center rounded-lg border-2 border-emerald-500 bg-emerald-50 px-4 py-2 text-sm font-medium text-emerald-700 cursor-pointer transition hover:bg-emerald-100 peer-checked/save:bg-emerald-600 peer-checked/save:text-white peer-checked/save:border-emerald-700"> 74 74 Save 75 75 </label> 76 - <input type="radio" name="recipe-{{.ComputeHash}}" value="dismiss" id="dismiss-{{.ComputeHash}}" class="peer/dismiss hidden" onchange="document.getElementById('dismissed-{{.ComputeHash}}').value = '{{.ComputeHash}}'; document.getElementById('saved-{{.ComputeHash}}').value = '';" /> 76 + <input type="radio" name="recipe-{{.ComputeHash}}" value="dismiss" id="dismiss-{{.ComputeHash}}" class="peer/dismiss hidden" onchange="document.getElementById('dismissed-{{.ComputeHash}}').value = '{{.ComputeHash}}'; document.getElementById('saved-{{.ComputeHash}}').value = ''; setRecipeDetailsVisible('{{.ComputeHash}}', false);" /> 77 77 <label for="dismiss-{{.ComputeHash}}" class="inline-flex items-center justify-center rounded-lg border-2 border-red-500 bg-red-50 px-4 py-2 text-sm font-medium text-red-700 cursor-pointer transition hover:bg-red-100 peer-checked/dismiss:bg-red-600 peer-checked/dismiss:text-white peer-checked/dismiss:border-red-700"> 78 78 Dismiss 79 79 </label> 80 + <button type="button" 81 + id="details-{{.ComputeHash}}-button" 82 + aria-controls="details-{{.ComputeHash}}" 83 + aria-expanded="{{if .Saved}}false{{else}}true{{end}}" 84 + onclick="toggleRecipeDetails('{{.ComputeHash}}')" 85 + class="inline-flex items-center justify-center rounded-lg border-2 border-brand-400 bg-brand-50 px-4 py-2 text-sm font-medium text-brand-700 transition hover:bg-brand-100 focus:outline-none focus:ring-2 focus:ring-brand-400 focus:ring-offset-2"> 86 + {{if .Saved}}Show details{{else}}Hide details{{end}} 87 + </button> 80 88 <input type="hidden" name="saved" id="saved-{{.ComputeHash}}" value="{{if .Saved}}{{.ComputeHash}}{{end}}" /> 81 89 <input type="hidden" name="dismissed" id="dismissed-{{.ComputeHash}}" value="" /> 82 90 </div> 83 91 </header> 84 92 85 - <section class="grid gap-6 md:grid-cols-2"> 86 - <div> 87 - <h3 class="text-sm font-semibold uppercase tracking-wide text-gray-500">Ingredients</h3> 88 - <ul class="mt-3 space-y-2 text-gray-700"> 89 - {{range .Ingredients}} 90 - <li class="flex flex-wrap items-center justify-between gap-2 rounded-lg bg-brand-50 px-3 py-2 text-sm"> 91 - <span class="font-medium text-brand-700">{{.Name}}</span> 92 - <span class="text-gray-600">{{.Quantity}}</span> 93 - <span class="text-gray-500">{{.Price}}</span> 94 - </li> 95 - {{end}} 96 - </ul> 97 - </div> 98 - <div> 99 - <h3 class="text-sm font-semibold uppercase tracking-wide text-gray-500">Instructions</h3> 100 - <ol class="mt-3 list-decimal space-y-2 pl-5 text-gray-700"> 101 - {{range .Instructions}} 102 - <li>{{.}}</li> 103 - {{end}} 104 - </ol> 93 + <section id="details-{{.ComputeHash}}" class="space-y-6 {{if .Saved}}hidden{{end}}"> 94 + <div class="grid gap-6 md:grid-cols-2"> 95 + <div> 96 + <h3 class="text-sm font-semibold uppercase tracking-wide text-gray-500">Ingredients</h3> 97 + <ul class="mt-3 space-y-2 text-gray-700"> 98 + {{range .Ingredients}} 99 + <li class="flex flex-wrap items-center justify-between gap-2 rounded-lg bg-brand-50 px-3 py-2 text-sm"> 100 + <span class="font-medium text-brand-700">{{.Name}}</span> 101 + <span class="text-gray-600">{{.Quantity}}</span> 102 + <span class="text-gray-500">{{.Price}}</span> 103 + </li> 104 + {{end}} 105 + </ul> 106 + </div> 107 + <div> 108 + <h3 class="text-sm font-semibold uppercase tracking-wide text-gray-500">Instructions</h3> 109 + <ol class="mt-3 list-decimal space-y-2 pl-5 text-gray-700"> 110 + {{range .Instructions}} 111 + <li>{{.}}</li> 112 + {{end}} 113 + </ol> 114 + </div> 105 115 </div> 106 - </section> 107 116 108 - <section class="space-y-2 text-sm text-gray-600"> 109 - <p><span class="font-semibold text-brand-700">Health notes:</span> {{.Health}}</p> 110 - <p><span class="font-semibold text-brand-700">Drink pairing:</span> {{.DrinkPairing}}</p> 117 + <div class="space-y-2 text-sm text-gray-600"> 118 + <p><span class="font-semibold text-brand-700">Health notes:</span> {{.Health}}</p> 119 + <p><span class="font-semibold text-brand-700">Drink pairing:</span> {{.DrinkPairing}}</p> 120 + </div> 111 121 </section> 112 122 </article> 113 123 {{end}} ··· 168 178 }).catch(function (err) { 169 179 alert('Failed to copy link: ' + err); 170 180 }); 181 + } 182 + 183 + function toggleRecipeDetails(hash) { 184 + const panel = document.getElementById('details-' + hash); 185 + if (!panel) { 186 + return; 187 + } 188 + const isOpen = panel.classList.contains('hidden'); 189 + setRecipeDetailsVisible(hash, isOpen); 190 + } 191 + 192 + function setRecipeDetailsVisible(hash, isVisible) { 193 + const panel = document.getElementById('details-' + hash); 194 + if (!panel) { 195 + return; 196 + } 197 + panel.classList.toggle('hidden', !isVisible); 198 + const button = document.getElementById('details-' + hash + '-button'); 199 + if (button) { 200 + button.setAttribute('aria-expanded', isVisible ? 'true' : 'false'); 201 + button.textContent = isVisible ? 'Hide details' : 'Show details'; 202 + } 171 203 } 172 204 173 205 const shoppingListToggle = document.getElementById('shoppingListToggle');