feat: add example receipt Pollen Forecast (EU)

This commit is contained in:
Benjamin Nussbaum 2025-05-14 11:49:21 +02:00
parent c069db219a
commit 725843dec0
3 changed files with 251 additions and 0 deletions

View file

@ -125,5 +125,24 @@ class ExampleRecipesSeeder extends Seeder
'flux_icon_name' => 'sunrise',
]
);
Plugin::updateOrCreate(
[
'uuid' => '82d3ee14-d578-4969-bda5-2bbf825435fe',
'name' => 'Pollen Forecast',
'user_id' => $user_id,
'data_payload' => null,
'data_stale_minutes' => 720,
'data_strategy' => 'polling',
'polling_url' => 'https://air-quality-api.open-meteo.com/v1/air-quality?latitude=48.2083&longitude=16.3731&hourly=alder_pollen,birch_pollen,grass_pollen,mugwort_pollen,ragweed_pollen&current=alder_pollen,birch_pollen,grass_pollen,mugwort_pollen,ragweed_pollen&timezone=Europe%2FVienna&forecast_days=2',
'polling_verb' => 'get',
'polling_header' => null,
'render_markup' => null,
'render_markup_view' => 'recipes.pollen-forecast-eu',
'detail_view_route' => null,
'icon_url' => null,
'flux_icon_name' => 'flower',
]
);
}
}

View file

