Hi, is it possible to make Glide’s progress bar into a segmented progress bar, with (preferably) a title for each segment? Something like this, only with titles above each segment.
Have you tried Custom Component feature? Take a screenshot of this and paste the image link on Custom Component Generator using AI.
It might work maybe.
I tried but it didn’t work. I’m guessing CSS will be a more reliable solution. Let me try Chat GPT to see if it can churn out any custom CSS.
Update: No luck with ChatGPT either
Tagging this as something I’ll look into through the weekend.
So you have an input as a number for the progress bar, but that progress bar should also have a set number of segments, and each segment should have a title?
Wow, thank you so much
Yes exactly. I have tied up my percentage amount to a “status” field via a lookup, so as the status changes to the next one, the percentage increases by 20%.
I’ve been doing this thing for 3 weeks and been sourcing ideas from this community. Maybe I’ll try yours or another one this weekend, maybe both, and will let you know as soon as I get something done.
Well, it’s called CSS.
This looks awesome! With the help from you and ThinhDinh, we might just be able to make something like this possible in Glide (minus the animation)
I’m also exploring the capabilities of this new component. It looks quite impressive. There seems to be a simpler way to code it. It even gets complicated when you present it to AI; maybe we need to adapt to its language and understanding .
Here’s the code I tested; please adapt it to your needs. Give your data the name “myProgress” in the custom component panel.
<!DOCTYPE html>
<html lang="en">
<head>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Segmented Progress Bar</title>
<style>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
margin: 0;
}
h2 {
font-size: 32px;
color: #fff;
text-align: left;
width: 100%;
max-width: 100%;
margin: 0 0 10px 0;
padding: 0;
box-sizing: border-box;
}
.progress-container {
display: flex;
gap: 10px;
width: 100%;
max-width: 100%;
}
.progress-segment {
flex: 1;
height: 20px;
background-color: #ddd;
border-radius: 15px;
overflow: hidden;
position: relative;
}
.progress-fill {
height: 100%;
background-color: #6a5acd;
border-radius: 15px;
transition: width 0.5s;
}
</style>
</head>
<body>
<h2>Segmented Progress Bar</h2>
<div class="progress-container">
<div class="progress-segment">
<div class="progress-fill" id="fill-1"></div>
</div>
<div class="progress-segment">
<div class="progress-fill" id="fill-2"></div>
</div>
<div class="progress-segment">
<div class="progress-fill" id="fill-3"></div>
</div>
<div class="progress-segment">
<div class="progress-fill" id="fill-4"></div>
</div>
<div class="progress-segment">
<div class="progress-fill" id="fill-5"></div>
</div>
</div>
<script>
var myProgress = S.myProgress;
var totalSegments = 5;
var segmentWidth = 100 / totalSegments;
var segments = Math.floor(myProgress / segmentWidth);
var remainder =
((myProgress % segmentWidth) / segmentWidth) * 100;
for (var i = 1; i <= totalSegments; i++) {
var fillElement = document.getElementById(
"fill-" + i
);
if (i < segments + 1) {
fillElement.style.width = "100%";
} else if (i === segments + 1) {
fillElement.style.width = remainder + "%";
} else {
fillElement.style.width = "0%";
}
}
</script>
</body>
</html>
Progress bar:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Segmented Progress Bar</title>
<script src="https://cdn.tailwindcss.com"></script>
<script
defer
src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"
></script>
</head>
<body
class="bg-gray-100 min-h-screen flex items-center justify-center"
>
<div
x-data="progressBar()"
x-init="init()"
class="w-full max-w-3xl p-6 bg-white rounded-lg shadow-lg"
>
<div class="flex mb-4 space-x-1">
<template
x-for="(width, index) in segmentWidths"
:key="index"
>
<div
class="flex-1 h-2 bg-gray-200 rounded-full overflow-hidden"
>
<div
class="h-full bg-blue-500 transition-all duration-300 ease-in-out"
:style="{ width: width }"
></div>
</div>
</template>
</div>
<h2
class="text-2xl font-bold text-center text-gray-800"
x-text="getCurrentStepTitle()"
></h2>
<p
class="text-center text-gray-600"
x-text="getCurrentStepDescription()"
></p>
<p
class="text-center text-gray-600 mt-2"
x-text="`${progress}% completed`"
></p>
</div>
<script>
function progressBar() {
return {
progress: 0,
steps: {},
segmentWidths: [],
init() {
this.progress = parseInt(S.progress);
this.steps = JSON.parse(S.steps);
this.calculateSegmentWidths();
},
calculateSegmentWidths() {
const stepCount = Object.keys(
this.steps
).length;
const segmentSize = 100 / stepCount;
this.segmentWidths = Array.from(
{ length: stepCount },
(_, index) => {
const segmentProgress = Math.min(
Math.max(
this.progress - index * segmentSize,
0
),
segmentSize
);
return `${
(segmentProgress / segmentSize) * 100
}%`;
}
);
},
getCurrentStepTitle() {
const currentStepIndex = Math.floor(
this.progress /
(100 / Object.keys(this.steps).length)
);
const stepKeys = Object.keys(this.steps);
return stepKeys[
Math.min(
currentStepIndex,
stepKeys.length - 1
)
];
},
getCurrentStepDescription() {
const currentStepIndex = Math.floor(
this.progress /
(100 / Object.keys(this.steps).length)
);
const stepKeys = Object.keys(this.steps);
return this.steps[
stepKeys[
Math.min(
currentStepIndex,
stepKeys.length - 1
)
]
];
},
};
}
</script>
</body>
</html>
Steps manager:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Steps Manager</title>
<script src="https://cdn.tailwindcss.com"></script>
<script
defer
src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"
></script>
</head>
<body class="bg-gray-100 min-h-screen p-6">
<div
x-data="stepsManager()"
x-init="initializeSteps()"
class="container mx-auto bg-gray-100 rounded-lg shadow-lg p-6"
>
<h1
class="text-3xl font-bold mb-6 text-center text-gray-800"
>
Steps Manager
</h1>
<div class="mb-6">
<h2
class="text-xl font-semibold mb-2 text-gray-700"
>
Add New Step
</h2>
<div class="flex space-x-2">
<input
type="text"
x-model="newStepTitle"
placeholder="Step Title"
class="flex-1 p-2 border rounded"
/>
<input
type="text"
x-model="newStepDescription"
placeholder="Step Description"
class="flex-1 p-2 border rounded"
/>
<button
@click="debounceAddStep()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition duration-300"
>
Add Step
</button>
</div>
</div>
<div>
<h2
class="text-xl font-semibold mb-2 text-gray-700"
>
Current Steps
</h2>
<template
x-for="(step, index) in stepsArray"
:key="index"
>
<div class="bg-white p-4 rounded-lg shadow mb-2">
<div
x-show="!step.editing"
class="flex items-center"
>
<div class="flex-1">
<h3
class="font-semibold text-lg text-gray-800"
x-text="step.title"
></h3>
<p
class="text-gray-600"
x-text="step.description"
></p>
</div>
<div class="flex space-x-2">
<button
@click="editStep(index)"
class="text-blue-500 hover:text-blue-700"
>
✏️
</button>
<button
@click="debounceMoveStep(index, 'up')"
:disabled="index === 0"
class="text-blue-500 hover:text-blue-700 disabled:text-gray-400"
>
↑
</button>
<button
@click="debounceMoveStep(index, 'down')"
:disabled="index === stepsArray.length - 1"
class="text-blue-500 hover:text-blue-700 disabled:text-gray-400"
>
↓
</button>
<button
@click="debounceRemoveStep(index)"
class="text-red-500 hover:text-red-700"
>
×
</button>
</div>
</div>
<div
x-show="step.editing"
class="flex items-center space-x-2"
>
<input
type="text"
x-model="step.editTitle"
class="flex-1 p-2 border rounded"
/>
<input
type="text"
x-model="step.editDescription"
class="flex-1 p-2 border rounded"
/>
<button
@click="saveEdit(index)"
class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600 transition duration-300"
>
Save
</button>
<button
@click="cancelEdit(index)"
class="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600 transition duration-300"
>
Cancel
</button>
</div>
</div>
</template>
</div>
<div class="mt-6">
<h2
class="text-xl font-semibold mb-2 text-gray-700"
>
JSON Output
</h2>
<pre
class="bg-gray-800 text-green-400 p-4 rounded overflow-x-auto"
x-text="JSON.stringify(steps, null, 2)"
></pre>
</div>
</div>
<script>
function debounce(func, wait) {
let timeout;
return function (...args) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(
() => func.apply(context, args),
wait
);
};
}
function stepsManager() {
return {
steps: {},
stepsArray: [],
newStepTitle: "",
newStepDescription: "",
initializeSteps() {
if (S && S.steps) {
try {
this.steps = JSON.parse(S.steps);
this.updateStepsArray();
} catch (error) {
console.error(
"Error parsing S.steps:",
error
);
this.steps = {};
this.stepsArray = [];
}
}
},
updateStepsArray() {
this.stepsArray = Object.entries(
this.steps
).map(([title, description]) => ({
title,
description,
editing: false,
editTitle: title,
editDescription: description,
}));
},
updateSteps() {
this.steps = Object.fromEntries(
this.stepsArray.map((step) => [
step.title,
step.description,
])
);
S.steps = JSON.stringify(this.steps);
},
addStep() {
if (
this.newStepTitle &&
this.newStepDescription
) {
this.stepsArray.push({
title: this.newStepTitle,
description: this.newStepDescription,
editing: false,
editTitle: this.newStepTitle,
editDescription: this.newStepDescription,
});
this.newStepTitle = "";
this.newStepDescription = "";
this.updateSteps();
}
},
debounceAddStep: debounce(function () {
this.addStep();
}, 300),
removeStep(index) {
this.stepsArray.splice(index, 1);
this.updateSteps();
},
debounceRemoveStep: debounce(function (index) {
this.removeStep(index);
}, 300),
moveStep(index, direction) {
if (
(direction === "up" && index > 0) ||
(direction === "down" &&
index < this.stepsArray.length - 1)
) {
const newIndex =
direction === "up" ? index - 1 : index + 1;
const temp = this.stepsArray[index];
this.stepsArray[index] =
this.stepsArray[newIndex];
this.stepsArray[newIndex] = temp;
this.updateSteps();
}
},
debounceMoveStep: debounce(function (
index,
direction
) {
this.moveStep(index, direction);
},
300),
editStep(index) {
this.stepsArray[index].editing = true;
},
saveEdit(index) {
const step = this.stepsArray[index];
step.title = step.editTitle;
step.description = step.editDescription;
step.editing = false;
this.updateSteps();
},
cancelEdit(index) {
const step = this.stepsArray[index];
step.editTitle = step.title;
step.editDescription = step.description;
step.editing = false;
},
};
}
</script>
</body>
</html>
Ahhh, time to watch this!
Dayumm, this is something else!
@Himaladin am I doing this right?
This is what I’m getting at the moment:
The code I’m using (removed the H2 title for now)
<!DOCTYPE html>
<html lang="en">
<head>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<style>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.progress-container {
display: flex;
gap: 8px;
width: 100%;
max-width: 100%;
}
.progress-segment {
flex: 1;
height: 8px;
background-color: #e9e5f3;
border-radius: 15px;
overflow: hidden;
position: relative;
}
.progress-fill {
height: 100%;
background-color: #613dc7;
border-radius: 15px;
transition: width 0.5s;
}
</style>
</head>
<body>
<div class="progress-container">
<div class="progress-segment">
<div class="progress-fill" id="fill-1"></div>
</div>
<div class="progress-segment">
<div class="progress-fill" id="fill-2"></div>
</div>
<div class="progress-segment">
<div class="progress-fill" id="fill-3"></div>
</div>
<div class="progress-segment">
<div class="progress-fill" id="fill-4"></div>
</div>
<div class="progress-segment">
<div class="progress-fill" id="fill-5"></div>
</div>
</div>
<script>
var myProgress = S.myProgress;
var totalSegments = 5;
var segmentWidth = 100 / totalSegments;
var segments = Math.floor(myProgress / segmentWidth);
var remainder =
((myProgress % segmentWidth) / segmentWidth) * 100;
for (var i = 1; i <= totalSegments; i++) {
var fillElement = document.getElementById(
"fill-" + i
);
if (i < segments + 1) {
fillElement.style.width = "100%";
} else if (i === segments + 1) {
fillElement.style.width = remainder + "%";
} else {
fillElement.style.width = "0%";
}
}
</script>
</body>
</html>
Seems like there’s a little issue with the Code component at the moment where the component does not tie correctly with defined variables.
Yes… 20% You can go directly to the column in the table without having to write it there. Now this component is having problems, is it working for you?
No, at this moment it’s not working for me either. The component is being displayed but the bar isn’t being filled up.
This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.