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

Configure Feed

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

feat: go back to pills for sorting

authored by

Patrick Dewey and committed by
Tangled
8b73885c a36c723b

+69 -30
+9 -8
internal/web/pages/feed.templ
··· 36 36 {Label: "Brews", Value: "brew"}, 37 37 {Label: "Beans", Value: "bean"}, 38 38 {Label: "Recipes", Value: "recipe"}, 39 - {Label: "Equipment", Value: "equipment"}, 39 + {Label: "Grinders", Value: "grinder"}, 40 + {Label: "Brewers", Value: "brewer"}, 40 41 } 41 42 } 42 43 ··· 110 111 class="mb-5" 111 112 data-type-filter={ qs.TypeFilter } 112 113 data-sort={ qs.Sort } 113 - x-data="{ typeFilter: $el.dataset.typeFilter, sort: $el.dataset.sort, tabClass(tab) { if (this.typeFilter !== tab) return 'feed-tab'; if (!tab) return 'feed-tab-active'; return 'feed-tab-' + tab; }, feedURL(t, s) { let u = '/api/feed', sep = '?'; if (t) { if (t === 'equipment') { u += sep + 'type=grinder&type=brewer'; } else { u += sep + 'type=' + t; } sep = '&'; } if (s) { if (s !== 'recent') { u += sep + 'sort=' + s; } } return u; }, changeFilter(t) { this.typeFilter = t; htmx.ajax('GET', this.feedURL(t, this.sort), {target: '#feed-items', swap: 'outerHTML', select: '#feed-items'}); }, changeSort(s) { this.sort = s; htmx.ajax('GET', this.feedURL(this.typeFilter, s), {target: '#feed-items', swap: 'outerHTML', select: '#feed-items'}); } }" 114 + x-data="{ typeFilter: $el.dataset.typeFilter, sort: $el.dataset.sort, pillClass(tab) { if (this.typeFilter !== tab) return 'filter-pill'; if (!tab) return 'filter-pill-active'; return 'filter-pill-' + tab; }, feedURL(t, s) { let u = '/api/feed', sep = '?'; if (t) { if (t === 'equipment') { u += sep + 'type=grinder&type=brewer'; } else { u += sep + 'type=' + t; } sep = '&'; } if (s) { if (s !== 'recent') { u += sep + 'sort=' + s; } } return u; }, changeFilter(t) { this.typeFilter = t; htmx.ajax('GET', this.feedURL(t, this.sort), {target: '#feed-items', swap: 'outerHTML', select: '#feed-items'}); }, changeSort(s) { this.sort = s; htmx.ajax('GET', this.feedURL(this.typeFilter, s), {target: '#feed-items', swap: 'outerHTML', select: '#feed-items'}); } }" 114 115 > 115 - <div class="flex items-center justify-between gap-4"> 116 - <!-- Type filter tabs --> 117 - <nav class="feed-tabs flex-1" aria-label="Feed filters"> 116 + <div class="flex flex-wrap items-center justify-between gap-2"> 117 + <!-- Type filter pills --> 118 + <div class="flex flex-wrap gap-1" role="tablist" aria-label="Feed filters"> 118 119 for _, tab := range feedFilterTabs() { 119 120 <button 120 - class="feed-tab" 121 - :class="tabClass($el.dataset.tab)" 121 + class="filter-pill" 122 + :class="pillClass($el.dataset.tab)" 122 123 data-tab={ tab.Value } 123 124 @click="changeFilter($el.dataset.tab)" 124 125 > 125 126 { tab.Label } 126 127 </button> 127 128 } 128 - </nav> 129 + </div> 129 130 <!-- Sort selector --> 130 131 <div class="flex items-center gap-1 flex-shrink-0"> 131 132 <button
+1 -1
nix/default.nix
··· 4 4 pname = "arabica"; 5 5 version = "0.1.0"; 6 6 src = ../.; 7 - vendorHash = "sha256-4DVZfuhWcewEddiJIVbtu2Ul8qXpHK9tw18/zl91HCg="; 7 + vendorHash = "sha256-ih1Qf18TyIyfa48FKq9RPokhGmy/4p3oF4fVTFec5HI="; 8 8 9 9 nativeBuildInputs = [ templ tailwindcss ]; 10 10
+59 -21
static/css/app.css
··· 1065 1065 color: var(--rating-text); 1066 1066 } 1067 1067 1068 - /* Feed Tab Bar */ 1069 - .feed-tabs { 1070 - @apply flex items-center gap-1 overflow-x-auto; 1071 - border-bottom: 2px solid var(--card-border); 1072 - } 1073 - 1074 - .feed-tab { 1075 - @apply px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors cursor-pointer; 1068 + /* Filter Pills */ 1069 + .filter-pill { 1070 + @apply inline-flex items-center gap-1.5 px-3 py-1 text-xs font-medium rounded-full transition-all cursor-pointer; 1076 1071 color: var(--text-muted); 1077 - border-bottom: 2px solid transparent; 1078 - margin-bottom: -2px; 1072 + background: transparent; 1073 + border: 1px solid var(--card-border); 1079 1074 } 1080 1075 1081 - .feed-tab:hover { 1076 + .filter-pill:hover { 1082 1077 color: var(--text-secondary); 1078 + border-color: var(--input-border-focus); 1079 + background: var(--surface-bg); 1083 1080 } 1084 1081 1085 - .feed-tab-active { 1086 - @apply px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors cursor-pointer; 1087 - color: var(--text-primary); 1088 - border-bottom: 2px solid var(--btn-primary-bg); 1089 - margin-bottom: -2px; 1082 + /* Type-aware hover */ 1083 + .filter-pill[data-tab="brew"]:hover { border-color: var(--type-brew); color: var(--type-brew); } 1084 + .filter-pill[data-tab="bean"]:hover { border-color: var(--type-bean); color: var(--type-bean); } 1085 + .filter-pill[data-tab="recipe"]:hover { border-color: var(--type-recipe); color: var(--type-recipe); } 1086 + .filter-pill[data-tab="grinder"]:hover { border-color: var(--type-grinder); color: var(--type-grinder); } 1087 + .filter-pill[data-tab="brewer"]:hover { border-color: var(--type-brewer); color: var(--type-brewer); } 1088 + 1089 + .filter-pill-active { 1090 + @apply inline-flex items-center gap-1.5 px-3 py-1 text-xs font-medium rounded-full transition-all cursor-pointer; 1091 + color: var(--btn-primary-text); 1092 + background: var(--btn-primary-bg); 1093 + border: 1px solid var(--btn-primary-bg); 1090 1094 } 1091 1095 1092 - /* Type-colored active tabs */ 1093 - .feed-tab-brew { color: var(--type-brew); border-bottom-color: var(--type-brew); } 1094 - .feed-tab-bean { color: var(--type-bean); border-bottom-color: var(--type-bean); } 1095 - .feed-tab-recipe { color: var(--type-recipe); border-bottom-color: var(--type-recipe); } 1096 - .feed-tab-equipment { color: var(--type-grinder); border-bottom-color: var(--type-grinder); } 1096 + .filter-pill-active:hover { 1097 + background: var(--btn-primary-bg-hover); 1098 + border-color: var(--btn-primary-bg-hover); 1099 + } 1100 + 1101 + /* Type-colored active pills */ 1102 + .filter-pill-brew, 1103 + .filter-pill-bean, 1104 + .filter-pill-recipe, 1105 + .filter-pill-grinder, 1106 + .filter-pill-brewer { 1107 + @apply inline-flex items-center gap-1.5 px-3 py-1 text-xs font-medium rounded-full transition-all cursor-pointer; 1108 + color: var(--btn-primary-text); 1109 + } 1110 + 1111 + .filter-pill-brew { 1112 + background: var(--type-brew); 1113 + border: 1px solid var(--type-brew); 1114 + } 1115 + 1116 + .filter-pill-bean { 1117 + background: var(--type-bean); 1118 + border: 1px solid var(--type-bean); 1119 + } 1120 + 1121 + .filter-pill-recipe { 1122 + background: var(--type-recipe); 1123 + border: 1px solid var(--type-recipe); 1124 + } 1125 + 1126 + .filter-pill-grinder { 1127 + background: var(--type-grinder); 1128 + border: 1px solid var(--type-grinder); 1129 + } 1130 + 1131 + .filter-pill-brewer { 1132 + background: var(--type-brewer); 1133 + border: 1px solid var(--type-brewer); 1134 + } 1097 1135 1098 1136 .feed-sort-btn { 1099 1137 @apply px-3 py-1.5 text-xs font-medium rounded-full transition-all cursor-pointer;