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

Configure Feed

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

feat: nicer bean page styling #2

open opened by pdewey.com targeting main from push-wyqtrtsvtyyy
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:hm5f3dnm6jdhrc55qp2npdja/sh.tangled.repo.pull/3mkm2vnrhn222
+94 -71
Diff #0
+1 -1
internal/web/components/layout.templ
··· 115 115 <link rel="icon" href="/static/favicon.svg" type="image/svg+xml"/> 116 116 <link rel="icon" href="/static/favicon-32.svg" type="image/svg+xml" sizes="32x32"/> 117 117 <link rel="apple-touch-icon" href="/static/icon-192.svg"/> 118 - <link rel="stylesheet" href="/static/css/output.css?v=0.12.0"/> 118 + <link rel="stylesheet" href="/static/css/output.css?v=0.13.0"/> 119 119 <style> 120 120 [x-cloak] { display: none !important; } 121 121 </style>
+3 -1
internal/web/components/shared.templ
··· 155 155 <time datetime={ props.TimestampISO } data-local="long">{ props.Timestamp }</time> 156 156 </div> 157 157 } 158 - <h2 class="record-view-title">{ props.Title }</h2> 158 + if props.Title != "" { 159 + <h2 class="record-view-title">{ props.Title }</h2> 160 + } 159 161 </div> 160 162 } 161 163
+15 -41
internal/web/pages/bean_view.templ
··· 27 27 templ BeanViewCard(props BeanViewProps) { 28 28 @components.RecordViewHeader(components.RecordViewHeaderProps{ 29 29 RecordType: "bean", 30 - Title: beanViewTitle(props.Bean), 30 + Title: "", 31 31 Timestamp: props.Bean.CreatedAt.Format("January 2, 2006 at 3:04 PM"), 32 32 TimestampISO: bff.FormatISO(props.Bean.CreatedAt), 33 33 AuthorDID: props.AuthorDID, ··· 36 36 AuthorAvatar: props.AuthorAvatar, 37 37 }) 38 38 <div class="record-label p-4"> 39 + <h1 class="label-origin-hero">{ beanViewTitle(props.Bean) }</h1> 39 40 if props.Bean.Roaster != nil && props.Bean.Roaster.Name != "" { 40 41 <div class="label-byline"> 41 - <span class="inline-flex items-center gap-1"> 42 - @components.IconStore() 43 - <a href={ templ.SafeURL(fmt.Sprintf("/roasters/%s?owner=%s", props.Bean.Roaster.RKey, getOwnerFromShareURL(props.ShareURL))) }> 44 - { props.Bean.Roaster.Name } 45 - </a> 46 - if props.Bean.Roaster.Location != "" { 47 - <span class="text-faint">·</span> 48 - <span class="inline-flex items-center gap-1"> 49 - @components.IconMapPin() 50 - { props.Bean.Roaster.Location } 51 - </span> 52 - } 53 - </span> 42 + <a href={ templ.SafeURL(fmt.Sprintf("/roasters/%s?owner=%s", props.Bean.Roaster.RKey, getOwnerFromShareURL(props.ShareURL))) }> 43 + { props.Bean.Roaster.Name } 44 + </a> 45 + if props.Bean.Roaster.Location != "" { 46 + <span class="text-faint"> · { props.Bean.Roaster.Location }</span> 47 + } 54 48 </div> 55 49 } 56 50 if props.Bean.Rating != nil { 57 - <div class="brew-rating-hero mt-4"> 51 + <div class="brew-rating-hero mt-5"> 58 52 <span class="brew-rating-value">{ fmt.Sprintf("%d", *props.Bean.Rating) }</span> 59 - <span class="brew-rating-max">/10</span> 53 + <span class="brew-rating-max">/ 10</span> 60 54 </div> 61 55 } 62 56 <div class="label-tags"> 63 57 if props.Bean.Origin != "" { 64 - <span class="label-tag"> 65 - <span class="inline-flex items-center gap-1"> 66 - @components.IconMapPin() 67 - { props.Bean.Origin } 68 - </span> 69 - </span> 58 + <span class="label-tag">{ props.Bean.Origin }</span> 70 59 } 71 60 if props.Bean.Variety != "" { 72 - <span class="label-tag"> 73 - <span class="inline-flex items-center gap-1"> 74 - @components.IconLeaf() 75 - { props.Bean.Variety } 76 - </span> 77 - </span> 61 + <span class="label-tag">{ props.Bean.Variety }</span> 78 62 } 79 63 if props.Bean.RoastLevel != "" { 80 - <span class="label-tag"> 81 - <span class="inline-flex items-center gap-1"> 82 - @components.IconFlame() 83 - { props.Bean.RoastLevel } 84 - </span> 85 - </span> 64 + <span class="label-tag">{ props.Bean.RoastLevel }</span> 86 65 } 87 66 if props.Bean.Process != "" { 88 - <span class="label-tag"> 89 - <span class="inline-flex items-center gap-1"> 90 - @components.IconSprout() 91 - { props.Bean.Process } 92 - </span> 93 - </span> 67 + <span class="label-tag">{ props.Bean.Process }</span> 94 68 } 95 69 if props.Bean.Closed { 96 - <span class="label-tag" style="border-color: var(--text-muted)">Closed</span> 70 + <span class="label-tag label-tag-closed">Closed</span> 97 71 } 98 72 </div> 99 73 if props.Bean.Description != "" {
+14 -11
internal/web/pages/brew_view.templ
··· 48 48 templ BrewViewCard(props BrewViewProps) { 49 49 @components.RecordViewHeader(components.RecordViewHeaderProps{ 50 50 RecordType: "brew", 51 - Title: "Brew Details", 51 + Title: getBrewShareTitle(props.Brew), 52 52 Timestamp: props.Brew.CreatedAt.Format("January 2, 2006 at 3:04 PM"), 53 53 TimestampISO: bff.FormatISO(props.Brew.CreatedAt), 54 54 AuthorDID: props.AuthorDID, ··· 60 60 @BrewSummary(props.Brew) 61 61 @BrewBeanSection(props.Brew, getOwnerFromShareURL(props.ShareURL)) 62 62 <div class="my-6"> 63 + <div class="ledger-section">Inputs</div> 63 64 @components.JournalField(components.DetailStackedProps{Icon: components.IconScale(), Label: "Coffee", Value: getCoffeeAmountDisplay(props.Brew)}) 64 - @components.JournalField(components.DetailStackedProps{Icon: components.IconCoffee(), Label: "Brew Method", Value: getBrewerName(props.Brew), LinkHref: getBrewerViewURL(props.Brew, getOwnerFromShareURL(props.ShareURL))}) 65 + @components.JournalField(components.DetailStackedProps{Icon: components.IconDroplet(), Label: "Water", Value: getWaterAmountDisplay(props.Brew)}) 65 66 @components.JournalField(components.DetailStackedProps{Icon: components.IconGear(), Label: "Grinder", Value: getGrinderName(props.Brew), LinkHref: getGrinderViewURL(props.Brew, getOwnerFromShareURL(props.ShareURL))}) 66 67 @components.JournalField(components.DetailStackedProps{Icon: components.IconDisc(), Label: "Grind Size", Value: getGrindSizeDisplay(props.Brew)}) 67 - @components.JournalField(components.DetailStackedProps{Icon: components.IconDroplet(), Label: "Water", Value: getWaterAmountDisplay(props.Brew)}) 68 68 @components.JournalField(components.DetailStackedProps{Icon: components.IconThermometer(), Label: "Temperature", Value: getTemperatureDisplay(props.Brew)}) 69 + if props.Brew.PouroverParams != nil && props.Brew.PouroverParams.Filter != "" { 70 + @components.JournalField(components.DetailStackedProps{Icon: components.IconSliders(), Label: "Filter", Value: props.Brew.PouroverParams.Filter}) 71 + } 72 + <div class="ledger-section">Process</div> 73 + @components.JournalField(components.DetailStackedProps{Icon: components.IconCoffee(), Label: "Brew Method", Value: getBrewerName(props.Brew), LinkHref: getBrewerViewURL(props.Brew, getOwnerFromShareURL(props.ShareURL))}) 69 74 @components.JournalField(components.DetailStackedProps{Icon: components.IconClock(), Label: "Brew Time", Value: getBrewTimeDisplay(props.Brew)}) 70 75 if props.Brew.EspressoParams != nil { 71 - if props.Brew.EspressoParams.YieldWeight > 0 { 72 - @components.JournalField(components.DetailStackedProps{Icon: components.IconScale(), Label: "Yield", Value: fmt.Sprintf("%.1fg", props.Brew.EspressoParams.YieldWeight)}) 76 + if props.Brew.EspressoParams.PreInfusionSeconds > 0 { 77 + @components.JournalField(components.DetailStackedProps{Icon: components.IconClock(), Label: "Pre-infusion", Value: fmt.Sprintf("%ds", props.Brew.EspressoParams.PreInfusionSeconds)}) 73 78 } 74 79 if props.Brew.EspressoParams.Pressure > 0 { 75 80 @components.JournalField(components.DetailStackedProps{Icon: components.IconBarChart(), Label: "Pressure", Value: fmt.Sprintf("%.1f bar", props.Brew.EspressoParams.Pressure)}) 76 81 } 77 - if props.Brew.EspressoParams.PreInfusionSeconds > 0 { 78 - @components.JournalField(components.DetailStackedProps{Icon: components.IconClock(), Label: "Pre-infusion", Value: fmt.Sprintf("%ds", props.Brew.EspressoParams.PreInfusionSeconds)}) 79 - } 80 82 } 81 83 if props.Brew.PouroverParams != nil { 82 84 if props.Brew.PouroverParams.BloomWater > 0 || props.Brew.PouroverParams.BloomSeconds > 0 { ··· 88 90 if props.Brew.PouroverParams.BypassWater > 0 { 89 91 @components.JournalField(components.DetailStackedProps{Icon: components.IconDroplet(), Label: "Bypass Water", Value: fmt.Sprintf("%dg", props.Brew.PouroverParams.BypassWater)}) 90 92 } 91 - if props.Brew.PouroverParams.Filter != "" { 92 - @components.JournalField(components.DetailStackedProps{Icon: components.IconSliders(), Label: "Filter", Value: props.Brew.PouroverParams.Filter}) 93 - } 93 + } 94 + if props.Brew.EspressoParams != nil && props.Brew.EspressoParams.YieldWeight > 0 { 95 + <div class="ledger-section">Output</div> 96 + @components.JournalField(components.DetailStackedProps{Icon: components.IconScale(), Label: "Yield", Value: fmt.Sprintf("%.1fg", props.Brew.EspressoParams.YieldWeight)}) 94 97 } 95 98 </div> 96 99 <div class="space-y-6">
+12 -10
internal/web/pages/recipe_view.templ
··· 55 55 AuthorAvatar: props.AuthorAvatar, 56 56 }) 57 57 if props.SourceRecipeURL != "" { 58 - <p class="text-sm text-brown-500 -mt-4 mb-4"> 59 - Forked from&#32; 60 - <a href={ templ.SafeURL(props.SourceRecipeURL) } class="text-brown-700 underline hover:text-brown-900"> 61 - if props.SourceRecipeAuthor != "" { 62 - { props.SourceRecipeAuthor + "'s recipe" } 63 - } else { 64 - original recipe 65 - } 66 - </a> 67 - </p> 58 + <div class="-mt-3"> 59 + <span class="fork-chip"> 60 + ↳ forked from&#32; 61 + <a href={ templ.SafeURL(props.SourceRecipeURL) }> 62 + if props.SourceRecipeAuthor != "" { 63 + { props.SourceRecipeAuthor + "'s recipe" } 64 + } else { 65 + original recipe 66 + } 67 + </a> 68 + </span> 69 + </div> 68 70 } 69 71 <div class="record-journal p-4"> 70 72 <div>
+49 -7
static/css/app.css
··· 538 538 /* Record view — tinted header region */ 539 539 .record-view-header { 540 540 @apply -mx-6 -mt-6 px-6 pt-5 pb-4 mb-6 rounded-t-xl; 541 + border-bottom: 1px solid var(--surface-border); 541 542 } 542 543 543 544 .record-view-header-brew { ··· 669 670 } 670 671 671 672 .brew-rating-value { 672 - @apply text-4xl font-bold tracking-tight; 673 + @apply font-bold tracking-tight leading-none; 674 + font-size: clamp(3.25rem, 6vw + 1rem, 4.5rem); 673 675 color: var(--rating-text); 674 676 } 675 677 676 678 .brew-rating-max { 677 - @apply text-lg font-medium; 679 + @apply text-xs font-medium uppercase tracking-wider self-end pb-1; 678 680 color: var(--text-muted); 679 681 } 680 682 ··· 722 724 } 723 725 } 724 726 727 + /* Section heading inside the journal ledger — separates Inputs/Process/Output */ 728 + .ledger-section { 729 + @apply text-xs font-semibold uppercase mt-7 mb-1 pb-1; 730 + letter-spacing: 0.18em; 731 + color: var(--text-muted); 732 + border-bottom: 1px solid var(--surface-border); 733 + } 734 + .ledger-section:first-child { 735 + @apply mt-0; 736 + } 737 + 738 + /* Kraft tape chip — used for recipe fork provenance */ 739 + .fork-chip { 740 + @apply inline-flex items-center gap-1 text-xs font-medium px-3 py-1 mb-5; 741 + background-color: var(--kraft-bg); 742 + background-image: var(--texture-kraft); 743 + color: var(--text-secondary); 744 + border: 1px solid var(--surface-border); 745 + border-radius: 2px; 746 + transform: rotate(-1.25deg); 747 + box-shadow: var(--shadow-sm); 748 + } 749 + .fork-chip a { 750 + color: var(--text-primary); 751 + text-decoration: underline; 752 + text-decoration-color: var(--text-faint); 753 + text-underline-offset: 2px; 754 + } 755 + .fork-chip a:hover { 756 + text-decoration-color: var(--text-muted); 757 + } 758 + 725 759 /* Pour rows: shared by brew and recipe views */ 726 760 .pour-row { 727 761 @apply flex gap-4 text-sm py-2; ··· 778 812 color: var(--text-primary); 779 813 } 780 814 781 - /* Inline tag strip: variety / process / roast level */ 815 + /* Inline tag strip: variety / process / roast level — stamp marks, not pills */ 782 816 .label-tags { 783 - @apply flex flex-wrap gap-2 mt-4; 817 + @apply flex flex-wrap gap-x-3 gap-y-2 mt-5; 784 818 } 785 819 786 820 .label-tag { 787 - @apply text-xs font-medium px-2.5 py-1 rounded-full; 788 - background: var(--surface-bg); 821 + @apply text-[0.7rem] font-semibold uppercase px-2.5 py-1; 822 + letter-spacing: 0.14em; 823 + background: transparent; 789 824 color: var(--text-secondary); 790 - border: 1px solid var(--surface-border); 825 + border: 1px solid var(--text-muted); 826 + border-radius: 2px; 827 + } 828 + 829 + .label-tag-closed { 830 + color: var(--text-muted); 831 + border-color: var(--text-faint); 832 + border-style: dashed; 791 833 } 792 834 793 835 /* Description on a label — flowing paragraph, no indent */

History

1 round 0 comments
sign up or login to add to the discussion
pdewey.com submitted #0
1 commit
expand
feat: nicer bean page styling
merge conflicts detected
expand
  • internal/web/components/layout.templ:115
  • internal/web/components/shared.templ:218
  • internal/web/pages/bean_view.templ:53
  • internal/web/pages/brew_view.templ:56
  • internal/web/pages/brewer_view.templ:53
  • internal/web/pages/grinder_view.templ:53
  • internal/web/pages/recipe_view.templ:66
  • internal/web/pages/roaster_view.templ:53
  • static/css/app.css:561
expand 0 comments