@ -0,0 +1,50 @@
{{-- Credit: Lucide (https://lucide.dev) --}}
@props([
'variant' => 'outline',
])
@php
if ($variant === 'solid') {
throw new \Exception('The "solid" variant is not supported in Lucide.');
}
$classes = Flux::classes('shrink-0')
->add(match($variant) {
'outline' => '[:where(&)]:size-6',
'solid' => '[:where(&)]:size-6',
'mini' => '[:where(&)]:size-5',
'micro' => '[:where(&)]:size-4',
});
$strokeWidth = match ($variant) {
'outline' => 2,
'mini' => 2.25,
'micro' => 2.5,
};
@endphp
<svg
{{ $attributes->class($classes) }}
data-flux-icon
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="{{ $strokeWidth }}"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
data-slot="icon"
>
<circle cx="12" cy="12" r="3" />
<path d="M12 16.5A4.5 4.5 0 1 1 7.5 12 4.5 4.5 0 1 1 12 7.5a4.5 4.5 0 1 1 4.5 4.5 4.5 4.5 0 1 1-4.5 4.5" />
<path d="M12 7.5V9" />
<path d="M7.5 12H9" />
<path d="M16.5 12H15" />
<path d="M12 16.5V15" />
<path d="m8 8 1.88 1.88" />
<path d="M14.12 9.88 16 8" />
<path d="m8 16 1.88-1.88" />
<path d="M14.12 14.12 16 16" />
</svg>

View file

@ -0,0 +1,182 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=Inter:300,400,500" rel="stylesheet"/>
<link rel="stylesheet" href="https://usetrmnl.com/css/latest/plugins.css">
<script src="https://usetrmnl.com/js/latest/plugins.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartkick@5.0.1/dist/chartkick.min.js"></script>
<title>plugin</title>
<style>
.trmnl .content .description {
word-break: break-word;
}
</style>
</head>
<body class="environment trmnl">
<div class="screen">
<div class="view view--full">
<div class="layout layout--col gap--space-between">
<!-- Current Pollen Stats -->
<div class="grid grid--cols-5">
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value value--tnums">{{ data.current.birch_pollen }}</span>
<span class="label label--small">grains/m³</span>
<span class="label">Birch</span>
</div>
</div>
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value value--tnums">{{ data.current.grass_pollen }}</span>
<span class="label label--small">grains/m³</span>
<span class="label">Grass</span>
</div>
</div>
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value value--tnums">{{ data.current.alder_pollen }}</span>
<span class="label label--small">grains/m³</span>
<span class="label">Alder</span>
</div>
</div>
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value value--tnums">{{ data.current.mugwort_pollen }}</span>
<span class="label label--small">grains/m³</span>
<span class="label">Mugwort</span>
</div>
</div>
<div class="item">
<div class="meta"></div>
<div class="content">
<span class="value value--tnums">{{ data.current.ragweed_pollen }}</span>
<span class="label label--small">grains/m³</span>
<span class="label">Ragweed</span>
</div>
</div>
</div>
<!-- Chart Container -->
<div id="chart-pollen" style="width: 100%"></div>
</div>
<div class="title_bar">
<svg width="30px" fill="currentColor" xmlns="http://www.w3.org/2000/svg" id="mdi-flower-pollen" viewBox="0 0 24 24"><path d="M18.4 12.75C18.4 11.37 17.28 10.25 15.9 10.25C15.37 10.25 14.88 10.41 14.5 10.69V10.5C14.5 9.12 13.38 8 12 8S9.5 9.12 9.5 10.5V10.69C9.12 10.41 8.63 10.25 8.1 10.25C6.72 10.25 5.6 11.37 5.6 12.75C5.6 13.74 6.19 14.6 7.03 15C6.19 15.4 5.6 16.25 5.6 17.25C5.6 18.63 6.72 19.75 8.1 19.75C8.63 19.75 9.12 19.58 9.5 19.31V19.5C9.5 20.88 10.62 22 12 22S14.5 20.88 14.5 19.5V19.31C14.88 19.58 15.37 19.75 15.9 19.75C17.28 19.75 18.4 18.63 18.4 17.25C18.4 16.25 17.81 15.4 16.97 15C17.81 14.6 18.4 13.74 18.4 12.75M12 17.5C10.62 17.5 9.5 16.38 9.5 15S10.62 12.5 12 12.5 14.5 13.62 14.5 15 13.38 17.5 12 17.5M11 6C11 5.45 11.45 5 12 5S13 5.45 13 6 12.55 7 12 7 11 6.55 11 6M7 8C7 7.45 7.45 7 8 7S9 7.45 9 8 8.55 9 8 9 7 8.55 7 8M5 6C4.45 6 4 5.55 4 5S4.45 4 5 4 6 4.45 6 5 5.55 6 5 6M8 3C8 2.45 8.45 2 9 2S10 2.45 10 3 9.55 4 9 4 8 3.55 8 3M14 3C14 2.45 14.45 2 15 2S16 2.45 16 3 15.55 4 15 4 14 3.55 14 3M20 5C20 5.55 19.55 6 19 6S18 5.55 18 5 18.45 4 19 4 20 4.45 20 5M16 7C16.55 7 17 7.45 17 8S16.55 9 16 9 15 8.55 15 8 15.45 7 16 7Z"></path></svg>
<span class="title">Pollen Forecast Vienna</span>
<span class="instance">Data provided by: Open-Meteo.com</span>
</div>
</div>
<script type="text/javascript">
// Build data arrays manually via Liquid
var birchData = [
{% for i in (0..47) %}
["{{ data.hourly.time[i] }}", {{ data.hourly.birch_pollen[i] }}]{% unless forloop.last %},{% endunless %}
{% endfor %}
];
var grassData = [
{% for i in (0..47) %}
["{{ data.hourly.time[i] }}", {{ data.hourly.grass_pollen[i] }}]{% unless forloop.last %},{% endunless %}
{% endfor %}
];
var alderData = [
{% for i in (0..47) %}
["{{ data.hourly.time[i] }}", {{ data.hourly.alder_pollen[i] }}]{% unless forloop.last %},{% endunless %}
{% endfor %}
];
var mugwortData = [
{% for i in (0..47) %}
["{{ data.hourly.time[i] }}", {{ data.hourly.mugwort_pollen[i] }}]{% unless forloop.last %},{% endunless %}
{% endfor %}
];
var ragweedData = [
{% for i in (0..47) %}
["{{ data.hourly.time[i] }}", {{ data.hourly.ragweed_pollen[i] }}]{% unless forloop.last %},{% endunless %}
{% endfor %}
];
// Function to get max value from data array
function getMaxValue(dataArray) {
return Math.max(...dataArray.map(item => item[1]));
}
// Filter data based on max value threshold
const threshold = 0.2;
const seriesData = [
{ name: "Birch", data: birchData },
{ name: "Grass", data: grassData, dashStyle: "shortdot" },
{ name: "Alder", data: alderData, birchData, dashStyle: "shortdash" },
{ name: "Mugwort", data: mugwortData },
{ name: "Ragweed", data: ragweedData, dashStyle: "shortdash" }
].filter(series => getMaxValue(series.data) > threshold);
// Chartkick config
var createChart = function() {
new Chartkick["LineChart"](
"chart-pollen",
seriesData,
{
adapter: "highcharts",
thousands: ",",
points: false,
curve: true,
colors: ["#111", "#111", "#111", "#111", "#111"],
library: {
chart: { height: 300 },
plotOptions: {
series: {
animation: false,
lineWidth: 5
}
},
yAxis: {
labels: { style: { fontSize: "16px", color: "#000000" }},
gridLineDashStyle: "shortdot",
gridLineWidth: 1,
gridLineColor: "#000000",
tickAmount: 5
},
xAxis: {
type: "datetime",
labels: { style: { fontSize: "16px", color: "#000000" }},
lineWidth: 0,
gridLineDashStyle: "dot",
tickWidth: 1,
tickLength: 0,
gridLineWidth: 1,
gridLineColor: "#000000",
tickPixelInterval: 120,
plotLines: [{
value: new Date().getTime(),
color: '#000000',
width: 2,
dashStyle: 'shortdash',
zIndex: 5
}]
}
}
}
);
};
if ("Chartkick" in window) {
createChart();
} else {
window.addEventListener("chartkick:load", createChart, true);
}
</script>
</div>
</div>
</body>
</html>