updated
This commit is contained in:
@@ -630,13 +630,18 @@ data:
|
|||||||
- type: custom-api
|
- type: custom-api
|
||||||
title: Meal for the Day
|
title: Meal for the Day
|
||||||
cache: 1d
|
cache: 1d
|
||||||
url: ${TANDOOR_URL}/api/recipe/flat/
|
|
||||||
|
# Use the endpoint that definitely exists in your Tandoor
|
||||||
|
url: ${TANDOOR_URL}/api/recipe/
|
||||||
headers:
|
headers:
|
||||||
Accept: application/json
|
Accept: application/json
|
||||||
Authorization: Bearer ${TANDOOR_TOKEN}
|
Authorization: Bearer ${TANDOOR_TOKEN}
|
||||||
|
|
||||||
# We use Prometheus just to get a stable "today" number (Unix time),
|
# Pass base url into template (NO env() needed)
|
||||||
# so the 3 picks are deterministic for the day.
|
options:
|
||||||
|
base_url: ${TANDOOR_URL}
|
||||||
|
|
||||||
|
# Use Prometheus time() to make the pick stable for the day
|
||||||
subrequests:
|
subrequests:
|
||||||
epoch:
|
epoch:
|
||||||
url: ${PROMETHEUS_URL}/api/v1/query
|
url: ${PROMETHEUS_URL}/api/v1/query
|
||||||
@@ -645,71 +650,32 @@ data:
|
|||||||
|
|
||||||
template: |
|
template: |
|
||||||
<style>
|
<style>
|
||||||
.mealwrap { display: flex; flex-direction: column; gap: 10px; }
|
.mealwrap { display:flex; flex-direction:column; gap:10px; }
|
||||||
.mealmeta { opacity: .65; font-size: 12px; display:flex; justify-content: space-between; align-items:center; }
|
.mealmeta { opacity:.65; font-size:12px; display:flex; justify-content:space-between; align-items:center; }
|
||||||
.mealmeta a { opacity: .9; }
|
.mealscroller { display:flex; gap:12px; overflow-x:auto; scroll-snap-type:x mandatory; -webkit-overflow-scrolling:touch; padding-bottom:6px; }
|
||||||
|
.mealslide { min-width:100%; scroll-snap-align:start; border-radius:14px; overflow:hidden; background:rgba(255,255,255,0.04); box-shadow:0 0 0 1px rgba(255,255,255,0.06) inset; }
|
||||||
.mealscroller {
|
.mealimg { height:150px; background:rgba(0,0,0,0.15); display:flex; align-items:center; justify-content:center; overflow:hidden; }
|
||||||
display: flex;
|
.mealimg img { width:100%; height:100%; object-fit:cover; display:block; }
|
||||||
gap: 12px;
|
.mealnoimg { opacity:.55; font-size:12px; padding:18px; text-align:center; }
|
||||||
overflow-x: auto;
|
.mealname { padding:10px 12px 12px; font-weight:700; opacity:.95; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
||||||
scroll-snap-type: x mandatory;
|
.meallink { display:block; color:inherit; text-decoration:none; }
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
padding-bottom: 6px;
|
|
||||||
}
|
|
||||||
.mealscroller::-webkit-scrollbar { height: 8px; }
|
|
||||||
.mealscroller::-webkit-scrollbar-thumb { border-radius: 999px; background: rgba(255,255,255,0.18); }
|
|
||||||
.mealscroller::-webkit-scrollbar-track { background: rgba(255,255,255,0.06); border-radius: 999px; }
|
|
||||||
|
|
||||||
.mealslide {
|
|
||||||
min-width: 100%;
|
|
||||||
scroll-snap-align: start;
|
|
||||||
border-radius: 14px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: rgba(255,255,255,0.04);
|
|
||||||
box-shadow: 0 0 0 1px rgba(255,255,255,0.06) inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mealimg {
|
|
||||||
height: 150px;
|
|
||||||
background: rgba(0,0,0,0.15);
|
|
||||||
display:flex;
|
|
||||||
align-items:center;
|
|
||||||
justify-content:center;
|
|
||||||
overflow:hidden;
|
|
||||||
}
|
|
||||||
.mealimg img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
display:block;
|
|
||||||
}
|
|
||||||
.mealnoimg { opacity:.55; font-size: 12px; padding: 18px; text-align:center; }
|
|
||||||
|
|
||||||
.mealname {
|
|
||||||
padding: 10px 12px 12px 12px;
|
|
||||||
font-weight: 700;
|
|
||||||
opacity: .95;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
.meallink {
|
|
||||||
display:block;
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{{ $recipes := .JSON.Array "" }}
|
{{ $base := .Options.String "base_url" }}
|
||||||
{{ $n := len $recipes }}
|
|
||||||
|
|
||||||
|
{{/* Handle both: array response OR paginated {results:[...]} */}}
|
||||||
|
{{ $recipes := .JSON.Array "results" }}
|
||||||
|
{{ if eq (len $recipes) 0 }}
|
||||||
|
{{ $recipes = .JSON.Array "" }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ $n := len $recipes }}
|
||||||
{{ if lt $n 1 }}
|
{{ if lt $n 1 }}
|
||||||
<div class="mealwrap">
|
<div class="mealwrap">
|
||||||
<div class="color-negative">No recipes returned from Tandoor.</div>
|
<div class="color-negative">No recipes returned from Tandoor.</div>
|
||||||
<div class="mealmeta">
|
<div class="mealmeta">
|
||||||
<span>Check token / permissions</span>
|
<span>Check token / permissions</span>
|
||||||
<a href="{{ .Options.StringOr "tandoor-url" (print (env "TANDOOR_URL")) }}" target="_blank" rel="noreferrer">Open Tandoor</a>
|
<a href="{{ $base }}" target="_blank" rel="noreferrer">Open Tandoor</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
@@ -717,7 +683,6 @@ data:
|
|||||||
{{ $epoch := (.Subrequest "epoch").JSON.Float "data.result.0.value.1" }}
|
{{ $epoch := (.Subrequest "epoch").JSON.Float "data.result.0.value.1" }}
|
||||||
{{ $day := div $epoch 86400.0 | toInt }}
|
{{ $day := div $epoch 86400.0 | toInt }}
|
||||||
|
|
||||||
{{/* pick a "base" index for today; then next 2 indices */}}
|
|
||||||
{{ $i0 := mod $day $n }}
|
{{ $i0 := mod $day $n }}
|
||||||
{{ $i1 := mod (add $i0 1) $n }}
|
{{ $i1 := mod (add $i0 1) $n }}
|
||||||
{{ $i2 := mod (add $i0 2) $n }}
|
{{ $i2 := mod (add $i0 2) $n }}
|
||||||
@@ -726,17 +691,10 @@ data:
|
|||||||
{{ $r1 := index $recipes $i1 }}
|
{{ $r1 := index $recipes $i1 }}
|
||||||
{{ $r2 := index $recipes $i2 }}
|
{{ $r2 := index $recipes $i2 }}
|
||||||
|
|
||||||
{{ $base := env "TANDOOR_URL" }}
|
{{/* images are already absolute in your API output */}}
|
||||||
|
|
||||||
{{/* helper: ensure absolute image URL */}}
|
|
||||||
{{ $img0 := $r0.String "image" }}
|
{{ $img0 := $r0.String "image" }}
|
||||||
{{ if and $img0 (not (hasPrefix "http" $img0)) }}{{ $img0 = print $base $img0 }}{{ end }}
|
|
||||||
|
|
||||||
{{ $img1 := $r1.String "image" }}
|
{{ $img1 := $r1.String "image" }}
|
||||||
{{ if and $img1 (not (hasPrefix "http" $img1)) }}{{ $img1 = print $base $img1 }}{{ end }}
|
|
||||||
|
|
||||||
{{ $img2 := $r2.String "image" }}
|
{{ $img2 := $r2.String "image" }}
|
||||||
{{ if and $img2 (not (hasPrefix "http" $img2)) }}{{ $img2 = print $base $img2 }}{{ end }}
|
|
||||||
|
|
||||||
<div class="mealwrap">
|
<div class="mealwrap">
|
||||||
<div class="mealmeta">
|
<div class="mealmeta">
|
||||||
@@ -745,40 +703,31 @@ data:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mealscroller">
|
<div class="mealscroller">
|
||||||
{{/* Slide 1 */}}
|
|
||||||
<div class="mealslide">
|
<div class="mealslide">
|
||||||
<a class="meallink" href="{{ $base }}/recipe/{{ $r0.Int "id" }}" target="_blank" rel="noreferrer">
|
<a class="meallink" href="{{ $base }}/recipe/{{ $r0.Int "id" }}" target="_blank" rel="noreferrer">
|
||||||
<div class="mealimg">
|
<div class="mealimg">{{ if $img0 }}<img src="{{ $img0 }}" alt="" />{{ else }}<div class="mealnoimg">No image</div>{{ end }}</div>
|
||||||
{{ if $img0 }}<img src="{{ $img0 }}" alt="" />{{ else }}<div class="mealnoimg">No image</div>{{ end }}
|
|
||||||
</div>
|
|
||||||
<div class="mealname">{{ $r0.String "name" }}</div>
|
<div class="mealname">{{ $r0.String "name" }}</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{/* Slide 2 */}}
|
|
||||||
<div class="mealslide">
|
<div class="mealslide">
|
||||||
<a class="meallink" href="{{ $base }}/recipe/{{ $r1.Int "id" }}" target="_blank" rel="noreferrer">
|
<a class="meallink" href="{{ $base }}/recipe/{{ $r1.Int "id" }}" target="_blank" rel="noreferrer">
|
||||||
<div class="mealimg">
|
<div class="mealimg">{{ if $img1 }}<img src="{{ $img1 }}" alt="" />{{ else }}<div class="mealnoimg">No image</div>{{ end }}</div>
|
||||||
{{ if $img1 }}<img src="{{ $img1 }}" alt="" />{{ else }}<div class="mealnoimg">No image</div>{{ end }}
|
|
||||||
</div>
|
|
||||||
<div class="mealname">{{ $r1.String "name" }}</div>
|
<div class="mealname">{{ $r1.String "name" }}</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{/* Slide 3 */}}
|
|
||||||
<div class="mealslide">
|
<div class="mealslide">
|
||||||
<a class="meallink" href="{{ $base }}/recipe/{{ $r2.Int "id" }}" target="_blank" rel="noreferrer">
|
<a class="meallink" href="{{ $base }}/recipe/{{ $r2.Int "id" }}" target="_blank" rel="noreferrer">
|
||||||
<div class="mealimg">
|
<div class="mealimg">{{ if $img2 }}<img src="{{ $img2 }}" alt="" />{{ else }}<div class="mealnoimg">No image</div>{{ end }}</div>
|
||||||
{{ if $img2 }}<img src="{{ $img2 }}" alt="" />{{ else }}<div class="mealnoimg">No image</div>{{ end }}
|
|
||||||
</div>
|
|
||||||
<div class="mealname">{{ $r2.String "name" }}</div>
|
<div class="mealname">{{ $r2.String "name" }}</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
# ---------- CENTER COLUMN ----------
|
# ---------- CENTER COLUMN ----------
|
||||||
- size: full
|
- size: full
|
||||||
widgets:
|
widgets:
|
||||||
|
|||||||
Reference in New Issue
Block a user