tangled
alpha
login
or
join now
arabica.social
/
arabica
7
fork
atom
Coffee journaling on ATProto (alpha)
alpha.arabica.social
coffee
7
fork
atom
overview
issues
pulls
pipelines
fix: misc fixes
pdewey.com
1 month ago
46a20b5b
1045c338
verified
This commit was signed with the committer's
known signature
.
pdewey.com
SSH Key Fingerprint:
SHA256:ePOVkJstqVLchGK8m9/OGQG+aFNHD5XN3xjvW9wKCA4=
+42
-33
3 changed files
expand all
collapse all
unified
split
frontend
src
components
Modal.svelte
routes
BrewForm.svelte
web
static
app
index.html
-1
frontend/src/components/Modal.svelte
···
1
<script>
2
-
export let label;
3
export let onSave;
4
export let onCancel;
5
export let isOpen = false;
···
1
<script>
0
2
export let onSave;
3
export let onCancel;
4
export let isOpen = false;
+41
-31
frontend/src/routes/BrewForm.svelte
···
215
<form on:submit|preventDefault={handleSubmit} class="space-y-6">
216
<!-- Bean Selection -->
217
<div>
218
-
<label class="block text-sm font-medium text-brown-900 mb-2">Coffee Bean *</label>
219
<div class="flex gap-2">
220
<select
0
221
bind:value={form.bean_rkey}
222
required
223
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"
···
241
242
<!-- Coffee Amount -->
243
<div>
244
-
<label class="block text-sm font-medium text-brown-900 mb-2">Coffee Amount (grams)</label>
245
<input
0
246
type="number"
247
bind:value={form.coffee_amount}
248
step="0.1"
···
254
255
<!-- Grinder -->
256
<div>
257
-
<label class="block text-sm font-medium text-brown-900 mb-2">Grinder</label>
258
<div class="flex gap-2">
259
<select
0
260
bind:value={form.grinder_rkey}
261
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"
262
>
···
277
278
<!-- Grind Size -->
279
<div>
280
-
<label class="block text-sm font-medium text-brown-900 mb-2">Grind Size</label>
281
<input
0
282
type="text"
283
bind:value={form.grind_size}
284
placeholder="e.g. 18, Medium, 3.5, Fine"
···
289
290
<!-- Brew Method -->
291
<div>
292
-
<label class="block text-sm font-medium text-brown-900 mb-2">Brew Method</label>
293
<div class="flex gap-2">
294
<select
0
295
bind:value={form.brewer_rkey}
296
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"
297
>
···
312
313
<!-- Water Amount -->
314
<div>
315
-
<label class="block text-sm font-medium text-brown-900 mb-2">Water Amount (ml)</label>
316
<input
0
317
type="number"
318
bind:value={form.water_amount}
319
step="1"
···
324
325
<!-- Water Temperature -->
326
<div>
327
-
<label class="block text-sm font-medium text-brown-900 mb-2">Water Temperature (°C)</label>
328
<input
0
329
type="number"
330
bind:value={form.water_temp}
331
step="0.1"
···
336
337
<!-- Brew Time -->
338
<div>
339
-
<label class="block text-sm font-medium text-brown-900 mb-2">Total Brew Time (seconds)</label>
340
<input
0
341
type="number"
342
bind:value={form.brew_time}
343
step="1"
···
349
<!-- Pours -->
350
<div>
351
<div class="flex items-center justify-between mb-2">
352
-
<label class="block text-sm font-medium text-brown-900">Pour Schedule (Optional)</label>
353
<button
354
type="button"
355
on:click={addPour}
···
391
392
<!-- Rating -->
393
<div>
394
-
<label class="block text-sm font-medium text-brown-900 mb-2">
395
Rating: <span class="font-bold">{form.rating}/10</span>
396
</label>
397
<input
0
398
type="range"
399
bind:value={form.rating}
400
min="0"
···
410
411
<!-- Notes -->
412
<div>
413
-
<label class="block text-sm font-medium text-brown-900 mb-2">Tasting Notes</label>
414
<textarea
0
415
bind:value={form.notes}
416
rows="4"
417
placeholder="Describe the flavor, aroma, body, etc."
···
450
>
451
<div class="space-y-4">
452
<div>
453
-
<label class="block text-sm font-medium text-gray-700 mb-1">Name</label>
454
-
<input type="text" bind:value={beanForm.name} class="w-full rounded border-gray-300 px-3 py-2" />
455
</div>
456
<div>
457
-
<label class="block text-sm font-medium text-gray-700 mb-1">Origin *</label>
458
-
<input type="text" bind:value={beanForm.origin} required class="w-full rounded border-gray-300 px-3 py-2" />
459
</div>
460
<div>
461
-
<label class="block text-sm font-medium text-gray-700 mb-1">Roast Level *</label>
462
-
<select bind:value={beanForm.roast_level} required class="w-full rounded border-gray-300 px-3 py-2">
463
<option value="">Select...</option>
464
<option value="Light">Light</option>
465
<option value="Medium-Light">Medium-Light</option>
···
469
</select>
470
</div>
471
<div>
472
-
<label class="block text-sm font-medium text-gray-700 mb-1">Roaster</label>
473
<div class="flex gap-2">
474
-
<select bind:value={beanForm.roaster_rkey} class="flex-1 rounded border-gray-300 px-3 py-2">
475
<option value="">Select...</option>
476
{#each roasters as roaster}
477
<option value={roaster.rkey}>{roaster.name}</option>
···
497
>
498
<div class="space-y-4">
499
<div>
500
-
<label class="block text-sm font-medium text-gray-700 mb-1">Name *</label>
501
-
<input type="text" bind:value={roasterForm.name} required class="w-full rounded border-gray-300 px-3 py-2" />
502
</div>
503
<div>
504
-
<label class="block text-sm font-medium text-gray-700 mb-1">Location</label>
505
-
<input type="text" bind:value={roasterForm.location} class="w-full rounded border-gray-300 px-3 py-2" />
506
</div>
507
</div>
508
</Modal>
···
515
>
516
<div class="space-y-4">
517
<div>
518
-
<label class="block text-sm font-medium text-gray-700 mb-1">Name *</label>
519
-
<input type="text" bind:value={grinderForm.name} required class="w-full rounded border-gray-300 px-3 py-2" />
520
</div>
521
<div>
522
-
<label class="block text-sm font-medium text-gray-700 mb-1">Type</label>
523
-
<select bind:value={grinderForm.grinder_type} class="w-full rounded border-gray-300 px-3 py-2">
524
<option value="">Select...</option>
525
<option value="Manual">Manual</option>
526
<option value="Electric">Electric</option>
···
538
>
539
<div class="space-y-4">
540
<div>
541
-
<label class="block text-sm font-medium text-gray-700 mb-1">Name *</label>
542
-
<input type="text" bind:value={brewerForm.name} required class="w-full rounded border-gray-300 px-3 py-2" />
543
</div>
544
<div>
545
-
<label class="block text-sm font-medium text-gray-700 mb-1">Type</label>
546
-
<select bind:value={brewerForm.brewer_type} class="w-full rounded border-gray-300 px-3 py-2">
547
<option value="">Select...</option>
548
<option value="Pour Over">Pour Over</option>
549
<option value="French Press">French Press</option>
···
215
<form on:submit|preventDefault={handleSubmit} class="space-y-6">
216
<!-- Bean Selection -->
217
<div>
218
+
<label for="bean-select" class="block text-sm font-medium text-brown-900 mb-2">Coffee Bean *</label>
219
<div class="flex gap-2">
220
<select
221
+
id="bean-select"
222
bind:value={form.bean_rkey}
223
required
224
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"
···
242
243
<!-- Coffee Amount -->
244
<div>
245
+
<label for="coffee-amount" class="block text-sm font-medium text-brown-900 mb-2">Coffee Amount (grams)</label>
246
<input
247
+
id="coffee-amount"
248
type="number"
249
bind:value={form.coffee_amount}
250
step="0.1"
···
256
257
<!-- Grinder -->
258
<div>
259
+
<label for="grinder-select" class="block text-sm font-medium text-brown-900 mb-2">Grinder</label>
260
<div class="flex gap-2">
261
<select
262
+
id="grinder-select"
263
bind:value={form.grinder_rkey}
264
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"
265
>
···
280
281
<!-- Grind Size -->
282
<div>
283
+
<label for="grind-size" class="block text-sm font-medium text-brown-900 mb-2">Grind Size</label>
284
<input
285
+
id="grind-size"
286
type="text"
287
bind:value={form.grind_size}
288
placeholder="e.g. 18, Medium, 3.5, Fine"
···
293
294
<!-- Brew Method -->
295
<div>
296
+
<label for="brewer-select" class="block text-sm font-medium text-brown-900 mb-2">Brew Method</label>
297
<div class="flex gap-2">
298
<select
299
+
id="brewer-select"
300
bind:value={form.brewer_rkey}
301
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"
302
>
···
317
318
<!-- Water Amount -->
319
<div>
320
+
<label for="water-amount" class="block text-sm font-medium text-brown-900 mb-2">Water Amount (ml)</label>
321
<input
322
+
id="water-amount"
323
type="number"
324
bind:value={form.water_amount}
325
step="1"
···
330
331
<!-- Water Temperature -->
332
<div>
333
+
<label for="water-temp" class="block text-sm font-medium text-brown-900 mb-2">Water Temperature (°C)</label>
334
<input
335
+
id="water-temp"
336
type="number"
337
bind:value={form.water_temp}
338
step="0.1"
···
343
344
<!-- Brew Time -->
345
<div>
346
+
<label for="brew-time" class="block text-sm font-medium text-brown-900 mb-2">Total Brew Time (seconds)</label>
347
<input
348
+
id="brew-time"
349
type="number"
350
bind:value={form.brew_time}
351
step="1"
···
357
<!-- Pours -->
358
<div>
359
<div class="flex items-center justify-between mb-2">
360
+
<span class="block text-sm font-medium text-brown-900">Pour Schedule (Optional)</span>
361
<button
362
type="button"
363
on:click={addPour}
···
399
400
<!-- Rating -->
401
<div>
402
+
<label for="rating" class="block text-sm font-medium text-brown-900 mb-2">
403
Rating: <span class="font-bold">{form.rating}/10</span>
404
</label>
405
<input
406
+
id="rating"
407
type="range"
408
bind:value={form.rating}
409
min="0"
···
419
420
<!-- Notes -->
421
<div>
422
+
<label for="notes" class="block text-sm font-medium text-brown-900 mb-2">Tasting Notes</label>
423
<textarea
424
+
id="notes"
425
bind:value={form.notes}
426
rows="4"
427
placeholder="Describe the flavor, aroma, body, etc."
···
460
>
461
<div class="space-y-4">
462
<div>
463
+
<label for="bean-name" class="block text-sm font-medium text-gray-700 mb-1">Name</label>
464
+
<input id="bean-name" type="text" bind:value={beanForm.name} class="w-full rounded border-gray-300 px-3 py-2" />
465
</div>
466
<div>
467
+
<label for="bean-origin" class="block text-sm font-medium text-gray-700 mb-1">Origin *</label>
468
+
<input id="bean-origin" type="text" bind:value={beanForm.origin} required class="w-full rounded border-gray-300 px-3 py-2" />
469
</div>
470
<div>
471
+
<label for="bean-roast-level" class="block text-sm font-medium text-gray-700 mb-1">Roast Level *</label>
472
+
<select id="bean-roast-level" bind:value={beanForm.roast_level} required class="w-full rounded border-gray-300 px-3 py-2">
473
<option value="">Select...</option>
474
<option value="Light">Light</option>
475
<option value="Medium-Light">Medium-Light</option>
···
479
</select>
480
</div>
481
<div>
482
+
<label for="bean-roaster" class="block text-sm font-medium text-gray-700 mb-1">Roaster</label>
483
<div class="flex gap-2">
484
+
<select id="bean-roaster" bind:value={beanForm.roaster_rkey} class="flex-1 rounded border-gray-300 px-3 py-2">
485
<option value="">Select...</option>
486
{#each roasters as roaster}
487
<option value={roaster.rkey}>{roaster.name}</option>
···
507
>
508
<div class="space-y-4">
509
<div>
510
+
<label for="roaster-name" class="block text-sm font-medium text-gray-700 mb-1">Name *</label>
511
+
<input id="roaster-name" type="text" bind:value={roasterForm.name} required class="w-full rounded border-gray-300 px-3 py-2" />
512
</div>
513
<div>
514
+
<label for="roaster-location" class="block text-sm font-medium text-gray-700 mb-1">Location</label>
515
+
<input id="roaster-location" type="text" bind:value={roasterForm.location} class="w-full rounded border-gray-300 px-3 py-2" />
516
</div>
517
</div>
518
</Modal>
···
525
>
526
<div class="space-y-4">
527
<div>
528
+
<label for="grinder-name" class="block text-sm font-medium text-gray-700 mb-1">Name *</label>
529
+
<input id="grinder-name" type="text" bind:value={grinderForm.name} required class="w-full rounded border-gray-300 px-3 py-2" />
530
</div>
531
<div>
532
+
<label for="grinder-type" class="block text-sm font-medium text-gray-700 mb-1">Type</label>
533
+
<select id="grinder-type" bind:value={grinderForm.grinder_type} class="w-full rounded border-gray-300 px-3 py-2">
534
<option value="">Select...</option>
535
<option value="Manual">Manual</option>
536
<option value="Electric">Electric</option>
···
548
>
549
<div class="space-y-4">
550
<div>
551
+
<label for="brewer-name" class="block text-sm font-medium text-gray-700 mb-1">Name *</label>
552
+
<input id="brewer-name" type="text" bind:value={brewerForm.name} required class="w-full rounded border-gray-300 px-3 py-2" />
553
</div>
554
<div>
555
+
<label for="brewer-type" class="block text-sm font-medium text-gray-700 mb-1">Type</label>
556
+
<select id="brewer-type" bind:value={brewerForm.brewer_type} class="w-full rounded border-gray-300 px-3 py-2">
557
<option value="">Select...</option>
558
<option value="Pour Over">Pour Over</option>
559
<option value="French Press">French Press</option>
+1
-1
web/static/app/index.html
···
18
<!-- Web Manifest -->
19
<link rel="manifest" href="/static/manifest.json">
20
<meta name="theme-color" content="#78350f">
21
-
<script type="module" crossorigin src="/static/app/assets/index-PnQOiph1.js"></script>
22
<link rel="stylesheet" crossorigin href="/static/app/assets/index-C3lHx5fe.css">
23
</head>
24
<body class="bg-brown-50 text-brown-900 min-h-screen">
···
18
<!-- Web Manifest -->
19
<link rel="manifest" href="/static/manifest.json">
20
<meta name="theme-color" content="#78350f">
21
+
<script type="module" crossorigin src="/static/app/assets/index-D8yIXtJi.js"></script>
22
<link rel="stylesheet" crossorigin href="/static/app/assets/index-C3lHx5fe.css">
23
</head>
24
<body class="bg-brown-50 text-brown-900 min-h-screen">