nice clean recipes pear.dunkirk.sh
recipes
1
fork

Configure Feed

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

feat: add flag confirmation

+30 -2
+7 -1
ui/static/style.css
··· 333 333 .flag-link:hover{color:var(--accent);background:var(--border);text-decoration:none} 334 334 .flag-link.flagged{color:#dc2626} 335 335 .flag-link.flagged svg{fill:currentColor} 336 + #flag-dialog{border:none;border-radius:var(--radius);padding:1.5rem;max-width:320px;box-shadow:0 25px 50px -12px rgba(0,0,0,.25);margin:auto} 337 + #flag-dialog h3{font-family:'Poppins',system-ui,sans-serif;font-size:1.1rem;font-weight:600;margin-bottom:.5rem} 338 + #flag-dialog p{color:var(--text-muted);font-size:.9rem;margin-bottom:1.25rem} 339 + #flag-dialog::backdrop{background:rgba(0,0,0,.3)} 340 + .flag-dialog-actions{display:flex;gap:.5rem;justify-content:flex-end} 341 + .flag-dialog-actions button{padding:.4rem .9rem;border-radius:4px;font-size:.85rem;cursor:pointer;font-family:'Poppins',system-ui,sans-serif} 336 342 337 343 .meta-link{ 338 344 font-family:'Poppins',system-ui,sans-serif; ··· 376 382 .btn-primary{background:var(--accent);color:#fff;border:none} 377 383 .btn-primary:hover{background:var(--accent-hover);text-decoration:none} 378 384 .btn-secondary{background:var(--surface);color:var(--text);border:1px solid var(--border)} 379 - .btn-secondary:hover{border-color:var(--accent);text-decoration:none} 385 + .btn-secondary:hover{background:var(--btn-hover);text-decoration:none} 380 386 381 387 .error-box{ 382 388 text-align:center;
+23 -1
ui/templates/recipe.html
··· 40 40 {{if .Recipe.CookTime}}<span><svg class="meta-icon" xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> {{fmtDuration .Recipe.CookTime}} cook</span>{{end}} 41 41 {{if .Recipe.Yield}}<span>Serves {{.Recipe.Yield}}</span>{{end}} 42 42 <a href="/cook?url={{.TargetURL | urlquery}}" class="cook-link">.cook</a> 43 - <a href="/flag?url={{.TargetURL | urlquery}}" class="flag-link{{if .IsFlagged}} flagged{{end}}" title="Flag as problematic – saves recipe for review"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528"/></svg></a> 43 + <a href="/flag?url={{.TargetURL | urlquery}}" class="flag-link{{if .IsFlagged}} flagged{{end}}" data-flag-url="/flag?url={{.TargetURL | urlquery}}" title="Flag as problematic – saves recipe for review"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528"/></svg></a> 44 44 </div> 45 45 {{if .Recipe.Description}}<p class="description">{{.Recipe.Description}}</p>{{end}} 46 46 </div> ··· 86 86 <div class="actions"> 87 87 </div> 88 88 89 + <dialog id="flag-dialog"> 90 + <h3>Flag this recipe?</h3> 91 + <p>This recipe will be saved for review.</p> 92 + <div class="flag-dialog-actions"> 93 + <button class="btn-secondary" onclick="document.getElementById('flag-dialog').close()">Cancel</button> 94 + <button class="btn-primary" id="flag-confirm-btn">Flag</button> 95 + </div> 96 + </dialog> 97 + 89 98 <script> 99 + const flagLink = document.querySelector('.flag-link:not(.flagged)'); 100 + const flagDialog = document.getElementById('flag-dialog'); 101 + const flagConfirmBtn = document.getElementById('flag-confirm-btn'); 102 + if (flagLink) { 103 + flagLink.addEventListener('click', function(e) { 104 + e.preventDefault(); 105 + flagDialog.showModal(); 106 + }); 107 + flagConfirmBtn.addEventListener('click', function() { 108 + location.href = flagLink.dataset.flagUrl; 109 + }); 110 + } 111 + 90 112 function toggleCheck(li) { 91 113 const cb = li.querySelector('input[type="checkbox"]'); 92 114 cb.checked = !cb.checked;