diff --git a/src/charts/ChartTimeline/ChartTimeline.js b/src/charts/ChartTimeline/ChartTimeline.js
new file mode 100644
index 00000000..2432d4b9
--- /dev/null
+++ b/src/charts/ChartTimeline/ChartTimeline.js
@@ -0,0 +1,103 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { makeStyles } from '@mui/styles';
+import dayjs from 'dayjs';
+import { LineChart, Line, XAxis, ResponsiveContainer, ReferenceDot, ReferenceArea } from 'recharts';
+
+const useStyles = makeStyles({
+ container: {
+ backgroundColor: '#1C1C20',
+ width: '100%',
+ height: 64,
+ },
+});
+
+const ChartTimeline = ({ chartData, markers, currentTimestep, setCurrentTimestep, startDate, endDate }) => {
+ const classes = useStyles();
+
+ const data = chartData.map((value, index) => ({
+ index,
+ value,
+ }));
+
+ const totalSteps = chartData.length;
+ const numberOfTicks = 12;
+
+ const ticks = Array.from({ length: numberOfTicks }, (_, i) =>
+ Math.floor((i * (totalSteps - 1)) / (numberOfTicks - 1))
+ );
+
+ const formatDateTick = (index) => {
+ if (!startDate || !endDate || !chartData.length) return '';
+
+ const start = dayjs(startDate);
+ const end = dayjs(endDate);
+ const totalSteps = chartData.length;
+
+ if (index < 0 || index >= totalSteps) return '';
+
+ const totalDurationMs = end.valueOf() - start.valueOf();
+ const msPerStep = totalDurationMs / (totalSteps - 1);
+ const dateForTick = start.add(msPerStep * index, 'millisecond');
+ return dateForTick.isValid() ? dateForTick.format('MMM') : '';
+ };
+
+ const handleClick = (e) => {
+ if (e?.activeLabel != null) {
+ setCurrentTimestep(e.activeLabel);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+ {markers.map((markerIndex) => {
+ const markerData = data[markerIndex];
+ if (!markerData) return null;
+ return (
+ }
+ />
+ );
+ })}
+
+
+
+
+
+ );
+};
+
+ChartTimeline.propTypes = {
+ chartData: PropTypes.arrayOf(PropTypes.number).isRequired,
+ markers: PropTypes.arrayOf(PropTypes.number),
+ currentTimestep: PropTypes.number.isRequired,
+ setCurrentTimestep: PropTypes.func.isRequired,
+ startDate: PropTypes.instanceOf(Date).isRequired,
+ endDate: PropTypes.instanceOf(Date).isRequired,
+};
+
+ChartTimeline.defaultProps = {
+ markers: [],
+};
+
+export default ChartTimeline;
diff --git a/src/charts/ChartTimeline/index.js b/src/charts/ChartTimeline/index.js
new file mode 100644
index 00000000..ebab267f
--- /dev/null
+++ b/src/charts/ChartTimeline/index.js
@@ -0,0 +1 @@
+export { default as ChartTimeline } from './ChartTimeline';
diff --git a/src/charts/index.js b/src/charts/index.js
index f7c28cb8..87ac5803 100644
--- a/src/charts/index.js
+++ b/src/charts/index.js
@@ -5,3 +5,4 @@ export { CytoViz } from './CytoViz';
export { Dashboard } from './Dashboard';
export { ScenarioManagerTreeList } from './ScenarioManagerTreeList';
export { SimplePowerBIReportEmbed } from './SimplePowerBIReportEmbed';
+export { ChartTimeline } from './ChartTimeline';
diff --git a/src/index.js b/src/index.js
index 73e9a742..5b4737dd 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,7 +3,7 @@
export { CreateScenarioButton, SelfDestructLinkButton, SignInButton, RolesEditionButton } from './buttons';
export { ScenarioNode, ResourceCard } from './cards';
-export { CytoViz, Dashboard, ScenarioManagerTreeList, SimplePowerBIReportEmbed } from './charts';
+export { CytoViz, Dashboard, ScenarioManagerTreeList, SimplePowerBIReportEmbed, ChartTimeline } from './charts';
export { SimpleTwoActionsDialog, DontAskAgainDialog } from './dialogs';
export {
HierarchicalComboBox,