apps/cellar/templates/wine_form.html 5.7 K raw
1
{{define "wine_form.html"}}{{template "base.html" .}}{{end}}
2
{{define "title"}}{{if .Wine}}Edit{{else}}New{{end}} Wine - Cellar{{end}}
3
{{define "content"}}
4
  {{if .Error}}<p class="error">{{.Error}}</p>{{end}}
5
  {{$w := .Wine}}
6
  <form method="POST" enctype="multipart/form-data"
7
    action="{{if $w}}/admin/edit/{{$w.ShortID}}{{else}}/admin/new{{end}}"
8
    class="form">
9
10
    <label for="image">image</label>
11
    <div class="image-upload-row">
12
      <input type="file" id="image" name="image" accept="image/*">
13
      {{if .HasAnthropicKey}}<button type="button" id="analyze-btn" onclick="analyzeImage()">analyze</button>{{end}}
14
    </div>
15
16
    <label for="name">name</label>
17
    <input type="text" id="name" name="name" required value="{{if $w}}{{$w.Name}}{{end}}">
18
19
    <label for="origin">origin</label>
20
    <input type="text" id="origin" name="origin" value="{{if $w}}{{$w.Origin}}{{end}}">
21
22
    <label for="grape">grape</label>
23
    <input type="text" id="grape" name="grape" value="{{if $w}}{{$w.Grape}}{{end}}">
24
25
    <label for="notes">notes</label>
26
    <textarea id="notes" name="notes" rows="5">{{if $w}}{{$w.Notes}}{{end}}</textarea>
27
28
    <label for="background">background</label>
29
    <textarea id="background" name="background" rows="5">{{if $w}}{{$w.Background}}{{end}}</textarea>
30
31
    <div class="score-group">
32
      <div class="score-section-label">appearance</div>
33
      <div class="score-row">
34
        <label for="clarity">clarity</label>
35
        <input type="range" id="clarity" name="clarity" min="1" max="5" value="{{if $w}}{{$w.Clarity}}{{else}}3{{end}}">
36
        <span class="score-value" data-for="clarity">{{if $w}}{{$w.Clarity}}{{else}}3{{end}}</span>
37
      </div>
38
      <div class="score-row">
39
        <label for="color_intensity">intensity</label>
40
        <input type="range" id="color_intensity" name="color_intensity" min="1" max="5" value="{{if $w}}{{$w.ColorIntensity}}{{else}}3{{end}}">
41
        <span class="score-value" data-for="color_intensity">{{if $w}}{{$w.ColorIntensity}}{{else}}3{{end}}</span>
42
      </div>
43
44
      <div class="score-section-label">nose</div>
45
      <div class="score-row">
46
        <label for="aroma_intensity">aroma</label>
47
        <input type="range" id="aroma_intensity" name="aroma_intensity" min="1" max="5" value="{{if $w}}{{$w.AromaIntensity}}{{else}}3{{end}}">
48
        <span class="score-value" data-for="aroma_intensity">{{if $w}}{{$w.AromaIntensity}}{{else}}3{{end}}</span>
49
      </div>
50
      <div class="score-row">
51
        <label for="nose_complexity">complexity</label>
52
        <input type="range" id="nose_complexity" name="nose_complexity" min="1" max="5" value="{{if $w}}{{$w.NoseComplexity}}{{else}}3{{end}}">
53
        <span class="score-value" data-for="nose_complexity">{{if $w}}{{$w.NoseComplexity}}{{else}}3{{end}}</span>
54
      </div>
55
56
      <div class="score-section-label">palate</div>
57
      <div class="score-row">
58
        <label for="sweetness">sweetness</label>
59
        <input type="range" id="sweetness" name="sweetness" min="1" max="5" value="{{if $w}}{{$w.Sweetness}}{{else}}3{{end}}">
60
        <span class="score-value" data-for="sweetness">{{if $w}}{{$w.Sweetness}}{{else}}3{{end}}</span>
61
      </div>
62
      <div class="score-row">
63
        <label for="acidity">acidity</label>
64
        <input type="range" id="acidity" name="acidity" min="1" max="5" value="{{if $w}}{{$w.Acidity}}{{else}}3{{end}}">
65
        <span class="score-value" data-for="acidity">{{if $w}}{{$w.Acidity}}{{else}}3{{end}}</span>
66
      </div>
67
      <div class="score-row">
68
        <label for="tannin">tannin</label>
69
        <input type="range" id="tannin" name="tannin" min="1" max="5" value="{{if $w}}{{$w.Tannin}}{{else}}3{{end}}">
70
        <span class="score-value" data-for="tannin">{{if $w}}{{$w.Tannin}}{{else}}3{{end}}</span>
71
      </div>
72
      <div class="score-row">
73
        <label for="alcohol">alcohol</label>
74
        <input type="range" id="alcohol" name="alcohol" min="1" max="5" value="{{if $w}}{{$w.Alcohol}}{{else}}3{{end}}">
75
        <span class="score-value" data-for="alcohol">{{if $w}}{{$w.Alcohol}}{{else}}3{{end}}</span>
76
      </div>
77
      <div class="score-row">
78
        <label for="body">body</label>
79
        <input type="range" id="body" name="body" min="1" max="5" value="{{if $w}}{{$w.Body}}{{else}}3{{end}}">
80
        <span class="score-value" data-for="body">{{if $w}}{{$w.Body}}{{else}}3{{end}}</span>
81
      </div>
82
    </div>
83
84
    <button type="submit">{{if $w}}update{{else}}create{{end}}</button>
85
  </form>
86
87
  <script>
88
    document.querySelectorAll('input[type="range"]').forEach(function(input) {
89
      input.addEventListener('input', function() {
90
        var span = document.querySelector('.score-value[data-for="' + this.id + '"]');
91
        if (span) span.textContent = this.value;
92
      });
93
    });
94
95
    {{if .HasAnthropicKey}}
96
    async function analyzeImage() {
97
      var fileInput = document.getElementById('image');
98
      if (!fileInput.files.length) return;
99
      var formData = new FormData();
100
      formData.append('image', fileInput.files[0]);
101
      var btn = document.getElementById('analyze-btn');
102
      btn.textContent = 'analyzing...';
103
      btn.disabled = true;
104
      try {
105
        var res = await fetch('/admin/analyze-image', { method: 'POST', body: formData });
106
        if (res.ok) {
107
          var data = await res.json();
108
          if (data.name) document.getElementById('name').value = data.name;
109
          if (data.origin) document.getElementById('origin').value = data.origin;
110
          if (data.grape) document.getElementById('grape').value = data.grape;
111
          if (data.background) document.getElementById('background').value = data.background;
112
        }
113
      } catch (e) { console.error('Analysis failed:', e); }
114
      finally { btn.textContent = 'analyze'; btn.disabled = false; }
115
    }
116
    {{end}}
117
  </script>
118
{{end}}