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: styling improvements

pdewey 96135df5 be9d9ae9

+473 -428
+7
flake.nix
··· 21 21 type = "app"; 22 22 program = "${self.packages.${system}.arabica}/bin/arabica"; 23 23 }; 24 + tailwind = { 25 + type = "app"; 26 + program = toString (pkgs.writeShellScript "tailwind-build" '' 27 + cd ${./.} 28 + ${pkgs.tailwindcss}/bin/tailwindcss -i web/static/css/style.css -o web/static/css/output.css --minify 29 + ''); 30 + }; 24 31 }); 25 32 26 33 nixosModules.default = import ./module.nix;
+2 -1
justfile
··· 8 8 @go test ./... -cover -coverprofile=cover.out 9 9 10 10 style: 11 - @tailwindcss -i web/static/css/style.css -o web/static/css/output.css --minify 11 + @nix develop --command tailwindcss -i web/static/css/style.css -o web/static/css/output.css --minify 12 + # @tailwindcss -i web/static/css/style.css -o web/static/css/output.css --minify
+12
tailwind.config.js
··· 16 16 800: "#4a2c2a", 17 17 900: "#3d2319", 18 18 }, 19 + amber: { 20 + 50: "#fffbeb", 21 + 100: "#fef3c7", 22 + 200: "#fde68a", 23 + 300: "#fcd34d", 24 + 400: "#fbbf24", 25 + 500: "#f59e0b", 26 + 600: "#d97706", 27 + 700: "#b45309", 28 + 800: "#92400e", 29 + 900: "#78350f", 30 + }, 19 31 }, 20 32 }, 21 33 },
+5 -5
templates/404.tmpl
··· 1 1 {{define "content"}} 2 2 <div class="max-w-4xl mx-auto"> 3 - <div class="bg-white rounded-lg shadow-md p-8 text-center"> 4 - <div class="text-6xl mb-4">404</div> 5 - <h2 class="text-2xl font-bold text-gray-800 mb-4">Page Not Found</h2> 6 - <p class="text-gray-600 mb-6">The page you're looking for doesn't exist or has been moved.</p> 7 - <a href="/" class="inline-block bg-brown-600 text-white py-3 px-6 rounded-lg hover:bg-brown-700 transition"> 3 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-xl p-8 text-center border border-brown-300"> 4 + <div class="text-6xl mb-4 font-bold text-brown-800">404</div> 5 + <h2 class="text-2xl font-bold text-brown-900 mb-4">Page Not Found</h2> 6 + <p class="text-brown-700 mb-6">The page you're looking for doesn't exist or has been moved.</p> 7 + <a href="/" class="inline-block bg-gradient-to-r from-brown-700 to-brown-800 text-white py-3 px-6 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all font-medium shadow-lg hover:shadow-xl"> 8 8 Back to Home 9 9 </a> 10 10 </div>
+35 -35
templates/about.tmpl
··· 3 3 {{define "content"}} 4 4 <div class="max-w-3xl mx-auto"> 5 5 <div class="flex items-center gap-3 mb-8"> 6 - <h1 class="text-4xl font-bold text-brown-800">About Arabica</h1> 7 - <span class="text-sm bg-yellow-500 text-brown-900 px-3 py-1 rounded font-semibold">ALPHA</span> 6 + <h1 class="text-4xl font-bold text-brown-900">About Arabica</h1> 7 + <span class="text-sm bg-amber-400 text-brown-900 px-3 py-1 rounded-md font-semibold shadow-sm">ALPHA</span> 8 8 </div> 9 9 10 - <div class="bg-yellow-50 border-l-4 border-yellow-500 p-4 mb-6"> 11 - <p class="text-sm text-gray-700"> 10 + <div class="bg-amber-50 border-l-4 border-amber-400 p-4 mb-6 rounded-r-lg"> 11 + <p class="text-sm text-brown-800"> 12 12 <strong>Alpha Software:</strong> Arabica is currently in early development. Features may change, and data structures could be modified in future updates. 13 13 </p> 14 14 </div> 15 15 16 16 <div class="prose prose-lg max-w-none space-y-6"> 17 17 <section> 18 - <h2 class="text-2xl font-semibold text-brown-800 mb-4">Your Coffee Journey, Your Data</h2> 19 - <p class="text-gray-700 leading-relaxed"> 18 + <h2 class="text-2xl font-semibold text-brown-900 mb-4">Your Coffee Journey, Your Data</h2> 19 + <p class="text-brown-800 leading-relaxed"> 20 20 Arabica is a coffee brew tracking application built on the AT Protocol, a decentralized social networking protocol. 21 21 Unlike traditional apps where your data is locked in a company's database, Arabica stores your brew logs, 22 22 coffee beans, and equipment information in <strong>your own Personal Data Server (PDS)</strong>. 23 23 </p> 24 24 </section> 25 25 26 - <section class="bg-brown-50 p-6 rounded-lg"> 27 - <h3 class="text-xl font-semibold text-brown-800 mb-3">What Makes Arabica Different?</h3> 28 - <ul class="list-disc list-inside space-y-2 text-gray-700"> 26 + <section class="bg-gradient-to-br from-brown-100 to-brown-200 p-6 rounded-xl border border-brown-300"> 27 + <h3 class="text-xl font-semibold text-brown-900 mb-3">What Makes Arabica Different?</h3> 28 + <ul class="list-disc list-inside space-y-2 text-brown-800"> 29 29 <li><strong>You own your data</strong> - All your brew logs live in your PDS, not our servers</li> 30 30 <li><strong>Portable identity</strong> - Switch PDS providers anytime without losing your data</li> 31 31 <li><strong>Privacy by design</strong> - You control who sees your brews</li> ··· 34 34 </section> 35 35 36 36 <section> 37 - <h2 class="text-2xl font-semibold text-brown-800 mb-4">Features</h2> 37 + <h2 class="text-2xl font-semibold text-brown-900 mb-4">Features</h2> 38 38 <div class="grid md:grid-cols-2 gap-4"> 39 - <div class="bg-white border border-gray-200 p-4 rounded-lg"> 40 - <h4 class="font-semibold text-brown-800 mb-2">Track Your Brews</h4> 41 - <p class="text-gray-600 text-sm">Log every detail: beans, grind size, water temp, brew time, and tasting notes</p> 39 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 border border-brown-200 p-4 rounded-lg shadow-md"> 40 + <h4 class="font-semibold text-brown-900 mb-2">Track Your Brews</h4> 41 + <p class="text-brown-700 text-sm">Log every detail: beans, grind size, water temp, brew time, and tasting notes</p> 42 42 </div> 43 - <div class="bg-white border border-gray-200 p-4 rounded-lg"> 44 - <h4 class="font-semibold text-brown-800 mb-2">Manage Equipment</h4> 45 - <p class="text-gray-600 text-sm">Keep track of your grinders, brewers, beans, and roasters</p> 43 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 border border-brown-200 p-4 rounded-lg shadow-md"> 44 + <h4 class="font-semibold text-brown-900 mb-2">Manage Equipment</h4> 45 + <p class="text-brown-700 text-sm">Keep track of your grinders, brewers, beans, and roasters</p> 46 46 </div> 47 - <div class="bg-white border border-gray-200 p-4 rounded-lg"> 48 - <h4 class="font-semibold text-brown-800 mb-2">Community Feed</h4> 49 - <p class="text-gray-600 text-sm">Share your best brews with the community (coming soon: likes and comments!)</p> 47 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 border border-brown-200 p-4 rounded-lg shadow-md"> 48 + <h4 class="font-semibold text-brown-900 mb-2">Community Feed</h4> 49 + <p class="text-brown-700 text-sm">Share your best brews with the community (coming soon: likes and comments!)</p> 50 50 </div> 51 - <div class="bg-white border border-gray-200 p-4 rounded-lg"> 52 - <h4 class="font-semibold text-brown-800 mb-2">Export Your Data</h4> 53 - <p class="text-gray-600 text-sm">Export all your brews anytime in JSON format</p> 51 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 border border-brown-200 p-4 rounded-lg shadow-md"> 52 + <h4 class="font-semibold text-brown-900 mb-2">Export Your Data</h4> 53 + <p class="text-brown-700 text-sm">Export all your brews anytime in JSON format</p> 54 54 </div> 55 55 </div> 56 56 </section> 57 57 58 58 <section> 59 - <h2 class="text-2xl font-semibold text-brown-800 mb-4">The AT Protocol Advantage</h2> 60 - <p class="text-gray-700 leading-relaxed"> 59 + <h2 class="text-2xl font-semibold text-brown-900 mb-4">The AT Protocol Advantage</h2> 60 + <p class="text-brown-800 leading-relaxed"> 61 61 The AT Protocol is a decentralized social networking protocol that gives users true ownership of their data 62 62 and identity. When you use Arabica: 63 63 </p> 64 - <ul class="list-disc list-inside space-y-2 text-gray-700 mt-3"> 64 + <ul class="list-disc list-inside space-y-2 text-brown-800 mt-3"> 65 65 <li>Your brew data is stored as ATProto records in collections on your PDS</li> 66 66 <li>You authenticate via OAuth with your PDS, not with us</li> 67 67 <li>References between records (like linking a brew to a bean) use AT-URIs</li> ··· 69 69 </ul> 70 70 </section> 71 71 72 - <section class="bg-blue-50 border border-blue-200 p-6 rounded-lg"> 73 - <h3 class="text-xl font-semibold text-blue-900 mb-3">Getting Started</h3> 74 - <p class="text-gray-700 mb-4"> 72 + <section class="bg-gradient-to-br from-amber-50 to-brown-100 border-2 border-brown-300 p-6 rounded-xl shadow-lg"> 73 + <h3 class="text-xl font-semibold text-brown-900 mb-3">Getting Started</h3> 74 + <p class="text-brown-800 mb-4"> 75 75 To use Arabica, you'll need an account on a PDS that supports the AT Protocol. 76 - The easiest way is to create a Bluesky account at <a href="https://bsky.app" class="text-blue-600 hover:underline" target="_blank" rel="noopener noreferrer">bsky.app</a>. 76 + The easiest way is to create a Bluesky account at <a href="https://bsky.app" class="text-brown-700 hover:underline font-medium" target="_blank" rel="noopener noreferrer">bsky.app</a>. 77 77 </p> 78 - <p class="text-gray-700"> 78 + <p class="text-brown-800"> 79 79 Once you have an account, simply log in with your handle (e.g., yourname.bsky.social) and start tracking your brews! 80 80 </p> 81 81 </section> 82 82 83 83 <section> 84 - <h2 class="text-2xl font-semibold text-brown-800 mb-4">Open Source</h2> 85 - <p class="text-gray-700 leading-relaxed"> 84 + <h2 class="text-2xl font-semibold text-brown-900 mb-4">Open Source</h2> 85 + <p class="text-brown-800 leading-relaxed"> 86 86 Arabica is open source software. You can view the code, contribute, or even run your own instance. 87 - Visit our <a href="https://github.com/ptdewey/arabica" class="text-blue-600 hover:underline" target="_blank" rel="noopener noreferrer">GitHub repository</a> to learn more. 87 + Visit our <a href="https://github.com/ptdewey/arabica" class="text-brown-700 hover:underline font-medium" target="_blank" rel="noopener noreferrer">GitHub repository</a> to learn more. 88 88 </p> 89 89 </section> 90 90 </div> 91 91 92 92 <div class="mt-12 text-center"> 93 93 {{if not .IsAuthenticated}} 94 - <a href="/login" class="inline-block bg-brown-800 text-white px-8 py-3 rounded-lg hover:bg-brown-700 transition-colors font-semibold"> 94 + <a href="/login" class="inline-block bg-gradient-to-r from-brown-700 to-brown-800 text-white px-8 py-3 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all font-semibold shadow-lg hover:shadow-xl"> 95 95 Get Started 96 96 </a> 97 97 {{else}} 98 - <a href="/brews/new" class="inline-block bg-brown-800 text-white px-8 py-3 rounded-lg hover:bg-brown-700 transition-colors font-semibold"> 98 + <a href="/brews/new" class="inline-block bg-gradient-to-r from-brown-700 to-brown-800 text-white px-8 py-3 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all font-semibold shadow-lg hover:shadow-xl"> 99 99 Log Your Next Brew 100 100 </a> 101 101 {{end}}
+39 -39
templates/brew_form.tmpl
··· 2 2 <script src="/static/js/brew-form.js"></script> 3 3 4 4 <div class="max-w-2xl mx-auto"> 5 - <div class="bg-white rounded-lg shadow-md p-8"> 6 - <h2 class="text-3xl font-bold text-gray-800 mb-6"> 5 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-xl p-8 border border-brown-300"> 6 + <h2 class="text-3xl font-bold text-brown-900 mb-6"> 7 7 {{if .Brew}}Edit Brew{{else}}New Brew{{end}} 8 8 </h2> 9 9 ··· 22 22 23 23 <!-- Bean Selection --> 24 24 <div> 25 - <label class="block text-sm font-medium text-gray-700 mb-2">Coffee Bean</label> 25 + <label class="block text-sm font-medium text-brown-900 mb-2">Coffee Bean</label> 26 26 <div class="flex gap-2"> 27 27 <select 28 28 name="bean_rkey" 29 29 required 30 - class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4 truncate max-w-full"> 30 + class="flex-1 rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 truncate max-w-full bg-white"> 31 31 <option value="">Select a bean...</option> 32 32 {{if .Beans}} 33 33 {{range .Beans}} ··· 46 46 <button 47 47 type="button" 48 48 @click="showNewBean = true" 49 - class="bg-gray-200 text-gray-700 px-4 py-2 rounded hover:bg-gray-300"> 49 + class="bg-brown-300 text-brown-900 px-4 py-2 rounded-lg hover:bg-brown-400 font-medium transition-colors"> 50 50 + New 51 51 </button> 52 52 </div> ··· 56 56 57 57 <!-- Coffee Amount --> 58 58 <div> 59 - <label class="block text-sm font-medium text-gray-700 mb-2">Coffee Amount (grams)</label> 59 + <label class="block text-sm font-medium text-brown-900 mb-2">Coffee Amount (grams)</label> 60 60 <input 61 61 type="number" 62 62 name="coffee_amount" 63 63 step="0.1" 64 64 {{if and .Brew (gt .Brew.CoffeeAmount 0)}}value="{{.Brew.CoffeeAmount}}"{{end}} 65 65 placeholder="e.g. 18" 66 - class="w-full rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4"/> 67 - <p class="text-sm text-gray-500 mt-1">Amount of ground coffee used</p> 66 + class="w-full rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 bg-white"/> 67 + <p class="text-sm text-brown-700 mt-1">Amount of ground coffee used</p> 68 68 </div> 69 69 70 70 <!-- Grinder --> 71 71 <div> 72 - <label class="block text-sm font-medium text-gray-700 mb-2">Grinder</label> 72 + <label class="block text-sm font-medium text-brown-900 mb-2">Grinder</label> 73 73 <div class="flex gap-2"> 74 74 <select 75 75 name="grinder_rkey" 76 - class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4 truncate max-w-full"> 76 + class="flex-1 rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 truncate max-w-full bg-white"> 77 77 <option value="">Select a grinder...</option> 78 78 {{if .Grinders}} 79 79 {{range .Grinders}} ··· 92 92 <button 93 93 type="button" 94 94 @click="showNewGrinder = true" 95 - class="bg-gray-200 text-gray-700 px-4 py-2 rounded hover:bg-gray-300"> 95 + class="bg-brown-300 text-brown-900 px-4 py-2 rounded-lg hover:bg-brown-400 font-medium transition-colors"> 96 96 + New 97 97 </button> 98 98 </div> ··· 102 102 103 103 <!-- Grind Size --> 104 104 <div> 105 - <label class="block text-sm font-medium text-gray-700 mb-2">Grind Size</label> 105 + <label class="block text-sm font-medium text-brown-900 mb-2">Grind Size</label> 106 106 <input 107 107 type="text" 108 108 name="grind_size" 109 109 {{if .Brew}}value="{{.Brew.GrindSize}}"{{end}} 110 110 placeholder="e.g. 18, Medium, 3.5, Fine" 111 - class="w-full rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4"/> 112 - <p class="text-sm text-gray-500 mt-1">Enter a number (grinder setting) or description (e.g. "Medium", "Fine")</p> 111 + class="w-full rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 bg-white"/> 112 + <p class="text-sm text-brown-700 mt-1">Enter a number (grinder setting) or description (e.g. "Medium", "Fine")</p> 113 113 </div> 114 114 115 115 <!-- Brew Method --> 116 116 <div> 117 - <label class="block text-sm font-medium text-gray-700 mb-2">Brew Method</label> 117 + <label class="block text-sm font-medium text-brown-900 mb-2">Brew Method</label> 118 118 <div class="flex gap-2"> 119 119 <select 120 120 name="brewer_rkey" 121 - class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4 truncate max-w-full"> 121 + class="flex-1 rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 truncate max-w-full bg-white"> 122 122 <option value="">Select brew method...</option> 123 123 {{if .Brewers}} 124 124 {{range .Brewers}} ··· 137 137 <button 138 138 type="button" 139 139 @click="showNewBrewer = true" 140 - class="bg-gray-200 text-gray-700 px-4 py-2 rounded hover:bg-gray-300"> 140 + class="bg-brown-300 text-brown-900 px-4 py-2 rounded-lg hover:bg-brown-400 font-medium transition-colors"> 141 141 + New 142 142 </button> 143 143 </div> ··· 147 147 148 148 <!-- Water Amount --> 149 149 <div> 150 - <label class="block text-sm font-medium text-gray-700 mb-2">Water Amount (grams)</label> 150 + <label class="block text-sm font-medium text-brown-900 mb-2">Water Amount (grams)</label> 151 151 <input 152 152 type="number" 153 153 name="water_amount" 154 154 step="1" 155 155 {{if and .Brew (gt .Brew.WaterAmount 0)}}value="{{.Brew.WaterAmount}}"{{end}} 156 156 placeholder="e.g. 250" 157 - class="w-full rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4"/> 158 - <p class="text-sm text-gray-500 mt-1">Total water used (or leave empty if using pours below)</p> 157 + class="w-full rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 bg-white"/> 158 + <p class="text-sm text-brown-700 mt-1">Total water used (or leave empty if using pours below)</p> 159 159 </div> 160 160 161 161 <!-- Pours Section --> 162 162 <div> 163 163 <div class="flex items-center justify-between mb-2"> 164 - <label class="block text-sm font-medium text-gray-700">Pours (Optional)</label> 164 + <label class="block text-sm font-medium text-brown-900">Pours (Optional)</label> 165 165 <button 166 166 type="button" 167 167 @click="addPour()" 168 - class="text-sm bg-gray-200 text-gray-700 px-3 py-1 rounded hover:bg-gray-300"> 168 + class="text-sm bg-brown-300 text-brown-900 px-3 py-1 rounded-lg hover:bg-brown-400 font-medium transition-colors"> 169 169 + Add Pour 170 170 </button> 171 171 </div> 172 - <p class="text-sm text-gray-500 mb-3">Track individual pours for bloom and subsequent additions</p> 172 + <p class="text-sm text-brown-700 mb-3">Track individual pours for bloom and subsequent additions</p> 173 173 174 174 <div class="space-y-3"> 175 175 <template x-for="(pour, index) in pours" :key="index"> 176 - <div class="flex gap-2 items-center bg-gray-50 p-3 rounded"> 176 + <div class="flex gap-2 items-center bg-brown-50 p-3 rounded-lg border border-brown-200"> 177 177 <div class="flex-1"> 178 - <label class="text-xs text-gray-600" x-text="'Pour ' + (index + 1)"></label> 178 + <label class="text-xs text-brown-700 font-medium" x-text="'Pour ' + (index + 1)"></label> 179 179 <input 180 180 type="number" 181 181 :name="'pour_water_' + index" 182 182 x-model="pour.water" 183 183 placeholder="Water (g)" 184 - class="w-full rounded-md border-gray-300 text-sm py-2 px-3 mt-1"/> 184 + class="w-full rounded-md border-brown-300 text-sm py-2 px-3 mt-1 bg-white"/> 185 185 </div> 186 186 <div class="flex-1"> 187 - <label class="text-xs text-gray-600">Time (sec)</label> 187 + <label class="text-xs text-brown-700 font-medium">Time (sec)</label> 188 188 <input 189 189 type="number" 190 190 :name="'pour_time_' + index" 191 191 x-model="pour.time" 192 192 placeholder="e.g. 45" 193 - class="w-full rounded-md border-gray-300 text-sm py-2 px-3 mt-1"/> 193 + class="w-full rounded-md border-brown-300 text-sm py-2 px-3 mt-1 bg-white"/> 194 194 </div> 195 195 <button 196 196 type="button" 197 197 @click="removePour(index)" 198 - class="text-red-600 hover:text-red-800 mt-5" 198 + class="text-brown-700 hover:text-brown-900 mt-5 font-bold" 199 199 x-show="pours.length > 0"> 200 200 201 201 </button> ··· 206 206 207 207 <!-- Temperature --> 208 208 <div> 209 - <label class="block text-sm font-medium text-gray-700 mb-2">Temperature</label> 209 + <label class="block text-sm font-medium text-brown-900 mb-2">Temperature</label> 210 210 <input 211 211 type="number" 212 212 name="temperature" 213 213 step="0.1" 214 214 {{if and .Brew (gt .Brew.Temperature 0.0)}}value="{{printf "%.1f" .Brew.Temperature}}"{{end}} 215 215 placeholder="e.g. 93.5" 216 - class="w-full rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4"/> 216 + class="w-full rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 bg-white"/> 217 217 </div> 218 218 219 219 <!-- Brew Time --> 220 220 <div> 221 - <label class="block text-sm font-medium text-gray-700 mb-2">Brew Time (seconds)</label> 221 + <label class="block text-sm font-medium text-brown-900 mb-2">Brew Time (seconds)</label> 222 222 <input 223 223 type="number" 224 224 name="time_seconds" 225 225 {{if and .Brew (gt .Brew.TimeSeconds 0)}}value="{{.Brew.TimeSeconds}}"{{end}} 226 226 placeholder="e.g. 180" 227 - class="w-full rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4"/> 227 + class="w-full rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 bg-white"/> 228 228 </div> 229 229 230 230 <!-- Tasting Notes --> 231 231 <div> 232 - <label class="block text-sm font-medium text-gray-700 mb-2">Tasting Notes</label> 232 + <label class="block text-sm font-medium text-brown-900 mb-2">Tasting Notes</label> 233 233 <textarea 234 234 name="tasting_notes" 235 235 rows="4" 236 236 placeholder="Describe the flavors, aroma, and your thoughts..." 237 - class="w-full rounded-md border-gray-300 shadow-sm focus:border-brown-500 focus:ring-brown-500 text-base py-3 px-4">{{if .Brew}}{{.Brew.TastingNotes}}{{end}}</textarea> 237 + class="w-full rounded-lg border-2 border-brown-300 shadow-sm focus:border-brown-600 focus:ring-brown-600 text-base py-3 px-4 bg-white">{{if .Brew}}{{.Brew.TastingNotes}}{{end}}</textarea> 238 238 </div> 239 239 240 240 <!-- Rating --> 241 241 <div> 242 - <label class="block text-sm font-medium text-gray-700 mb-2">Rating</label> 242 + <label class="block text-sm font-medium text-brown-900 mb-2">Rating</label> 243 243 <input 244 244 type="range" 245 245 name="rating" ··· 248 248 {{if .Brew}}value="{{.Brew.Rating}}"{{else}}value="5"{{end}} 249 249 x-model="rating" 250 250 x-init="rating = $el.value" 251 - class="w-full"/> 252 - <div class="text-center text-2xl font-bold text-brown-600"> 251 + class="w-full accent-brown-700"/> 252 + <div class="text-center text-2xl font-bold text-brown-800"> 253 253 <span x-text="rating"></span>/10 254 254 </div> 255 255 </div> ··· 258 258 <div> 259 259 <button 260 260 type="submit" 261 - class="w-full bg-brown-600 text-white py-3 px-6 rounded-lg hover:bg-brown-700 transition font-medium text-lg"> 261 + class="w-full bg-gradient-to-r from-brown-700 to-brown-800 text-white py-3 px-6 rounded-xl hover:from-brown-800 hover:to-brown-900 transition-all font-semibold text-lg shadow-lg hover:shadow-xl"> 262 262 {{if .Brew}}Update Brew{{else}}Save Brew{{end}} 263 263 </button> 264 264 </div>
+24 -24
templates/brew_list.tmpl
··· 1 1 {{define "content"}} 2 2 <div class="max-w-6xl mx-auto"> 3 3 <div class="mb-6"> 4 - <h2 class="text-3xl font-bold text-gray-800 mb-4">Your Brews</h2> 4 + <h2 class="text-3xl font-bold text-brown-900 mb-4">Your Brews</h2> 5 5 <div class="flex flex-col sm:flex-row gap-4"> 6 6 <a href="/brews/new" 7 - class="bg-brown-600 text-white py-2 px-4 rounded hover:bg-brown-700 transition text-center"> 8 - + New Brew 7 + class="bg-gradient-to-r from-brown-700 to-brown-800 text-white py-2 px-4 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all text-center font-medium shadow-lg hover:shadow-xl"> 8 + ☕ New Brew 9 9 </a> 10 10 <a href="/brews/export" 11 - class="bg-green-600 text-white py-2 px-4 rounded hover:bg-green-700 transition text-center"> 12 - Export JSON 11 + class="bg-gradient-to-r from-brown-500 to-brown-600 text-white py-2 px-4 rounded-lg hover:from-brown-600 hover:to-brown-700 transition-all text-center font-medium shadow-lg hover:shadow-xl"> 12 + 📥 Export JSON 13 13 </a> 14 14 </div> 15 15 </div> 16 16 17 17 <div hx-get="/api/brews" hx-trigger="load" hx-swap="innerHTML"> 18 18 <!-- Loading skeleton --> 19 - <div class="overflow-x-auto bg-white rounded-lg shadow-md"> 20 - <table class="min-w-full divide-y divide-gray-200"> 21 - <thead class="bg-gray-50"> 19 + <div class="overflow-x-auto bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-xl border border-brown-300"> 20 + <table class="min-w-full divide-y divide-brown-300"> 21 + <thead class="bg-brown-200/80"> 22 22 <tr> 23 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th> 24 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Bean</th> 25 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Roaster</th> 26 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Method</th> 27 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Rating</th> 28 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> 23 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Date</th> 24 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Bean</th> 25 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Roaster</th> 26 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Method</th> 27 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Rating</th> 28 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Actions</th> 29 29 </tr> 30 30 </thead> 31 - <tbody class="bg-white divide-y divide-gray-200"> 31 + <tbody class="bg-brown-50/60 divide-y divide-brown-200"> 32 32 {{range iterate 5}} 33 33 <tr class="animate-pulse"> 34 34 <td class="px-6 py-4 whitespace-nowrap"> 35 - <div class="h-4 bg-gray-200 rounded w-20"></div> 35 + <div class="h-4 bg-brown-300 rounded w-20"></div> 36 36 </td> 37 37 <td class="px-6 py-4"> 38 - <div class="h-4 bg-gray-200 rounded w-32 mb-2"></div> 39 - <div class="h-3 bg-gray-100 rounded w-24"></div> 38 + <div class="h-4 bg-brown-300 rounded w-32 mb-2"></div> 39 + <div class="h-3 bg-brown-200 rounded w-24"></div> 40 40 </td> 41 41 <td class="px-6 py-4"> 42 - <div class="h-4 bg-gray-200 rounded w-24"></div> 42 + <div class="h-4 bg-brown-300 rounded w-24"></div> 43 43 </td> 44 44 <td class="px-6 py-4"> 45 - <div class="h-4 bg-gray-200 rounded w-20 mb-2"></div> 46 - <div class="h-3 bg-gray-100 rounded w-16"></div> 45 + <div class="h-4 bg-brown-300 rounded w-20 mb-2"></div> 46 + <div class="h-3 bg-brown-200 rounded w-16"></div> 47 47 </td> 48 48 <td class="px-6 py-4"> 49 - <div class="h-5 bg-yellow-100 rounded-full w-14"></div> 49 + <div class="h-5 bg-amber-200 rounded-full w-14"></div> 50 50 </td> 51 51 <td class="px-6 py-4"> 52 52 <div class="flex gap-2"> 53 - <div class="h-4 bg-gray-200 rounded w-10"></div> 54 - <div class="h-4 bg-gray-200 rounded w-12"></div> 53 + <div class="h-4 bg-brown-300 rounded w-10"></div> 54 + <div class="h-4 bg-brown-300 rounded w-12"></div> 55 55 </div> 56 56 </td> 57 57 </tr>
+33 -33
templates/home.tmpl
··· 1 1 {{define "content"}} 2 2 <div class="max-w-4xl mx-auto"> 3 - <div class="bg-white rounded-lg shadow-md p-8 mb-8"> 3 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-xl p-8 mb-8 border border-brown-300"> 4 4 <div class="flex items-center gap-3 mb-4"> 5 - <h2 class="text-3xl font-bold text-gray-800">Welcome to Arabica</h2> 6 - <span class="text-xs bg-yellow-500 text-brown-900 px-2 py-1 rounded font-semibold">ALPHA</span> 5 + <h2 class="text-3xl font-bold text-brown-900">Welcome to Arabica</h2> 6 + <span class="text-xs bg-amber-400 text-brown-900 px-2 py-1 rounded-md font-semibold shadow-sm">ALPHA</span> 7 7 </div> 8 - <p class="text-gray-600 mb-2">Track your coffee brewing journey with detailed logs of every cup.</p> 9 - <p class="text-sm text-gray-500 italic mb-6">Note: Arabica is currently in alpha. Features and data structures may change.</p> 8 + <p class="text-brown-800 mb-2 text-lg">Track your coffee brewing journey with detailed logs of every cup.</p> 9 + <p class="text-sm text-brown-700 italic mb-6">Note: Arabica is currently in alpha. Features and data structures may change.</p> 10 10 11 11 {{if .IsAuthenticated}} 12 12 <!-- Authenticated: Show app actions and logout --> 13 13 <div class="mb-6"> 14 - <p class="text-sm text-gray-600">Logged in as: <span class="font-mono text-blue-600">{{.UserDID}}</span></p> 14 + <p class="text-sm text-brown-700">Logged in as: <span class="font-mono text-brown-900 font-semibold">{{.UserDID}}</span></p> 15 15 </div> 16 16 <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"> 17 17 <a href="/brews/new" 18 - class="block bg-brown-600 text-white text-center py-4 px-6 rounded-lg hover:bg-brown-700 transition"> 19 - <span class="text-xl">+ Add New Brew</span> 18 + class="block bg-gradient-to-br from-brown-700 to-brown-800 text-white text-center py-4 px-6 rounded-xl hover:from-brown-800 hover:to-brown-900 transition-all shadow-lg hover:shadow-xl transform hover:-translate-y-0.5"> 19 + <span class="text-xl font-semibold">☕ Add New Brew</span> 20 20 </a> 21 21 <a href="/brews" 22 - class="block bg-gray-600 text-white text-center py-4 px-6 rounded-lg hover:bg-gray-700 transition"> 23 - <span class="text-xl">View All Brews</span> 22 + class="block bg-gradient-to-br from-brown-500 to-brown-600 text-white text-center py-4 px-6 rounded-xl hover:from-brown-600 hover:to-brown-700 transition-all shadow-lg hover:shadow-xl transform hover:-translate-y-0.5"> 23 + <span class="text-xl font-semibold">📋 View All Brews</span> 24 24 </a> 25 25 </div> 26 26 <div class="text-center mt-6"> 27 27 <form action="/logout" method="POST" class="inline-block"> 28 28 <input type="hidden" name="csrf_token" class="csrf-token-field"> 29 29 <button type="submit" 30 - class="bg-red-600 text-white py-3 px-8 rounded-lg hover:bg-red-700 transition text-lg"> 30 + class="bg-brown-400 text-brown-900 py-3 px-8 rounded-lg hover:bg-brown-500 transition-all text-lg font-medium shadow-md hover:shadow-lg"> 31 31 Logout 32 32 </button> 33 33 </form> ··· 35 35 {{else}} 36 36 <!-- Not authenticated: Show login --> 37 37 <div> 38 - <p class="text-gray-700 mb-6 text-center">Please log in with your AT Protocol handle to start tracking your brews.</p> 38 + <p class="text-brown-800 mb-6 text-center text-lg">Please log in with your AT Protocol handle to start tracking your brews.</p> 39 39 <form method="POST" action="/auth/login" class="max-w-md mx-auto"> 40 40 <input type="hidden" name="csrf_token" class="csrf-token-field"> 41 41 <div class="relative"> 42 - <label for="handle" class="block text-sm font-medium text-gray-700 mb-2">Your Handle</label> 42 + <label for="handle" class="block text-sm font-medium text-brown-900 mb-2">Your Handle</label> 43 43 <input 44 44 type="text" 45 45 id="handle" ··· 47 47 placeholder="alice.bsky.social" 48 48 autocomplete="off" 49 49 required 50 - class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" 50 + class="w-full px-4 py-3 border-2 border-brown-300 rounded-lg focus:ring-2 focus:ring-brown-600 focus:border-brown-600 bg-white" 51 51 /> 52 52 <!-- FIX: image is way too big--> 53 - <div id="autocomplete-results" class="hidden absolute z-10 w-full mt-1 bg-white border border-gray-300 rounded-lg shadow-lg max-h-60 overflow-y-auto"></div> 53 + <div id="autocomplete-results" class="hidden absolute z-10 w-full mt-1 bg-brown-50 border-2 border-brown-300 rounded-lg shadow-lg max-h-60 overflow-y-auto"></div> 54 54 </div> 55 55 <button 56 56 type="submit" 57 - class="w-full mt-4 bg-blue-600 text-white py-3 px-8 rounded-lg hover:bg-blue-700 transition text-lg font-medium"> 57 + class="w-full mt-4 bg-gradient-to-r from-brown-700 to-brown-800 text-white py-3 px-8 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all text-lg font-semibold shadow-lg hover:shadow-xl"> 58 58 Log In 59 59 </button> 60 60 </form> ··· 65 65 </div> 66 66 67 67 <!-- Community Feed --> 68 - <div class="bg-white rounded-lg shadow-md p-6 mb-8"> 69 - <h3 class="text-xl font-semibold text-gray-800 mb-4">Community Feed</h3> 68 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-xl p-6 mb-8 border border-brown-300"> 69 + <h3 class="text-xl font-bold text-brown-900 mb-4">☕ Community Feed</h3> 70 70 <div hx-get="/api/feed" hx-trigger="load" hx-swap="innerHTML"> 71 71 <!-- Loading state --> 72 72 <div class="space-y-4"> 73 73 <div class="animate-pulse"> 74 - <div class="bg-gray-100 rounded-lg p-4"> 74 + <div class="bg-brown-50 rounded-lg p-4 border border-brown-200"> 75 75 <div class="flex items-center gap-3 mb-3"> 76 - <div class="w-10 h-10 rounded-full bg-gray-300"></div> 76 + <div class="w-10 h-10 rounded-full bg-brown-300"></div> 77 77 <div class="flex-1"> 78 - <div class="h-4 bg-gray-300 rounded w-1/4 mb-2"></div> 79 - <div class="h-3 bg-gray-200 rounded w-1/6"></div> 78 + <div class="h-4 bg-brown-300 rounded w-1/4 mb-2"></div> 79 + <div class="h-3 bg-brown-200 rounded w-1/6"></div> 80 80 </div> 81 81 </div> 82 - <div class="bg-gray-200 rounded-lg p-3"> 83 - <div class="h-4 bg-gray-300 rounded w-3/4 mb-2"></div> 84 - <div class="h-3 bg-gray-200 rounded w-1/2"></div> 82 + <div class="bg-brown-200 rounded-lg p-3"> 83 + <div class="h-4 bg-brown-300 rounded w-3/4 mb-2"></div> 84 + <div class="h-3 bg-brown-200 rounded w-1/2"></div> 85 85 </div> 86 86 </div> 87 87 </div> ··· 89 89 </div> 90 90 </div> 91 91 92 - <div class="bg-blue-50 rounded-lg p-6 border border-blue-200"> 93 - <h3 class="text-lg font-semibold text-blue-900 mb-2">About Arabica</h3> 94 - <ul class="text-blue-800 space-y-2"> 95 - <li>- <strong>Decentralized:</strong> Your data lives in your Personal Data Server (PDS)</li> 96 - <li>- <strong>Portable:</strong> Own your coffee brewing history</li> 97 - <li>- Track brewing variables like temperature, time, and grind size</li> 98 - <li>- Organize beans by origin and roaster</li> 99 - <li>- Add tasting notes and ratings to each brew</li> 92 + <div class="bg-gradient-to-br from-amber-50 to-brown-100 rounded-xl p-6 border-2 border-brown-300 shadow-lg"> 93 + <h3 class="text-lg font-bold text-brown-900 mb-3">✨ About Arabica</h3> 94 + <ul class="text-brown-800 space-y-2 leading-relaxed"> 95 + <li class="flex items-start"><span class="mr-2">🔒</span><span><strong>Decentralized:</strong> Your data lives in your Personal Data Server (PDS)</span></li> 96 + <li class="flex items-start"><span class="mr-2">🚀</span><span><strong>Portable:</strong> Own your coffee brewing history</span></li> 97 + <li class="flex items-start"><span class="mr-2">📊</span><span>Track brewing variables like temperature, time, and grind size</span></li> 98 + <li class="flex items-start"><span class="mr-2">🌍</span><span>Organize beans by origin and roaster</span></li> 99 + <li class="flex items-start"><span class="mr-2">📝</span><span>Add tasting notes and ratings to each brew</span></li> 100 100 </ul> 101 101 </div> 102 102 </div>
+11 -8
templates/layout.tmpl
··· 7 7 <meta name="description" content="Arabica - Coffee brew tracker" /> 8 8 <meta name="theme-color" content="#4a2c2a" /> 9 9 <title>{{.Title}} - Arabica</title> 10 - <link rel="stylesheet" href="/static/css/output.css?v=0.1.4" /> 10 + <link rel="icon" href="/static/favicon.svg" type="image/svg+xml" /> 11 + <link rel="icon" href="/static/favicon-32.svg" type="image/svg+xml" sizes="32x32" /> 12 + <link rel="apple-touch-icon" href="/static/icon-192.svg" /> 13 + <link rel="stylesheet" href="/static/css/output.css?v=0.1.6" /> 11 14 <style>[x-cloak] { display: none !important; }</style> 12 15 <link rel="manifest" href="/static/manifest.json" /> 13 16 <!-- Alpine.js - Using standard build due to CDN MIME type issues with CSP build --> ··· 21 24 {{end}} 22 25 <script src="/static/js/sw-register.js"></script> 23 26 </head> 24 - <body class="bg-gray-50 min-h-full flex flex-col"> 25 - <nav class="bg-brown-800 text-white shadow-lg"> 27 + <body class="bg-brown-50 min-h-full flex flex-col"> 28 + <nav class="bg-gradient-to-br from-brown-800 to-brown-900 text-white shadow-xl border-b-2 border-brown-600"> 26 29 <div class="container mx-auto px-4 py-4"> 27 30 <div class="flex items-center justify-between"> 28 31 <a href="/" class="hidden md:flex items-center gap-2 hover:opacity-80 transition"> 29 32 <h1 class="text-2xl font-bold">☕ Arabica</h1> 30 - <span class="text-xs bg-yellow-500 text-brown-900 px-2 py-1 rounded font-semibold">ALPHA</span> 33 + <span class="text-xs bg-amber-400 text-brown-900 px-2 py-1 rounded-md font-semibold shadow-sm">ALPHA</span> 31 34 </a> 32 35 <div class="space-x-4"> 33 - <a href="/" class="hover:text-brown-200">Home</a> 36 + <a href="/" class="hover:text-brown-100 transition-colors font-medium">Home</a> 34 37 {{if .IsAuthenticated}} 35 - <a href="/brews" class="hover:text-brown-200">Brews</a> 36 - <a href="/brews/new" class="hover:text-brown-200">New Brew</a> 37 - <a href="/manage" class="hover:text-brown-200">Manage</a> 38 + <a href="/brews" class="hover:text-brown-100 transition-colors font-medium">Brews</a> 39 + <a href="/brews/new" class="hover:text-brown-100 transition-colors font-medium">New Brew</a> 40 + <a href="/manage" class="hover:text-brown-100 transition-colors font-medium">Manage</a> 38 41 {{end}} 39 42 </div> 40 43 </div>
+23 -23
templates/manage.tmpl
··· 2 2 <script src="/static/js/manage-page.js"></script> 3 3 4 4 <div class="max-w-6xl mx-auto" x-data="managePage()"> 5 - <h2 class="text-3xl font-bold text-gray-800 mb-6">Manage</h2> 5 + <h2 class="text-3xl font-bold text-brown-900 mb-6">Manage</h2> 6 6 7 7 <!-- Tabs --> 8 - <div class="mb-6 border-b border-gray-200"> 8 + <div class="mb-6 border-b-2 border-brown-300"> 9 9 <nav class="-mb-px flex space-x-8"> 10 10 <button @click="tab = 'beans'" 11 - :class="tab === 'beans' ? 'border-brown-600 text-brown-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'" 11 + :class="tab === 'beans' ? 'border-brown-700 text-brown-900' : 'border-transparent text-brown-600 hover:text-brown-800 hover:border-brown-400'" 12 12 class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"> 13 13 Beans 14 14 </button> 15 15 <button @click="tab = 'roasters'" 16 - :class="tab === 'roasters' ? 'border-brown-600 text-brown-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'" 16 + :class="tab === 'roasters' ? 'border-brown-700 text-brown-900' : 'border-transparent text-brown-600 hover:text-brown-800 hover:border-brown-400'" 17 17 class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"> 18 18 Roasters 19 19 </button> 20 20 <button @click="tab = 'grinders'" 21 - :class="tab === 'grinders' ? 'border-brown-600 text-brown-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'" 21 + :class="tab === 'grinders' ? 'border-brown-700 text-brown-900' : 'border-transparent text-brown-600 hover:text-brown-800 hover:border-brown-400'" 22 22 class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"> 23 23 Grinders 24 24 </button> 25 25 <button @click="tab = 'brewers'" 26 - :class="tab === 'brewers' ? 'border-brown-600 text-brown-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'" 26 + :class="tab === 'brewers' ? 'border-brown-700 text-brown-900' : 'border-transparent text-brown-600 hover:text-brown-800 hover:border-brown-400'" 27 27 class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"> 28 28 Brewers 29 29 </button> ··· 35 35 <div class="animate-pulse"> 36 36 <!-- Header skeleton --> 37 37 <div class="mb-4 flex justify-between items-center"> 38 - <div class="h-6 bg-gray-200 rounded w-32"></div> 39 - <div class="h-10 bg-brown-200 rounded w-28"></div> 38 + <div class="h-6 bg-brown-300 rounded w-32"></div> 39 + <div class="h-10 bg-brown-300 rounded w-28"></div> 40 40 </div> 41 41 42 42 <!-- Table skeleton --> 43 - <div class="bg-white shadow-md rounded-lg overflow-hidden"> 44 - <table class="min-w-full divide-y divide-gray-200"> 45 - <thead class="bg-gray-50"> 43 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 shadow-xl rounded-xl overflow-hidden border border-brown-300"> 44 + <table class="min-w-full divide-y divide-brown-300"> 45 + <thead class="bg-brown-200/80"> 46 46 <tr> 47 - <th class="px-6 py-3 text-left"><div class="h-3 bg-gray-200 rounded w-16"></div></th> 48 - <th class="px-6 py-3 text-left"><div class="h-3 bg-gray-200 rounded w-16"></div></th> 49 - <th class="px-6 py-3 text-left"><div class="h-3 bg-gray-200 rounded w-20"></div></th> 50 - <th class="px-6 py-3 text-left"><div class="h-3 bg-gray-200 rounded w-24"></div></th> 51 - <th class="px-6 py-3 text-left"><div class="h-3 bg-gray-200 rounded w-16"></div></th> 47 + <th class="px-6 py-3 text-left"><div class="h-3 bg-brown-300 rounded w-16"></div></th> 48 + <th class="px-6 py-3 text-left"><div class="h-3 bg-brown-300 rounded w-16"></div></th> 49 + <th class="px-6 py-3 text-left"><div class="h-3 bg-brown-300 rounded w-20"></div></th> 50 + <th class="px-6 py-3 text-left"><div class="h-3 bg-brown-300 rounded w-24"></div></th> 51 + <th class="px-6 py-3 text-left"><div class="h-3 bg-brown-300 rounded w-16"></div></th> 52 52 </tr> 53 53 </thead> 54 - <tbody class="bg-white divide-y divide-gray-200"> 54 + <tbody class="bg-brown-50/60 divide-y divide-brown-200"> 55 55 {{range iterate 4}} 56 56 <tr> 57 - <td class="px-6 py-4"><div class="h-4 bg-gray-200 rounded w-24"></div></td> 58 - <td class="px-6 py-4"><div class="h-4 bg-gray-200 rounded w-20"></div></td> 59 - <td class="px-6 py-4"><div class="h-4 bg-gray-200 rounded w-28"></div></td> 60 - <td class="px-6 py-4"><div class="h-4 bg-gray-200 rounded w-16"></div></td> 57 + <td class="px-6 py-4"><div class="h-4 bg-brown-300 rounded w-24"></div></td> 58 + <td class="px-6 py-4"><div class="h-4 bg-brown-300 rounded w-20"></div></td> 59 + <td class="px-6 py-4"><div class="h-4 bg-brown-300 rounded w-28"></div></td> 60 + <td class="px-6 py-4"><div class="h-4 bg-brown-300 rounded w-16"></div></td> 61 61 <td class="px-6 py-4"> 62 62 <div class="flex gap-2"> 63 - <div class="h-4 bg-gray-200 rounded w-10"></div> 64 - <div class="h-4 bg-gray-200 rounded w-12"></div> 63 + <div class="h-4 bg-brown-300 rounded w-10"></div> 64 + <div class="h-4 bg-brown-300 rounded w-12"></div> 65 65 </div> 66 66 </td> 67 67 </tr>
+31 -31
templates/partials/brew_list_content.tmpl
··· 1 1 {{define "brew_list_content"}} 2 2 {{if not .Brews}} 3 - <div class="bg-white rounded-lg shadow-md p-8 text-center"> 4 - <p class="text-gray-600 text-lg mb-4">No brews yet! Start tracking your coffee journey.</p> 3 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-xl p-8 text-center border border-brown-300"> 4 + <p class="text-brown-800 text-lg mb-4 font-medium">No brews yet! Start tracking your coffee journey.</p> 5 5 <a href="/brews/new" 6 - class="inline-block bg-brown-600 text-white py-3 px-6 rounded-lg hover:bg-brown-700 transition"> 6 + class="inline-block bg-gradient-to-r from-brown-700 to-brown-800 text-white py-3 px-6 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all shadow-lg hover:shadow-xl font-medium"> 7 7 Add Your First Brew 8 8 </a> 9 9 </div> 10 10 {{else}} 11 - <div class="overflow-x-auto bg-white rounded-lg shadow-md"> 12 - <table class="min-w-full divide-y divide-gray-200"> 13 - <thead class="bg-gray-50"> 11 + <div class="overflow-x-auto bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-xl border border-brown-300"> 12 + <table class="min-w-full divide-y divide-brown-300"> 13 + <thead class="bg-brown-200/80"> 14 14 <tr> 15 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th> 16 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Bean</th> 17 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Roaster</th> 18 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Method</th> 19 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Rating</th> 20 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> 15 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Date</th> 16 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Bean</th> 17 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Roaster</th> 18 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Method</th> 19 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Rating</th> 20 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase tracking-wider">Actions</th> 21 21 </tr> 22 22 </thead> 23 - <tbody class="bg-white divide-y divide-gray-200"> 23 + <tbody class="bg-brown-50/60 divide-y divide-brown-200"> 24 24 {{range .Brews}} 25 - <tr class="hover:bg-gray-50"> 26 - <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> 25 + <tr class="hover:bg-brown-100/60 transition-colors"> 26 + <td class="px-6 py-4 whitespace-nowrap text-sm text-brown-900 font-medium"> 27 27 {{.CreatedAt.Format "Jan 2, 2006"}} 28 28 </td> 29 - <td class="px-6 py-4 text-sm text-gray-900"> 29 + <td class="px-6 py-4 text-sm text-brown-900"> 30 30 {{if .Bean}} 31 31 {{if .Bean.Name}} 32 - <div class="font-medium">{{.Bean.Name}}</div> 33 - <div class="text-gray-500 text-xs">{{.Bean.Origin}} - {{.Bean.RoastLevel}}</div> 32 + <div class="font-medium text-brown-900">{{.Bean.Name}}</div> 33 + <div class="text-brown-600 text-xs">{{.Bean.Origin}} - {{.Bean.RoastLevel}}</div> 34 34 {{else}} 35 - <div class="font-medium">{{.Bean.Origin}}</div> 36 - <div class="text-gray-500">{{.Bean.RoastLevel}}</div> 35 + <div class="font-medium text-brown-900">{{.Bean.Origin}}</div> 36 + <div class="text-brown-600">{{.Bean.RoastLevel}}</div> 37 37 {{end}} 38 38 {{else}} 39 - <span class="text-gray-400">-</span> 39 + <span class="text-brown-400">-</span> 40 40 {{end}} 41 41 </td> 42 - <td class="px-6 py-4 text-sm text-gray-900"> 42 + <td class="px-6 py-4 text-sm text-brown-900"> 43 43 {{if and .Bean .Bean.Roaster .Bean.Roaster.Name}} 44 44 {{.Bean.Roaster.Name}} 45 45 {{else}} 46 - <span class="text-gray-400">-</span> 46 + <span class="text-brown-400">-</span> 47 47 {{end}} 48 48 </td> 49 - <td class="px-6 py-4 text-sm text-gray-900"> 50 - <div>{{.Method}}</div> 51 - <div class="text-gray-500 text-xs"> 49 + <td class="px-6 py-4 text-sm text-brown-900"> 50 + <div class="font-medium">{{.Method}}</div> 51 + <div class="text-brown-600 text-xs"> 52 52 {{.TempFormatted}} • {{.TimeFormatted}} 53 53 </div> 54 54 {{if .Pours}} 55 - <div class="text-gray-500 text-xs mt-1"> 55 + <div class="text-brown-600 text-xs mt-1"> 56 56 {{len .Pours}} pours 57 57 </div> 58 58 {{end}} 59 59 </td> 60 - <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> 61 - <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800"> 60 + <td class="px-6 py-4 whitespace-nowrap text-sm text-brown-900"> 61 + <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-900"> 62 62 ⭐ {{.RatingFormatted}} 63 63 </span> 64 64 </td> 65 65 <td class="px-6 py-4 whitespace-nowrap text-sm font-medium space-x-2"> 66 66 <a href="/brews/{{.RKey}}" 67 - class="text-blue-600 hover:text-blue-900">View</a> 67 + class="text-brown-700 hover:text-brown-900 font-medium">View</a> 68 68 <button hx-delete="/brews/{{.RKey}}" 69 69 hx-confirm="Are you sure you want to delete this brew?" hx-target="closest tr" 70 - hx-swap="outerHTML swap:1s" class="text-red-600 hover:text-red-900"> 70 + hx-swap="outerHTML swap:1s" class="text-brown-600 hover:text-brown-800 font-medium"> 71 71 Delete 72 72 </button> 73 73 </td>
+47 -47
templates/partials/feed.tmpl
··· 2 2 <div class="space-y-4"> 3 3 {{if .FeedItems}} 4 4 {{range .FeedItems}} 5 - <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4"> 5 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 rounded-lg shadow-md border border-brown-200 p-4 hover:shadow-lg transition-shadow"> 6 6 <!-- Author row --> 7 7 <div class="flex items-center gap-3 mb-3"> 8 8 <a href="/profile/{{.Author.Handle}}" class="flex-shrink-0"> 9 9 {{if .Author.Avatar}} 10 10 {{$safeAvatar := safeAvatarURL .Author.Avatar}} 11 11 {{if $safeAvatar}} 12 - <img src="{{$safeAvatar}}" alt="" class="w-10 h-10 rounded-full object-cover hover:ring-2 hover:ring-brown-400 transition" /> 12 + <img src="{{$safeAvatar}}" alt="" class="w-10 h-10 rounded-full object-cover hover:ring-2 hover:ring-brown-600 transition" /> 13 13 {{else}} 14 - <div class="w-10 h-10 rounded-full bg-gray-300 flex items-center justify-center hover:ring-2 hover:ring-brown-400 transition"> 15 - <span class="text-gray-500 text-sm">?</span> 14 + <div class="w-10 h-10 rounded-full bg-brown-300 flex items-center justify-center hover:ring-2 hover:ring-brown-600 transition"> 15 + <span class="text-brown-600 text-sm">?</span> 16 16 </div> 17 17 {{end}} 18 18 {{else}} 19 - <div class="w-10 h-10 rounded-full bg-gray-300 flex items-center justify-center hover:ring-2 hover:ring-brown-400 transition"> 20 - <span class="text-gray-500 text-sm">?</span> 19 + <div class="w-10 h-10 rounded-full bg-brown-300 flex items-center justify-center hover:ring-2 hover:ring-brown-600 transition"> 20 + <span class="text-brown-600 text-sm">?</span> 21 21 </div> 22 22 {{end}} 23 23 </a> 24 24 <div class="flex-1 min-w-0"> 25 25 <div class="flex items-center gap-2"> 26 26 {{if .Author.DisplayName}} 27 - <a href="/profile/{{.Author.Handle}}" class="font-medium text-gray-900 truncate hover:text-brown-700 hover:underline">{{.Author.DisplayName}}</a> 27 + <a href="/profile/{{.Author.Handle}}" class="font-medium text-brown-900 truncate hover:text-brown-700 hover:underline">{{.Author.DisplayName}}</a> 28 28 {{end}} 29 - <a href="/profile/{{.Author.Handle}}" class="text-gray-500 text-sm truncate hover:text-brown-600 hover:underline">@{{.Author.Handle}}</a> 29 + <a href="/profile/{{.Author.Handle}}" class="text-brown-600 text-sm truncate hover:text-brown-700 hover:underline">@{{.Author.Handle}}</a> 30 30 </div> 31 - <span class="text-gray-400 text-sm">{{.TimeAgo}}</span> 31 + <span class="text-brown-500 text-sm">{{.TimeAgo}}</span> 32 32 </div> 33 33 </div> 34 34 35 35 <!-- Action header --> 36 - <div class="mb-2 text-sm text-gray-600 italic"> 36 + <div class="mb-2 text-sm text-brown-700 italic"> 37 37 {{.Action}} 38 38 </div> 39 39 40 40 <!-- Record content --> 41 41 {{if eq .RecordType "brew"}} 42 42 <!-- Brew info --> 43 - <div class="bg-gray-50 rounded-lg p-3"> 43 + <div class="bg-white/60 backdrop-blur rounded-lg p-3 border border-brown-200"> 44 44 <!-- Bean and roaster info --> 45 45 <div class="flex items-start justify-between gap-2 mb-2"> 46 46 <div class="flex-1 min-w-0"> 47 47 {{if .Brew.Bean}} 48 48 <!-- Bean name and roaster --> 49 49 <div class="text-base"> 50 - <span class="text-gray-600">Bean:</span> 51 - <span class="font-bold text-gray-900"> 50 + <span class="text-brown-700">Bean:</span> 51 + <span class="font-bold text-brown-900"> 52 52 {{if .Brew.Bean.Name}}{{.Brew.Bean.Name}}{{else}}{{.Brew.Bean.Origin}}{{end}}{{if and .Brew.Bean.Roaster .Brew.Bean.Roaster.Name}} - {{.Brew.Bean.Roaster.Name}}{{end}} 53 53 </span> 54 54 </div> 55 55 <!-- Process, roast level, origin --> 56 - <div class="text-sm text-gray-600"> 56 + <div class="text-sm text-brown-600"> 57 57 {{if .Brew.Bean.Process}}{{.Brew.Bean.Process}}{{end}}{{if and .Brew.Bean.Process .Brew.Bean.RoastLevel}} • {{end}}{{if .Brew.Bean.RoastLevel}}{{.Brew.Bean.RoastLevel}}{{end}}{{if and (or .Brew.Bean.Process .Brew.Bean.RoastLevel) .Brew.Bean.Origin}} • {{end}}{{if .Brew.Bean.Origin}}{{.Brew.Bean.Origin}}{{end}} 58 58 </div> 59 59 {{end}} 60 60 </div> 61 61 {{if hasValue .Brew.Rating}} 62 - <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 flex-shrink-0"> 62 + <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-900 flex-shrink-0"> 63 63 ⭐ {{.Brew.Rating}}/10 64 64 </span> 65 65 {{end}} 66 66 </div> 67 67 68 68 <!-- Brew parameters --> 69 - <div class="grid grid-cols-2 gap-2 text-sm text-gray-600"> 69 + <div class="grid grid-cols-2 gap-2 text-sm text-brown-700"> 70 70 {{if hasValue .Brew.CoffeeAmount}} 71 71 <div> 72 - <span class="text-gray-500">Coffee:</span> {{.Brew.CoffeeAmount}}g 72 + <span class="text-brown-600">Coffee:</span> {{.Brew.CoffeeAmount}}g 73 73 </div> 74 74 {{end}} 75 75 {{if hasValue .Brew.WaterAmount}} 76 76 <div> 77 - <span class="text-gray-500">Water:</span> {{.Brew.WaterAmount}}g 77 + <span class="text-brown-600">Water:</span> {{.Brew.WaterAmount}}g 78 78 </div> 79 79 {{end}} 80 80 {{if hasTemp .Brew.Temperature}} 81 81 <div> 82 - <span class="text-gray-500">Temp:</span> {{formatTemp .Brew.Temperature}} 82 + <span class="text-brown-600">Temp:</span> {{formatTemp .Brew.Temperature}} 83 83 </div> 84 84 {{end}} 85 85 {{if hasValue .Brew.TimeSeconds}} 86 86 <div> 87 - <span class="text-gray-500">Time:</span> {{formatTime .Brew.TimeSeconds}} 87 + <span class="text-brown-600">Time:</span> {{formatTime .Brew.TimeSeconds}} 88 88 </div> 89 89 {{end}} 90 90 {{if .Brew.GrindSize}} 91 91 <div> 92 - <span class="text-gray-500">Grind:</span> {{.Brew.GrindSize}}{{if .Brew.GrinderObj}} ({{.Brew.GrinderObj.Name}}){{end}} 92 + <span class="text-brown-600">Grind:</span> {{.Brew.GrindSize}}{{if .Brew.GrinderObj}} ({{.Brew.GrinderObj.Name}}){{end}} 93 93 </div> 94 94 {{end}} 95 95 <div> 96 - <span class="text-gray-500">Brewer:</span> <span class="font-bold text-gray-900">{{if .Brew.BrewerObj}}{{.Brew.BrewerObj.Name}}{{else if .Brew.Method}}{{.Brew.Method}}{{else}}-{{end}}</span> 96 + <span class="text-brown-600">Brewer:</span> <span class="font-bold text-brown-900">{{if .Brew.BrewerObj}}{{.Brew.BrewerObj.Name}}{{else if .Brew.Method}}{{.Brew.Method}}{{else}}-{{end}}</span> 97 97 </div> 98 98 </div> 99 99 100 100 {{if .Brew.TastingNotes}} 101 - <div class="mt-3 text-sm text-gray-700 italic border-t border-gray-200 pt-2"> 101 + <div class="mt-3 text-sm text-brown-800 italic border-t border-brown-200 pt-2"> 102 102 "{{.Brew.TastingNotes}}" 103 103 </div> 104 104 {{end}} 105 105 </div> 106 106 {{else if eq .RecordType "bean"}} 107 107 <!-- Bean info --> 108 - <div class="bg-gray-50 rounded-lg p-3"> 108 + <div class="bg-white/60 backdrop-blur rounded-lg p-3 border border-brown-200"> 109 109 <div class="text-base mb-2"> 110 - <span class="font-bold text-gray-900"> 110 + <span class="font-bold text-brown-900"> 111 111 {{if .Bean.Name}}{{.Bean.Name}}{{else}}{{.Bean.Origin}}{{end}} 112 112 </span> 113 113 {{if and .Bean.Roaster .Bean.Roaster.Name}} 114 - <span class="text-gray-600"> from {{.Bean.Roaster.Name}}</span> 114 + <span class="text-brown-700"> from {{.Bean.Roaster.Name}}</span> 115 115 {{end}} 116 116 </div> 117 - <div class="text-sm text-gray-600 space-y-1"> 117 + <div class="text-sm text-brown-700 space-y-1"> 118 118 {{if .Bean.Origin}} 119 - <div><span class="text-gray-500">Origin:</span> {{.Bean.Origin}}</div> 119 + <div><span class="text-brown-600">Origin:</span> {{.Bean.Origin}}</div> 120 120 {{end}} 121 121 {{if .Bean.RoastLevel}} 122 - <div><span class="text-gray-500">Roast:</span> {{.Bean.RoastLevel}}</div> 122 + <div><span class="text-brown-600">Roast:</span> {{.Bean.RoastLevel}}</div> 123 123 {{end}} 124 124 {{if .Bean.Process}} 125 - <div><span class="text-gray-500">Process:</span> {{.Bean.Process}}</div> 125 + <div><span class="text-brown-600">Process:</span> {{.Bean.Process}}</div> 126 126 {{end}} 127 127 {{if .Bean.Description}} 128 - <div class="mt-2 text-gray-700 italic">"{{.Bean.Description}}"</div> 128 + <div class="mt-2 text-brown-800 italic">"{{.Bean.Description}}"</div> 129 129 {{end}} 130 130 </div> 131 131 </div> 132 132 {{else if eq .RecordType "roaster"}} 133 133 <!-- Roaster info --> 134 - <div class="bg-gray-50 rounded-lg p-3"> 134 + <div class="bg-white/60 backdrop-blur rounded-lg p-3 border border-brown-200"> 135 135 <div class="text-base mb-2"> 136 - <span class="font-bold text-gray-900">{{.Roaster.Name}}</span> 136 + <span class="font-bold text-brown-900">{{.Roaster.Name}}</span> 137 137 </div> 138 - <div class="text-sm text-gray-600 space-y-1"> 138 + <div class="text-sm text-brown-700 space-y-1"> 139 139 {{if .Roaster.Location}} 140 - <div><span class="text-gray-500">Location:</span> {{.Roaster.Location}}</div> 140 + <div><span class="text-brown-600">Location:</span> {{.Roaster.Location}}</div> 141 141 {{end}} 142 142 {{if .Roaster.Website}} 143 143 {{$safeWebsite := safeWebsiteURL .Roaster.Website}} 144 144 {{if $safeWebsite}} 145 - <div><span class="text-gray-500">Website:</span> <a href="{{$safeWebsite}}" target="_blank" rel="noopener noreferrer" class="text-blue-600 hover:underline">{{$safeWebsite}}</a></div> 145 + <div><span class="text-brown-600">Website:</span> <a href="{{$safeWebsite}}" target="_blank" rel="noopener noreferrer" class="text-brown-800 hover:underline">{{$safeWebsite}}</a></div> 146 146 {{end}} 147 147 {{end}} 148 148 </div> 149 149 </div> 150 150 {{else if eq .RecordType "grinder"}} 151 151 <!-- Grinder info --> 152 - <div class="bg-gray-50 rounded-lg p-3"> 152 + <div class="bg-white/60 backdrop-blur rounded-lg p-3 border border-brown-200"> 153 153 <div class="text-base mb-2"> 154 - <span class="font-bold text-gray-900">{{.Grinder.Name}}</span> 154 + <span class="font-bold text-brown-900">{{.Grinder.Name}}</span> 155 155 </div> 156 - <div class="text-sm text-gray-600 space-y-1"> 156 + <div class="text-sm text-brown-700 space-y-1"> 157 157 {{if .Grinder.GrinderType}} 158 - <div><span class="text-gray-500">Type:</span> {{.Grinder.GrinderType}}</div> 158 + <div><span class="text-brown-600">Type:</span> {{.Grinder.GrinderType}}</div> 159 159 {{end}} 160 160 {{if .Grinder.BurrType}} 161 - <div><span class="text-gray-500">Burr:</span> {{.Grinder.BurrType}}</div> 161 + <div><span class="text-brown-600">Burr:</span> {{.Grinder.BurrType}}</div> 162 162 {{end}} 163 163 {{if .Grinder.Notes}} 164 - <div class="mt-2 text-gray-700 italic">"{{.Grinder.Notes}}"</div> 164 + <div class="mt-2 text-brown-800 italic">"{{.Grinder.Notes}}"</div> 165 165 {{end}} 166 166 </div> 167 167 </div> 168 168 {{else if eq .RecordType "brewer"}} 169 169 <!-- Brewer info --> 170 - <div class="bg-gray-50 rounded-lg p-3"> 170 + <div class="bg-white/60 backdrop-blur rounded-lg p-3 border border-brown-200"> 171 171 <div class="text-base mb-2"> 172 - <span class="font-bold text-gray-900">{{.Brewer.Name}}</span> 172 + <span class="font-bold text-brown-900">{{.Brewer.Name}}</span> 173 173 </div> 174 174 {{if .Brewer.Description}} 175 - <div class="text-sm text-gray-700 italic">"{{.Brewer.Description}}"</div> 175 + <div class="text-sm text-brown-800 italic">"{{.Brewer.Description}}"</div> 176 176 {{end}} 177 177 </div> 178 178 {{end}} 179 179 </div> 180 180 {{end}} 181 181 {{else}} 182 - <div class="bg-gray-50 rounded-lg p-6 text-center text-gray-500"> 183 - <p class="mb-2">No activity in the feed yet.</p> 182 + <div class="bg-brown-100 rounded-lg p-6 text-center text-brown-700 border border-brown-200"> 183 + <p class="mb-2 font-medium">No activity in the feed yet.</p> 184 184 <p class="text-sm">Be the first to add something!</p> 185 185 </div> 186 186 {{end}}
+111 -111
templates/partials/manage_content.tmpl
··· 2 2 <!-- Beans Tab --> 3 3 <div x-show="tab === 'beans'"> 4 4 <div class="mb-4 flex justify-between items-center"> 5 - <h3 class="text-xl font-semibold">Coffee Beans</h3> 5 + <h3 class="text-xl font-semibold text-brown-900">Coffee Beans</h3> 6 6 <button 7 7 @click="showBeanForm = true; editingBean = null; beanForm = {name: '', origin: '', roast_level: '', process: '', description: '', roaster_rkey: ''}" 8 - class="bg-brown-600 text-white px-4 py-2 rounded hover:bg-brown-700"> 8 + class="bg-gradient-to-r from-brown-700 to-brown-800 text-white px-4 py-2 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all font-medium shadow-md hover:shadow-lg"> 9 9 + Add Bean 10 10 </button> 11 11 </div> 12 12 13 13 {{if not .Beans}} 14 - <div class="bg-gray-50 rounded-lg p-8 text-center text-gray-600"> 14 + <div class="bg-brown-100 rounded-lg p-8 text-center text-brown-700 border border-brown-200"> 15 15 No beans yet. Add your first bean to get started! 16 16 </div> 17 17 {{else}} 18 - <div class="bg-white shadow-md rounded-lg overflow-x-auto"> 19 - <table class="min-w-full divide-y divide-gray-200"> 20 - <thead class="bg-gray-50"> 18 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 shadow-xl rounded-xl overflow-x-auto border border-brown-300"> 19 + <table class="min-w-full divide-y divide-brown-300"> 20 + <thead class="bg-brown-200/80"> 21 21 <tr> 22 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Name</th> 23 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Origin</th> 24 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Roaster</th> 25 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Roast Level</th> 26 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Process</th> 27 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Description</th> 28 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Actions</th> 22 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Name</th> 23 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Origin</th> 24 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Roaster</th> 25 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Roast Level</th> 26 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Process</th> 27 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Description</th> 28 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Actions</th> 29 29 </tr> 30 30 </thead> 31 - <tbody class="bg-white divide-y divide-gray-200"> 31 + <tbody class="bg-brown-50/60 divide-y divide-brown-200"> 32 32 {{range .Beans}} 33 - <tr> 34 - <td class="px-6 py-4 text-sm font-medium text-gray-900">{{.Name}}</td> 35 - <td class="px-6 py-4 text-sm text-gray-900">{{.Origin}}</td> 36 - <td class="px-6 py-4 text-sm text-gray-900"> 33 + <tr class="hover:bg-brown-100/60 transition-colors"> 34 + <td class="px-6 py-4 text-sm font-medium text-brown-900">{{.Name}}</td> 35 + <td class="px-6 py-4 text-sm text-brown-900">{{.Origin}}</td> 36 + <td class="px-6 py-4 text-sm text-brown-900"> 37 37 {{if and .Roaster .Roaster.Name}} 38 38 {{.Roaster.Name}} 39 39 {{else}} 40 - <span class="text-gray-400">-</span> 40 + <span class="text-brown-400">-</span> 41 41 {{end}} 42 42 </td> 43 - <td class="px-6 py-4 text-sm text-gray-900">{{.RoastLevel}}</td> 44 - <td class="px-6 py-4 text-sm text-gray-900">{{.Process}}</td> 45 - <td class="px-6 py-4 text-sm text-gray-500">{{.Description}}</td> 43 + <td class="px-6 py-4 text-sm text-brown-900">{{.RoastLevel}}</td> 44 + <td class="px-6 py-4 text-sm text-brown-900">{{.Process}}</td> 45 + <td class="px-6 py-4 text-sm text-brown-700">{{.Description}}</td> 46 46 <td class="px-6 py-4 text-sm font-medium space-x-2"> 47 47 <button @click="editBean('{{.RKey}}', '{{.Name}}', '{{.Origin}}', '{{.RoastLevel}}', '{{.Process}}', '{{.Description}}', '{{.RoasterRKey}}')" 48 - class="text-blue-600 hover:text-blue-900">Edit</button> 48 + class="text-brown-700 hover:text-brown-900 font-medium">Edit</button> 49 49 <button @click="deleteBean('{{.RKey}}')" 50 - class="text-red-600 hover:text-red-900">Delete</button> 50 + class="text-brown-600 hover:text-brown-800 font-medium">Delete</button> 51 51 </td> 52 52 </tr> 53 53 {{end}} ··· 60 60 <!-- Roasters Tab --> 61 61 <div x-show="tab === 'roasters'"> 62 62 <div class="mb-4 flex justify-between items-center"> 63 - <h3 class="text-xl font-semibold">Roasters</h3> 63 + <h3 class="text-xl font-semibold text-brown-900">Roasters</h3> 64 64 <button 65 65 @click="showRoasterForm = true; editingRoaster = null; roasterForm = {name: '', location: '', website: ''}" 66 - class="bg-brown-600 text-white px-4 py-2 rounded hover:bg-brown-700"> 66 + class="bg-gradient-to-r from-brown-700 to-brown-800 text-white px-4 py-2 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all font-medium shadow-md hover:shadow-lg"> 67 67 + Add Roaster 68 68 </button> 69 69 </div> 70 70 71 71 {{if not .Roasters}} 72 - <div class="bg-gray-50 rounded-lg p-8 text-center text-gray-600"> 72 + <div class="bg-brown-100 rounded-lg p-8 text-center text-brown-700 border border-brown-200"> 73 73 No roasters yet. Add your first roaster! 74 74 </div> 75 75 {{else}} 76 - <div class="bg-white shadow-md rounded-lg overflow-x-auto"> 77 - <table class="min-w-full divide-y divide-gray-200"> 78 - <thead class="bg-gray-50"> 76 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 shadow-xl rounded-xl overflow-x-auto border border-brown-300"> 77 + <table class="min-w-full divide-y divide-brown-300"> 78 + <thead class="bg-brown-200/80"> 79 79 <tr> 80 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Name</th> 81 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Location</th> 82 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Website</th> 83 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Actions</th> 80 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Name</th> 81 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Location</th> 82 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Website</th> 83 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Actions</th> 84 84 </tr> 85 85 </thead> 86 - <tbody class="bg-white divide-y divide-gray-200"> 86 + <tbody class="bg-brown-50/60 divide-y divide-brown-200"> 87 87 {{range .Roasters}} 88 - <tr> 89 - <td class="px-6 py-4 text-sm font-medium text-gray-900">{{.Name}}</td> 90 - <td class="px-6 py-4 text-sm text-gray-900">{{.Location}}</td> 91 - <td class="px-6 py-4 text-sm text-gray-900"> 88 + <tr class="hover:bg-brown-100/60 transition-colors"> 89 + <td class="px-6 py-4 text-sm font-medium text-brown-900">{{.Name}}</td> 90 + <td class="px-6 py-4 text-sm text-brown-900">{{.Location}}</td> 91 + <td class="px-6 py-4 text-sm text-brown-900"> 92 92 {{if .Website}} 93 93 <a href="{{.Website}}" target="_blank" 94 - class="text-blue-600 hover:underline">{{.Website}}</a> 94 + class="text-brown-700 hover:underline font-medium">{{.Website}}</a> 95 95 {{end}} 96 96 </td> 97 97 <td class="px-6 py-4 text-sm font-medium space-x-2"> 98 98 <button @click="editRoaster('{{.RKey}}', '{{.Name}}', '{{.Location}}', '{{.Website}}')" 99 - class="text-blue-600 hover:text-blue-900">Edit</button> 99 + class="text-brown-700 hover:text-brown-900 font-medium">Edit</button> 100 100 <button @click="deleteRoaster('{{.RKey}}')" 101 - class="text-red-600 hover:text-red-900">Delete</button> 101 + class="text-brown-600 hover:text-brown-800 font-medium">Delete</button> 102 102 </td> 103 103 </tr> 104 104 {{end}} ··· 111 111 <!-- Grinders Tab --> 112 112 <div x-show="tab === 'grinders'"> 113 113 <div class="mb-4 flex justify-between items-center"> 114 - <h3 class="text-xl font-semibold">Grinders</h3> 114 + <h3 class="text-xl font-semibold text-brown-900">Grinders</h3> 115 115 <button 116 116 @click="showGrinderForm = true; editingGrinder = null; grinderForm = {name: '', grinder_type: '', burr_type: '', notes: ''}" 117 - class="bg-brown-600 text-white px-4 py-2 rounded hover:bg-brown-700"> 117 + class="bg-gradient-to-r from-brown-700 to-brown-800 text-white px-4 py-2 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all font-medium shadow-md hover:shadow-lg"> 118 118 + Add Grinder 119 119 </button> 120 120 </div> 121 121 122 122 {{if not .Grinders}} 123 - <div class="bg-gray-50 rounded-lg p-8 text-center text-gray-600"> 123 + <div class="bg-brown-100 rounded-lg p-8 text-center text-brown-700 border border-brown-200"> 124 124 No grinders yet. Add your first grinder! 125 125 </div> 126 126 {{else}} 127 - <div class="bg-white shadow-md rounded-lg overflow-x-auto"> 128 - <table class="min-w-full divide-y divide-gray-200"> 129 - <thead class="bg-gray-50"> 127 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 shadow-xl rounded-xl overflow-x-auto border border-brown-300"> 128 + <table class="min-w-full divide-y divide-brown-300"> 129 + <thead class="bg-brown-200/80"> 130 130 <tr> 131 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Name</th> 132 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Grinder Type</th> 133 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Burr Type</th> 134 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Notes</th> 135 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Actions</th> 131 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Name</th> 132 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Grinder Type</th> 133 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Burr Type</th> 134 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Notes</th> 135 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Actions</th> 136 136 </tr> 137 137 </thead> 138 - <tbody class="bg-white divide-y divide-gray-200"> 138 + <tbody class="bg-brown-50/60 divide-y divide-brown-200"> 139 139 {{range .Grinders}} 140 - <tr> 141 - <td class="px-6 py-4 text-sm font-medium text-gray-900">{{.Name}}</td> 142 - <td class="px-6 py-4 text-sm text-gray-900">{{.GrinderType}}</td> 143 - <td class="px-6 py-4 text-sm text-gray-900">{{.BurrType}}</td> 144 - <td class="px-6 py-4 text-sm text-gray-500">{{.Notes}}</td> 140 + <tr class="hover:bg-brown-100/60 transition-colors"> 141 + <td class="px-6 py-4 text-sm font-medium text-brown-900">{{.Name}}</td> 142 + <td class="px-6 py-4 text-sm text-brown-900">{{.GrinderType}}</td> 143 + <td class="px-6 py-4 text-sm text-brown-900">{{.BurrType}}</td> 144 + <td class="px-6 py-4 text-sm text-brown-700">{{.Notes}}</td> 145 145 <td class="px-6 py-4 text-sm font-medium space-x-2"> 146 146 <button @click="editGrinder('{{.RKey}}', '{{.Name}}', '{{.GrinderType}}', '{{.BurrType}}', '{{.Notes}}')" 147 - class="text-blue-600 hover:text-blue-900">Edit</button> 147 + class="text-brown-700 hover:text-brown-900 font-medium">Edit</button> 148 148 <button @click="deleteGrinder('{{.RKey}}')" 149 - class="text-red-600 hover:text-red-900">Delete</button> 149 + class="text-brown-600 hover:text-brown-800 font-medium">Delete</button> 150 150 </td> 151 151 </tr> 152 152 {{end}} ··· 159 159 <!-- Brewers Tab --> 160 160 <div x-show="tab === 'brewers'"> 161 161 <div class="mb-4 flex justify-between items-center"> 162 - <h3 class="text-xl font-semibold">Brewers</h3> 162 + <h3 class="text-xl font-semibold text-brown-900">Brewers</h3> 163 163 <button @click="showBrewerForm = true; editingBrewer = null; brewerForm = {name: '', description: ''}" 164 - class="bg-brown-600 text-white px-4 py-2 rounded hover:bg-brown-700"> 164 + class="bg-gradient-to-r from-brown-700 to-brown-800 text-white px-4 py-2 rounded-lg hover:from-brown-800 hover:to-brown-900 transition-all font-medium shadow-md hover:shadow-lg"> 165 165 + Add Brewer 166 166 </button> 167 167 </div> 168 168 169 169 {{if not .Brewers}} 170 - <div class="bg-gray-50 rounded-lg p-8 text-center text-gray-600"> 170 + <div class="bg-brown-100 rounded-lg p-8 text-center text-brown-700 border border-brown-200"> 171 171 No brewers yet. Add your first brewer! 172 172 </div> 173 173 {{else}} 174 - <div class="bg-white shadow-md rounded-lg overflow-x-auto"> 175 - <table class="min-w-full divide-y divide-gray-200"> 176 - <thead class="bg-gray-50"> 174 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 shadow-xl rounded-xl overflow-x-auto border border-brown-300"> 175 + <table class="min-w-full divide-y divide-brown-300"> 176 + <thead class="bg-brown-200/80"> 177 177 <tr> 178 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Name</th> 179 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Description</th> 180 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Actions</th> 178 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Name</th> 179 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Description</th> 180 + <th class="px-6 py-3 text-left text-xs font-medium text-brown-900 uppercase">Actions</th> 181 181 </tr> 182 182 </thead> 183 - <tbody class="bg-white divide-y divide-gray-200"> 183 + <tbody class="bg-brown-50/60 divide-y divide-brown-200"> 184 184 {{range .Brewers}} 185 - <tr> 186 - <td class="px-6 py-4 text-sm font-medium text-gray-900">{{.Name}}</td> 187 - <td class="px-6 py-4 text-sm text-gray-500">{{.Description}}</td> 185 + <tr class="hover:bg-brown-100/60 transition-colors"> 186 + <td class="px-6 py-4 text-sm font-medium text-brown-900">{{.Name}}</td> 187 + <td class="px-6 py-4 text-sm text-brown-700">{{.Description}}</td> 188 188 <td class="px-6 py-4 text-sm font-medium space-x-2"> 189 189 <button @click="editBrewer('{{.RKey}}', '{{.Name}}', '{{.Description}}')" 190 - class="text-blue-600 hover:text-blue-900">Edit</button> 190 + class="text-brown-700 hover:text-brown-900 font-medium">Edit</button> 191 191 <button @click="deleteBrewer('{{.RKey}}')" 192 - class="text-red-600 hover:text-red-900">Delete</button> 192 + class="text-brown-600 hover:text-brown-800 font-medium">Delete</button> 193 193 </td> 194 194 </tr> 195 195 {{end}} ··· 200 200 </div> 201 201 202 202 <!-- Bean Form Modal --> 203 - <div x-cloak x-show="showBeanForm" class="fixed inset-0 bg-gray-500 bg-opacity-75 flex items-center justify-center z-50"> 204 - <div class="bg-brown-100 rounded-lg border border-brown-300 p-8 max-w-md w-full mx-4"> 205 - <h3 class="text-xl font-semibold mb-4 text-gray-800" x-text="editingBean ? 'Edit Bean' : 'Add Bean'"></h3> 203 + <div x-cloak x-show="showBeanForm" class="fixed inset-0 bg-brown-900/75 flex items-center justify-center z-50"> 204 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl border-2 border-brown-300 p-8 max-w-md w-full mx-4 shadow-2xl"> 205 + <h3 class="text-xl font-semibold mb-4 text-brown-900" x-text="editingBean ? 'Edit Bean' : 'Add Bean'"></h3> 206 206 <div class="space-y-4"> 207 207 <input type="text" x-model="beanForm.name" placeholder="Name *" 208 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3" /> 208 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600" /> 209 209 <input type="text" x-model="beanForm.origin" placeholder="Origin *" 210 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3" /> 211 - <select x-model="beanForm.roaster_rkey" class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3"> 210 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600" /> 211 + <select x-model="beanForm.roaster_rkey" class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600"> 212 212 <option value="">Select Roaster (Optional)</option> 213 213 {{range .Roasters}} 214 214 <option value="{{.RKey}}">{{.Name}}</option> 215 215 {{end}} 216 216 </select> 217 - <select x-model="beanForm.roast_level" class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3"> 217 + <select x-model="beanForm.roast_level" class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600"> 218 218 <option value="">Select Roast Level (Optional)</option> 219 219 <option value="Ultra-Light">Ultra-Light</option> 220 220 <option value="Light">Light</option> ··· 224 224 <option value="Dark">Dark</option> 225 225 </select> 226 226 <input type="text" x-model="beanForm.process" placeholder="Process (e.g. Washed, Natural, Honey)" 227 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3" /> 227 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600" /> 228 228 <textarea x-model="beanForm.description" placeholder="Description" rows="3" 229 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3"></textarea> 229 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600"></textarea> 230 230 <div class="flex gap-2"> 231 231 <button @click="saveBean()" 232 - class="flex-1 bg-brown-600 text-white px-4 py-2 rounded hover:bg-brown-700">Save</button> 232 + class="flex-1 bg-gradient-to-r from-brown-700 to-brown-800 text-white px-4 py-2 rounded-lg hover:from-brown-800 hover:to-brown-900 font-medium transition-all shadow-md">Save</button> 233 233 <button @click="showBeanForm = false" 234 - class="flex-1 bg-gray-300 px-4 py-2 rounded hover:bg-gray-400">Cancel</button> 234 + class="flex-1 bg-brown-300 text-brown-900 px-4 py-2 rounded-lg hover:bg-brown-400 font-medium transition-colors">Cancel</button> 235 235 </div> 236 236 </div> 237 237 </div> 238 238 </div> 239 239 240 240 <!-- Roaster Form Modal --> 241 - <div x-cloak x-show="showRoasterForm" class="fixed inset-0 bg-gray-500 bg-opacity-75 flex items-center justify-center z-50"> 242 - <div class="bg-brown-100 rounded-lg border border-brown-300 p-8 max-w-md w-full mx-4"> 243 - <h3 class="text-xl font-semibold mb-4 text-gray-800" x-text="editingRoaster ? 'Edit Roaster' : 'Add Roaster'"></h3> 241 + <div x-cloak x-show="showRoasterForm" class="fixed inset-0 bg-brown-900/75 flex items-center justify-center z-50"> 242 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl border-2 border-brown-300 p-8 max-w-md w-full mx-4 shadow-2xl"> 243 + <h3 class="text-xl font-semibold mb-4 text-brown-900" x-text="editingRoaster ? 'Edit Roaster' : 'Add Roaster'"></h3> 244 244 <div class="space-y-4"> 245 245 <input type="text" x-model="roasterForm.name" placeholder="Name *" 246 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3" /> 246 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600" /> 247 247 <input type="text" x-model="roasterForm.location" placeholder="Location" 248 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3" /> 248 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600" /> 249 249 <input type="url" x-model="roasterForm.website" placeholder="Website" 250 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3" /> 250 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600" /> 251 251 <div class="flex gap-2"> 252 252 <button @click="saveRoaster()" 253 - class="flex-1 bg-brown-600 text-white px-4 py-2 rounded hover:bg-brown-700">Save</button> 253 + class="flex-1 bg-gradient-to-r from-brown-700 to-brown-800 text-white px-4 py-2 rounded-lg hover:from-brown-800 hover:to-brown-900 font-medium transition-all shadow-md">Save</button> 254 254 <button @click="showRoasterForm = false" 255 - class="flex-1 bg-gray-300 px-4 py-2 rounded hover:bg-gray-400">Cancel</button> 255 + class="flex-1 bg-brown-300 text-brown-900 px-4 py-2 rounded-lg hover:bg-brown-400 font-medium transition-colors">Cancel</button> 256 256 </div> 257 257 </div> 258 258 </div> 259 259 </div> 260 260 261 261 <!-- Grinder Form Modal --> 262 - <div x-cloak x-show="showGrinderForm" class="fixed inset-0 bg-gray-500 bg-opacity-75 flex items-center justify-center z-50"> 263 - <div class="bg-brown-100 rounded-lg border border-brown-300 p-8 max-w-md w-full mx-4"> 264 - <h3 class="text-xl font-semibold mb-4 text-gray-800" x-text="editingGrinder ? 'Edit Grinder' : 'Add Grinder'"></h3> 262 + <div x-cloak x-show="showGrinderForm" class="fixed inset-0 bg-brown-900/75 flex items-center justify-center z-50"> 263 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl border-2 border-brown-300 p-8 max-w-md w-full mx-4 shadow-2xl"> 264 + <h3 class="text-xl font-semibold mb-4 text-brown-900" x-text="editingGrinder ? 'Edit Grinder' : 'Add Grinder'"></h3> 265 265 <div class="space-y-4"> 266 266 <input type="text" x-model="grinderForm.name" placeholder="Name *" 267 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3" /> 268 - <select x-model="grinderForm.grinder_type" class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3"> 267 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600" /> 268 + <select x-model="grinderForm.grinder_type" class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600"> 269 269 <option value="">Select Grinder Type *</option> 270 270 <option value="Hand">Hand</option> 271 271 <option value="Electric">Electric</option> 272 272 <option value="Portable Electric">Portable Electric</option> 273 273 </select> 274 - <select x-model="grinderForm.burr_type" class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3"> 274 + <select x-model="grinderForm.burr_type" class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600"> 275 275 <option value="">Select Burr Type (Optional)</option> 276 276 <option value="Conical">Conical</option> 277 277 <option value="Flat">Flat</option> 278 278 </select> 279 279 <textarea x-model="grinderForm.notes" placeholder="Notes" rows="3" 280 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3"></textarea> 280 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600"></textarea> 281 281 <div class="flex gap-2"> 282 282 <button @click="saveGrinder()" 283 - class="flex-1 bg-brown-600 text-white px-4 py-2 rounded hover:bg-brown-700">Save</button> 283 + class="flex-1 bg-gradient-to-r from-brown-700 to-brown-800 text-white px-4 py-2 rounded-lg hover:from-brown-800 hover:to-brown-900 font-medium transition-all shadow-md">Save</button> 284 284 <button @click="showGrinderForm = false" 285 - class="flex-1 bg-gray-300 px-4 py-2 rounded hover:bg-gray-400">Cancel</button> 285 + class="flex-1 bg-brown-300 text-brown-900 px-4 py-2 rounded-lg hover:bg-brown-400 font-medium transition-colors">Cancel</button> 286 286 </div> 287 287 </div> 288 288 </div> 289 289 </div> 290 290 291 291 <!-- Brewer Form Modal --> 292 - <div x-cloak x-show="showBrewerForm" class="fixed inset-0 bg-gray-500 bg-opacity-75 flex items-center justify-center z-50"> 293 - <div class="bg-brown-100 rounded-lg border border-brown-300 p-8 max-w-md w-full mx-4"> 294 - <h3 class="text-xl font-semibold mb-4 text-gray-800" x-text="editingBrewer ? 'Edit Brewer' : 'Add Brewer'"></h3> 292 + <div x-cloak x-show="showBrewerForm" class="fixed inset-0 bg-brown-900/75 flex items-center justify-center z-50"> 293 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl border-2 border-brown-300 p-8 max-w-md w-full mx-4 shadow-2xl"> 294 + <h3 class="text-xl font-semibold mb-4 text-brown-900" x-text="editingBrewer ? 'Edit Brewer' : 'Add Brewer'"></h3> 295 295 <div class="space-y-4"> 296 296 <input type="text" x-model="brewerForm.name" placeholder="Name *" 297 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3" /> 297 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600" /> 298 298 <textarea x-model="brewerForm.description" placeholder="Description" rows="3" 299 - class="w-full rounded-md border-gray-300 bg-white shadow-sm py-2 px-3"></textarea> 299 + class="w-full rounded-lg border-2 border-brown-300 bg-white shadow-sm py-2 px-3 focus:border-brown-600 focus:ring-brown-600"></textarea> 300 300 <div class="flex gap-2"> 301 301 <button @click="saveBrewer()" 302 - class="flex-1 bg-brown-600 text-white px-4 py-2 rounded hover:bg-brown-700">Save</button> 302 + class="flex-1 bg-gradient-to-r from-brown-700 to-brown-800 text-white px-4 py-2 rounded-lg hover:from-brown-800 hover:to-brown-900 font-medium transition-all shadow-md">Save</button> 303 303 <button @click="showBrewerForm = false" 304 - class="flex-1 bg-gray-300 px-4 py-2 rounded hover:bg-gray-400">Cancel</button> 304 + class="flex-1 bg-brown-300 text-brown-900 px-4 py-2 rounded-lg hover:bg-brown-400 font-medium transition-colors">Cancel</button> 305 305 </div> 306 306 </div> 307 307 </div>
+67 -67
templates/profile.tmpl
··· 1 1 {{define "content"}} 2 2 <div class="max-w-4xl mx-auto"> 3 3 <!-- Profile Header --> 4 - <div class="bg-white rounded-lg shadow-md p-6 mb-6"> 4 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-xl p-6 mb-6 border border-brown-300"> 5 5 <div class="flex items-center gap-4"> 6 6 {{if .Profile.Avatar}} 7 7 {{$safeAvatar := safeAvatarURL .Profile.Avatar}} 8 8 {{if $safeAvatar}} 9 - <img src="{{$safeAvatar}}" alt="" class="w-20 h-20 rounded-full object-cover" /> 9 + <img src="{{$safeAvatar}}" alt="" class="w-20 h-20 rounded-full object-cover border-2 border-brown-300" /> 10 10 {{else}} 11 - <div class="w-20 h-20 rounded-full bg-gray-300 flex items-center justify-center"> 12 - <span class="text-gray-500 text-2xl">?</span> 11 + <div class="w-20 h-20 rounded-full bg-brown-300 flex items-center justify-center"> 12 + <span class="text-brown-600 text-2xl">?</span> 13 13 </div> 14 14 {{end}} 15 15 {{else}} 16 - <div class="w-20 h-20 rounded-full bg-gray-300 flex items-center justify-center"> 17 - <span class="text-gray-500 text-2xl">?</span> 16 + <div class="w-20 h-20 rounded-full bg-brown-300 flex items-center justify-center"> 17 + <span class="text-brown-600 text-2xl">?</span> 18 18 </div> 19 19 {{end}} 20 20 <div> 21 21 {{if .Profile.DisplayName}} 22 - <h1 class="text-2xl font-bold text-gray-900">{{.Profile.DisplayName}}</h1> 22 + <h1 class="text-2xl font-bold text-brown-900">{{.Profile.DisplayName}}</h1> 23 23 {{end}} 24 - <p class="text-gray-600">@{{.Profile.Handle}}</p> 24 + <p class="text-brown-700">@{{.Profile.Handle}}</p> 25 25 </div> 26 26 </div> 27 27 </div> 28 28 29 29 <!-- Stats --> 30 30 <div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6"> 31 - <div class="bg-white rounded-lg shadow-sm p-4 text-center"> 32 - <div class="text-2xl font-bold text-brown-700">{{len .Brews}}</div> 33 - <div class="text-sm text-gray-600">Brews</div> 31 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 32 + <div class="text-2xl font-bold text-brown-800">{{len .Brews}}</div> 33 + <div class="text-sm text-brown-700">Brews</div> 34 34 </div> 35 - <div class="bg-white rounded-lg shadow-sm p-4 text-center"> 36 - <div class="text-2xl font-bold text-brown-700">{{len .Beans}}</div> 37 - <div class="text-sm text-gray-600">Beans</div> 35 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 36 + <div class="text-2xl font-bold text-brown-800">{{len .Beans}}</div> 37 + <div class="text-sm text-brown-700">Beans</div> 38 38 </div> 39 - <div class="bg-white rounded-lg shadow-sm p-4 text-center"> 40 - <div class="text-2xl font-bold text-brown-700">{{len .Roasters}}</div> 41 - <div class="text-sm text-gray-600">Roasters</div> 39 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 40 + <div class="text-2xl font-bold text-brown-800">{{len .Roasters}}</div> 41 + <div class="text-sm text-brown-700">Roasters</div> 42 42 </div> 43 - <div class="bg-white rounded-lg shadow-sm p-4 text-center"> 44 - <div class="text-2xl font-bold text-brown-700">{{len .Grinders}}</div> 45 - <div class="text-sm text-gray-600">Grinders</div> 43 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 44 + <div class="text-2xl font-bold text-brown-800">{{len .Grinders}}</div> 45 + <div class="text-sm text-brown-700">Grinders</div> 46 46 </div> 47 - <div class="bg-white rounded-lg shadow-sm p-4 text-center"> 48 - <div class="text-2xl font-bold text-brown-700">{{len .Brewers}}</div> 49 - <div class="text-sm text-gray-600">Brewers</div> 47 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 48 + <div class="text-2xl font-bold text-brown-800">{{len .Brewers}}</div> 49 + <div class="text-sm text-brown-700">Brewers</div> 50 50 </div> 51 51 </div> 52 52 53 53 <!-- Tabs for content sections --> 54 54 <div x-data="{ activeTab: 'brews' }"> 55 55 <!-- Tab buttons --> 56 - <div class="bg-white rounded-lg shadow-sm mb-4"> 57 - <div class="flex border-b"> 56 + <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-xl shadow-md mb-4 border border-brown-300"> 57 + <div class="flex border-b border-brown-300"> 58 58 <button 59 59 @click="activeTab = 'brews'" 60 - :class="activeTab === 'brews' ? 'border-b-2 border-brown-600 text-brown-700' : 'text-gray-500 hover:text-gray-700'" 60 + :class="activeTab === 'brews' ? 'border-b-2 border-brown-700 text-brown-900' : 'text-brown-600 hover:text-brown-800'" 61 61 class="flex-1 py-3 px-4 text-center font-medium transition-colors"> 62 62 Brews 63 63 </button> 64 64 <button 65 65 @click="activeTab = 'beans'" 66 - :class="activeTab === 'beans' ? 'border-b-2 border-brown-600 text-brown-700' : 'text-gray-500 hover:text-gray-700'" 66 + :class="activeTab === 'beans' ? 'border-b-2 border-brown-700 text-brown-900' : 'text-brown-600 hover:text-brown-800'" 67 67 class="flex-1 py-3 px-4 text-center font-medium transition-colors"> 68 68 Beans 69 69 </button> 70 70 <button 71 71 @click="activeTab = 'gear'" 72 - :class="activeTab === 'gear' ? 'border-b-2 border-brown-600 text-brown-700' : 'text-gray-500 hover:text-gray-700'" 72 + :class="activeTab === 'gear' ? 'border-b-2 border-brown-700 text-brown-900' : 'text-brown-600 hover:text-brown-800'" 73 73 class="flex-1 py-3 px-4 text-center font-medium transition-colors"> 74 74 Gear 75 75 </button> ··· 80 80 <div x-show="activeTab === 'brews'" class="space-y-4"> 81 81 {{if .Brews}} 82 82 {{range .Brews}} 83 - <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4"> 83 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 rounded-lg shadow-md border border-brown-200 p-4"> 84 84 <!-- Brew info --> 85 - <div class="bg-gray-50 rounded-lg p-3"> 85 + <div class="bg-white/60 backdrop-blur rounded-lg p-3 border border-brown-200"> 86 86 <!-- Bean and roaster info --> 87 87 <div class="flex items-start justify-between gap-2 mb-2"> 88 88 <div class="flex-1 min-w-0"> 89 89 {{if .Bean}} 90 90 <div class="text-base"> 91 - <span class="text-gray-600">Bean:</span> 92 - <span class="font-bold text-gray-900"> 91 + <span class="text-brown-700">Bean:</span> 92 + <span class="font-bold text-brown-900"> 93 93 {{if .Bean.Name}}{{.Bean.Name}}{{else}}{{.Bean.Origin}}{{end}}{{if and .Bean.Roaster .Bean.Roaster.Name}} - {{.Bean.Roaster.Name}}{{end}} 94 94 </span> 95 95 </div> 96 - <div class="text-sm text-gray-600"> 96 + <div class="text-sm text-brown-600"> 97 97 {{if .Bean.Process}}{{.Bean.Process}}{{end}}{{if and .Bean.Process .Bean.RoastLevel}} | {{end}}{{if .Bean.RoastLevel}}{{.Bean.RoastLevel}}{{end}}{{if and (or .Bean.Process .Bean.RoastLevel) .Bean.Origin}} | {{end}}{{if .Bean.Origin}}{{.Bean.Origin}}{{end}} 98 98 </div> 99 99 {{end}} 100 100 </div> 101 101 {{if hasValue .Rating}} 102 - <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 flex-shrink-0"> 102 + <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-900 flex-shrink-0"> 103 103 {{.Rating}}/10 104 104 </span> 105 105 {{end}} 106 106 </div> 107 107 108 108 <!-- Brew parameters --> 109 - <div class="grid grid-cols-2 gap-2 text-sm text-gray-600"> 109 + <div class="grid grid-cols-2 gap-2 text-sm text-brown-700"> 110 110 {{if hasValue .CoffeeAmount}} 111 111 <div> 112 - <span class="text-gray-500">Coffee:</span> {{.CoffeeAmount}}g 112 + <span class="text-brown-600">Coffee:</span> {{.CoffeeAmount}}g 113 113 </div> 114 114 {{end}} 115 115 {{if hasValue .WaterAmount}} 116 116 <div> 117 - <span class="text-gray-500">Water:</span> {{.WaterAmount}}g 117 + <span class="text-brown-600">Water:</span> {{.WaterAmount}}g 118 118 </div> 119 119 {{end}} 120 120 {{if hasTemp .Temperature}} 121 121 <div> 122 - <span class="text-gray-500">Temp:</span> {{formatTemp .Temperature}} 122 + <span class="text-brown-600">Temp:</span> {{formatTemp .Temperature}} 123 123 </div> 124 124 {{end}} 125 125 {{if hasValue .TimeSeconds}} 126 126 <div> 127 - <span class="text-gray-500">Time:</span> {{formatTime .TimeSeconds}} 127 + <span class="text-brown-600">Time:</span> {{formatTime .TimeSeconds}} 128 128 </div> 129 129 {{end}} 130 130 {{if .GrindSize}} 131 131 <div> 132 - <span class="text-gray-500">Grind:</span> {{.GrindSize}}{{if .GrinderObj}} ({{.GrinderObj.Name}}){{end}} 132 + <span class="text-brown-600">Grind:</span> {{.GrindSize}}{{if .GrinderObj}} ({{.GrinderObj.Name}}){{end}} 133 133 </div> 134 134 {{end}} 135 135 <div> 136 - <span class="text-gray-500">Brewer:</span> <span class="font-bold text-gray-900">{{if .BrewerObj}}{{.BrewerObj.Name}}{{else if .Method}}{{.Method}}{{else}}-{{end}}</span> 136 + <span class="text-brown-600">Brewer:</span> <span class="font-bold text-brown-900">{{if .BrewerObj}}{{.BrewerObj.Name}}{{else if .Method}}{{.Method}}{{else}}-{{end}}</span> 137 137 </div> 138 138 </div> 139 139 140 140 {{if .TastingNotes}} 141 - <div class="mt-3 text-sm text-gray-700 italic border-t border-gray-200 pt-2"> 141 + <div class="mt-3 text-sm text-brown-800 italic border-t border-brown-200 pt-2"> 142 142 "{{.TastingNotes}}" 143 143 </div> 144 144 {{end}} ··· 146 146 </div> 147 147 {{end}} 148 148 {{else}} 149 - <div class="bg-gray-50 rounded-lg p-6 text-center text-gray-500"> 149 + <div class="bg-brown-100 rounded-lg p-6 text-center text-brown-700 border border-brown-200"> 150 150 <p>No brews yet.</p> 151 151 </div> 152 152 {{end}} ··· 156 156 <div x-show="activeTab === 'beans'" x-cloak class="space-y-4"> 157 157 {{if .Beans}} 158 158 {{range .Beans}} 159 - <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4"> 159 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 rounded-lg shadow-md border border-brown-200 p-4"> 160 160 <div class="text-base mb-2"> 161 - <span class="font-bold text-gray-900"> 161 + <span class="font-bold text-brown-900"> 162 162 {{if .Name}}{{.Name}}{{else}}{{.Origin}}{{end}} 163 163 </span> 164 164 {{if and .Roaster .Roaster.Name}} 165 - <span class="text-gray-600"> from {{.Roaster.Name}}</span> 165 + <span class="text-brown-700"> from {{.Roaster.Name}}</span> 166 166 {{end}} 167 167 </div> 168 - <div class="text-sm text-gray-600 space-y-1"> 168 + <div class="text-sm text-brown-700 space-y-1"> 169 169 {{if .Origin}} 170 - <div><span class="text-gray-500">Origin:</span> {{.Origin}}</div> 170 + <div><span class="text-brown-600">Origin:</span> {{.Origin}}</div> 171 171 {{end}} 172 172 {{if .RoastLevel}} 173 - <div><span class="text-gray-500">Roast:</span> {{.RoastLevel}}</div> 173 + <div><span class="text-brown-600">Roast:</span> {{.RoastLevel}}</div> 174 174 {{end}} 175 175 {{if .Process}} 176 - <div><span class="text-gray-500">Process:</span> {{.Process}}</div> 176 + <div><span class="text-brown-600">Process:</span> {{.Process}}</div> 177 177 {{end}} 178 178 {{if .Description}} 179 - <div class="mt-2 text-gray-700 italic">"{{.Description}}"</div> 179 + <div class="mt-2 text-brown-800 italic">"{{.Description}}"</div> 180 180 {{end}} 181 181 </div> 182 182 </div> 183 183 {{end}} 184 184 {{else}} 185 - <div class="bg-gray-50 rounded-lg p-6 text-center text-gray-500"> 185 + <div class="bg-brown-100 rounded-lg p-6 text-center text-brown-700 border border-brown-200"> 186 186 <p>No beans yet.</p> 187 187 </div> 188 188 {{end}} ··· 193 193 <!-- Grinders --> 194 194 {{if .Grinders}} 195 195 <div> 196 - <h3 class="text-lg font-semibold text-gray-800 mb-3">Grinders</h3> 196 + <h3 class="text-lg font-semibold text-brown-900 mb-3">Grinders</h3> 197 197 <div class="space-y-3"> 198 198 {{range .Grinders}} 199 - <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4"> 200 - <div class="font-bold text-gray-900">{{.Name}}</div> 201 - <div class="text-sm text-gray-600 mt-1"> 199 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 rounded-lg shadow-md border border-brown-200 p-4"> 200 + <div class="font-bold text-brown-900">{{.Name}}</div> 201 + <div class="text-sm text-brown-700 mt-1"> 202 202 {{if .GrinderType}}<span>{{.GrinderType}}</span>{{end}} 203 203 {{if .BurrType}}<span class="ml-2">| {{.BurrType}} burrs</span>{{end}} 204 204 </div> 205 205 {{if .Notes}} 206 - <div class="mt-2 text-sm text-gray-700 italic">"{{.Notes}}"</div> 206 + <div class="mt-2 text-sm text-brown-800 italic">"{{.Notes}}"</div> 207 207 {{end}} 208 208 </div> 209 209 {{end}} ··· 214 214 <!-- Brewers --> 215 215 {{if .Brewers}} 216 216 <div> 217 - <h3 class="text-lg font-semibold text-gray-800 mb-3">Brewers</h3> 217 + <h3 class="text-lg font-semibold text-brown-900 mb-3">Brewers</h3> 218 218 <div class="space-y-3"> 219 219 {{range .Brewers}} 220 - <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4"> 221 - <div class="font-bold text-gray-900">{{.Name}}</div> 220 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 rounded-lg shadow-md border border-brown-200 p-4"> 221 + <div class="font-bold text-brown-900">{{.Name}}</div> 222 222 {{if .Description}} 223 - <div class="mt-1 text-sm text-gray-700 italic">"{{.Description}}"</div> 223 + <div class="mt-1 text-sm text-brown-800 italic">"{{.Description}}"</div> 224 224 {{end}} 225 225 </div> 226 226 {{end}} ··· 231 231 <!-- Roasters --> 232 232 {{if .Roasters}} 233 233 <div> 234 - <h3 class="text-lg font-semibold text-gray-800 mb-3">Favorite Roasters</h3> 234 + <h3 class="text-lg font-semibold text-brown-900 mb-3">Favorite Roasters</h3> 235 235 <div class="space-y-3"> 236 236 {{range .Roasters}} 237 - <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4"> 238 - <div class="font-bold text-gray-900">{{.Name}}</div> 239 - <div class="text-sm text-gray-600 mt-1"> 237 + <div class="bg-gradient-to-br from-brown-50 to-brown-100 rounded-lg shadow-md border border-brown-200 p-4"> 238 + <div class="font-bold text-brown-900">{{.Name}}</div> 239 + <div class="text-sm text-brown-700 mt-1"> 240 240 {{if .Location}}<span>{{.Location}}</span>{{end}} 241 241 {{if .Website}} 242 242 {{$safeWebsite := safeWebsiteURL .Website}} 243 243 {{if $safeWebsite}} 244 - <a href="{{$safeWebsite}}" target="_blank" rel="noopener noreferrer" class="text-blue-600 hover:underline ml-2">{{$safeWebsite}}</a> 244 + <a href="{{$safeWebsite}}" target="_blank" rel="noopener noreferrer" class="text-brown-800 hover:underline ml-2">{{$safeWebsite}}</a> 245 245 {{end}} 246 246 {{end}} 247 247 </div> ··· 252 252 {{end}} 253 253 254 254 {{if and (not .Grinders) (not .Brewers) (not .Roasters)}} 255 - <div class="bg-gray-50 rounded-lg p-6 text-center text-gray-500"> 255 + <div class="bg-brown-100 rounded-lg p-6 text-center text-brown-700 border border-brown-200"> 256 256 <p>No gear added yet.</p> 257 257 </div> 258 258 {{end}}
+4
web/static/favicon-32.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> 2 + <rect width="32" height="32" fill="#4a2c2a" rx="4"/> 3 + <text x="16" y="24" font-size="20" text-anchor="middle">☕</text> 4 + </svg>
+4
web/static/favicon.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> 2 + <rect width="100" height="100" fill="#4a2c2a" rx="15"/> 3 + <text x="50" y="72" font-size="60" text-anchor="middle">☕</text> 4 + </svg>
+4
web/static/icon-192.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 192"> 2 + <rect width="192" height="192" fill="#4a2c2a" rx="30"/> 3 + <text x="96" y="140" font-size="120" text-anchor="middle">☕</text> 4 + </svg>
+4
web/static/icon-512.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> 2 + <rect width="512" height="512" fill="#4a2c2a" rx="80"/> 3 + <text x="256" y="380" font-size="320" text-anchor="middle">☕</text> 4 + </svg>
+10 -4
web/static/manifest.json
··· 9 9 "orientation": "portrait", 10 10 "icons": [ 11 11 { 12 - "src": "/static/icon-192.png", 12 + "src": "/static/favicon.svg", 13 + "sizes": "any", 14 + "type": "image/svg+xml", 15 + "purpose": "any" 16 + }, 17 + { 18 + "src": "/static/icon-192.svg", 13 19 "sizes": "192x192", 14 - "type": "image/png", 20 + "type": "image/svg+xml", 15 21 "purpose": "any maskable" 16 22 }, 17 23 { 18 - "src": "/static/icon-512.png", 24 + "src": "/static/icon-512.svg", 19 25 "sizes": "512x512", 20 - "type": "image/png", 26 + "type": "image/svg+xml", 21 27 "purpose": "any maskable" 22 28 } 23 29 ]