Coffee journaling on ATProto (alpha) alpha.arabica.social
coffee

feat: show variety in brew card

pdewey.com 6c3c2b12 11c8ac0b

verified
+58 -86
+4 -28
internal/web/components/profile_brew_card.templ
··· 126 126 <!-- Bean info with rating --> 127 127 <div class="flex items-start justify-between gap-3 mb-3"> 128 128 <div class="flex-1 min-w-0"> 129 - if brew.Bean != nil { 130 - <div class="font-bold text-brown-900 text-base"> 131 - if brew.Bean.Name != "" { 132 - { brew.Bean.Name } 133 - } else { 134 - { brew.Bean.Origin } 135 - } 136 - </div> 137 - if brew.Bean.Roaster != nil && brew.Bean.Roaster.Name != "" { 138 - <div class="text-sm text-brown-700 mt-0.5"> 139 - <span class="font-medium">๐Ÿญ { brew.Bean.Roaster.Name }</span> 140 - </div> 141 - } 142 - <div class="text-xs text-brown-600 mt-1 flex flex-wrap gap-x-2 gap-y-0.5"> 143 - if brew.Bean.Origin != "" { 144 - <span class="inline-flex items-center gap-0.5">๐Ÿ“ { brew.Bean.Origin }</span> 145 - } 146 - if brew.Bean.RoastLevel != "" { 147 - <span class="inline-flex items-center gap-0.5">๐Ÿ”ฅ { brew.Bean.RoastLevel }</span> 148 - } 149 - if brew.Bean.Process != "" { 150 - <span class="inline-flex items-center gap-0.5">๐ŸŒฑ { brew.Bean.Process }</span> 151 - } 152 - if brew.CoffeeAmount > 0 { 153 - <span class="inline-flex items-center gap-0.5">โš–๏ธ { fmt.Sprintf("%dg", brew.CoffeeAmount) }</span> 154 - } 155 - </div> 156 - } 129 + @BeanSummary(BeanSummaryProps{ 130 + Bean: brew.Bean, 131 + CoffeeAmount: brew.CoffeeAmount, 132 + }) 157 133 </div> 158 134 if brew.Rating > 0 { 159 135 <span class="badge-rating">
+47 -1
internal/web/components/shared.templ
··· 1 1 package components 2 2 3 - import "arabica/internal/web/bff" 3 + import ( 4 + "arabica/internal/models" 5 + "arabica/internal/web/bff" 6 + "fmt" 7 + ) 8 + 9 + // BeanSummaryProps defines props for displaying bean metadata inline. 10 + // Used in both bean feed cards and brew feed cards. 11 + type BeanSummaryProps struct { 12 + Bean *models.Bean 13 + CoffeeAmount int // if > 0, shows "โš–๏ธ Xg" (brew context) 14 + } 15 + 16 + // BeanSummary renders the bean name, roaster, and attribute tags. 17 + templ BeanSummary(props BeanSummaryProps) { 18 + if props.Bean != nil { 19 + <div class="font-bold text-brown-900 text-base"> 20 + if props.Bean.Name != "" { 21 + { props.Bean.Name } 22 + } else { 23 + { props.Bean.Origin } 24 + } 25 + </div> 26 + if props.Bean.Roaster != nil && props.Bean.Roaster.Name != "" { 27 + <div class="text-sm text-brown-700 mt-0.5"> 28 + <span class="font-medium">๐Ÿญ { props.Bean.Roaster.Name }</span> 29 + </div> 30 + } 31 + <div class="text-xs text-brown-600 mt-1 flex flex-wrap gap-x-2 gap-y-0.5"> 32 + if props.Bean.Origin != "" { 33 + <span class="inline-flex items-center gap-0.5">๐Ÿ“ { props.Bean.Origin }</span> 34 + } 35 + if props.Bean.RoastLevel != "" { 36 + <span class="inline-flex items-center gap-0.5">๐Ÿ”ฅ { props.Bean.RoastLevel }</span> 37 + } 38 + if props.Bean.Variety != "" { 39 + <span class="inline-flex items-center gap-0.5">๐ŸŒฟ { props.Bean.Variety }</span> 40 + } 41 + if props.Bean.Process != "" { 42 + <span class="inline-flex items-center gap-0.5">๐ŸŒฑ { props.Bean.Process }</span> 43 + } 44 + if props.CoffeeAmount > 0 { 45 + <span class="inline-flex items-center gap-0.5">โš–๏ธ { fmt.Sprintf("%dg", props.CoffeeAmount) }</span> 46 + } 47 + </div> 48 + } 49 + } 4 50 5 51 // EmptyStateProps defines properties for empty state messaging 6 52 type EmptyStateProps struct {
+7 -57
internal/web/pages/feed.templ
··· 319 319 <!-- Bean info with rating --> 320 320 <div class="flex items-start justify-between gap-3 mb-3"> 321 321 <div class="flex-1 min-w-0"> 322 - if item.Brew.Bean != nil { 323 - <div class="font-bold text-brown-900 text-base"> 324 - if item.Brew.Bean.Name != "" { 325 - { item.Brew.Bean.Name } 326 - } else { 327 - { item.Brew.Bean.Origin } 328 - } 329 - </div> 330 - if item.Brew.Bean.Roaster != nil && item.Brew.Bean.Roaster.Name != "" { 331 - <div class="text-sm text-brown-700 mt-0.5"> 332 - <span class="font-medium">๐Ÿญ { item.Brew.Bean.Roaster.Name }</span> 333 - </div> 334 - } 335 - // TODO: can we share code with the bean card here? (and the roaster?) 336 - <div class="text-xs text-brown-600 mt-1 flex flex-wrap gap-x-2 gap-y-0.5"> 337 - if item.Brew.Bean.Origin != "" { 338 - <span class="inline-flex items-center gap-0.5">๐Ÿ“ { item.Brew.Bean.Origin }</span> 339 - } 340 - if item.Brew.Bean.RoastLevel != "" { 341 - <span class="inline-flex items-center gap-0.5">๐Ÿ”ฅ { item.Brew.Bean.RoastLevel }</span> 342 - } 343 - if item.Brew.Bean.Process != "" { 344 - <span class="inline-flex items-center gap-0.5">๐ŸŒฑ { item.Brew.Bean.Process }</span> 345 - } 346 - if item.Brew.CoffeeAmount > 0 { 347 - <span class="inline-flex items-center gap-0.5">โš–๏ธ { fmt.Sprintf("%dg", item.Brew.CoffeeAmount) }</span> 348 - } 349 - </div> 350 - } 322 + @components.BeanSummary(components.BeanSummaryProps{ 323 + Bean: item.Brew.Bean, 324 + CoffeeAmount: item.Brew.CoffeeAmount, 325 + }) 351 326 </div> 352 327 if item.Brew.Rating > 0 { 353 328 <span class="badge-rating"> ··· 419 394 templ FeedBeanContent(item *feed.FeedItem) { 420 395 if item.Bean != nil { 421 396 <div class="feed-content-box-sm"> 422 - <div class="mb-2"> 423 - <div class="font-bold text-brown-900 text-base"> 424 - if item.Bean.Name != "" { 425 - { item.Bean.Name } 426 - } else { 427 - { item.Bean.Origin } 428 - } 429 - </div> 430 - if item.Bean.Roaster != nil && item.Bean.Roaster.Name != "" { 431 - <div class="text-sm text-brown-700 mt-0.5"> 432 - <span class="font-medium">๐Ÿญ { item.Bean.Roaster.Name }</span> 433 - </div> 434 - } 435 - </div> 436 - <div class="text-xs text-brown-600 mt-1 flex flex-wrap gap-x-2 gap-y-0.5"> 437 - if item.Bean.Origin != "" { 438 - <span class="inline-flex items-center gap-0.5">๐Ÿ“ { item.Bean.Origin }</span> 439 - } 440 - if item.Bean.Variety != "" { 441 - <span class="inline-flex items-center gap-0.5">๐ŸŒฟ { item.Bean.Variety }</span> 442 - } 443 - if item.Bean.RoastLevel != "" { 444 - <span class="inline-flex items-center gap-0.5">๐Ÿ”ฅ { item.Bean.RoastLevel }</span> 445 - } 446 - if item.Bean.Process != "" { 447 - <span class="inline-flex items-center gap-0.5">๐ŸŒฑ { item.Bean.Process }</span> 448 - } 449 - </div> 397 + @components.BeanSummary(components.BeanSummaryProps{ 398 + Bean: item.Bean, 399 + }) 450 400 if item.Bean.Description != "" { 451 401 <div class="mt-2 text-sm text-brown-800 italic">"{ item.Bean.Description }"</div> 452 402 }