Yesterday we “vibe coded” a counter component with the @elementsbot here on the forum.
I spent a little extra time today tidying it up and making it more usable. In the project (included below) I also set up a couple of Templates to make it even easier to add to your own projects
Open this Project in Elements and watch the video below to see how it all works
Oh, and here’s the final code that you can copy and paste into a custom component (if you want to build it yourself):
Template Code:
<div
class=""
x-data="{ count: 0, hasAnimated: false }"
x-intersect.once="if (!hasAnimated) { hasAnimated = true; $nextTick(() => { let start = 0; let end = +{{myNumber}}; let duration = 1500; let startTime = null; function animate(now) { if(!startTime) startTime = now; let progress = Math.min((now - startTime) / duration, 1); count = Math.floor(progress * (end - start) + start); if(progress < 1){ requestAnimationFrame(animate); } } requestAnimationFrame(animate); }); }"
>
@if(edit)
<div class="font-bold {{textColor}} {{headingTextStyles}} {{fontFamily}}">{{myNumber}}</div>
@else
<div class="font-bold {{textColor}} {{headingTextStyles}} {{fontFamily}}" x-text="count"></div>
@endif
</div>
Properties Code:
{
"groups": [
{
"title": "General",
"icon": "gearshape",
"properties": [
{
"title": "Number",
"id": "myNumber",
"number": {
"default": 100
}
},
{
"title": "Font",
"id": "fontFamily",
"themeFont": {
"default": {
"base": { "name": "body" }
}
}
},
{
"title": "Size",
"id": "headingTextStyles",
"themeTextStyle": {
"default": {
"base": {
"name": "5xl"
}
}
}
},
{
"title": "Color",
"id": "textColor",
"format": "text-{{value}}",
"themeColor": {
"default": {
"name": "text",
"brightness": 300
}
}
}
]
}
]
}