diff --git a/plugins/carhop-blocks/src/company-timeline/block.json b/plugins/carhop-blocks/src/company-timeline/block.json
new file mode 100644
index 0000000..7e677e3
--- /dev/null
+++ b/plugins/carhop-blocks/src/company-timeline/block.json
@@ -0,0 +1,71 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "telex/block-company-timeline",
+ "version": "0.1.0",
+ "title": "Company Timeline",
+ "category": "design",
+ "icon": "calendar-alt",
+ "description": "Display company milestones with a fixed sidebar navigation and scroll-based highlighting",
+ "keywords": [
+ "timeline",
+ "history",
+ "milestones",
+ "chronology",
+ "events"
+ ],
+ "attributes": {
+ "entries": {
+ "type": "array",
+ "default": [
+ {
+ "year": "2020",
+ "title": "Company Founded",
+ "description": "Our journey began with a vision to make a difference.",
+ "imageUrl": "",
+ "imageId": 0
+ }
+ ]
+ }
+ },
+ "example": {
+ "attributes": {
+ "entries": [
+ {
+ "year": "2010",
+ "title": "The Beginning",
+ "description": "Founded with a mission to innovate.",
+ "imageUrl": "",
+ "imageId": 0
+ },
+ {
+ "year": "2015",
+ "title": "Major Milestone",
+ "description": "Reached 1 million customers worldwide.",
+ "imageUrl": "",
+ "imageId": 0
+ },
+ {
+ "year": "2020",
+ "title": "Global Expansion",
+ "description": "Opened offices in 25 countries.",
+ "imageUrl": "",
+ "imageId": 0
+ }
+ ]
+ }
+ },
+ "supports": {
+ "html": false,
+ "anchor": true,
+ "align": [
+ "wide",
+ "full"
+ ]
+ },
+ "textdomain": "company-timeline",
+ "editorScript": "file:./index.js",
+ "editorStyle": "file:./index.css",
+ "style": "file:./style-index.css",
+ "viewScript": "file:./view.js"
+}
\ No newline at end of file
diff --git a/plugins/carhop-blocks/src/company-timeline/edit.js b/plugins/carhop-blocks/src/company-timeline/edit.js
new file mode 100644
index 0000000..73b9835
--- /dev/null
+++ b/plugins/carhop-blocks/src/company-timeline/edit.js
@@ -0,0 +1,219 @@
+import { __ } from "@wordpress/i18n";
+
+import {
+ useBlockProps,
+ InspectorControls,
+ MediaUpload,
+ MediaUploadCheck,
+ RichText,
+} from "@wordpress/block-editor";
+
+import {
+ PanelBody,
+ Button,
+ TextControl,
+ Card,
+ CardBody,
+ CardHeader,
+ IconButton,
+} from "@wordpress/components";
+
+import { useState } from "@wordpress/element";
+
+import "./editor.scss";
+
+export default function Edit({ attributes, setAttributes }) {
+ const { entries } = attributes;
+ const [selectedYear, setSelectedYear] = useState(null);
+
+ const addEntry = () => {
+ const newEntries = [
+ ...entries,
+ {
+ year: new Date().getFullYear().toString(),
+ title: "",
+ description: "",
+ imageUrl: "",
+ imageId: 0,
+ },
+ ];
+ setAttributes({ entries: newEntries });
+ };
+
+ const updateEntry = (index, field, value) => {
+ const newEntries = [...entries];
+ newEntries[index] = {
+ ...newEntries[index],
+ [field]: value,
+ };
+ setAttributes({ entries: newEntries });
+ };
+
+ const removeEntry = (index) => {
+ const newEntries = entries.filter((_, i) => i !== index);
+ setAttributes({ entries: newEntries });
+ };
+
+ const sortedEntries = [...entries].sort(
+ (a, b) => parseInt(a.year) - parseInt(b.year)
+ );
+
+ const years = [...new Set(sortedEntries.map((entry) => entry.year))];
+
+ return (
+ <>
+
+
+
+
+ {sortedEntries.map((entry, index) => {
+ const originalIndex = entries.findIndex(
+ (e) =>
+ e.year === entry.year &&
+ e.title === entry.title &&
+ e.description === entry.description
+ );
+
+ return (
+
+
+
+ {entry.year || __("New Entry", "company-timeline")}
+
+
+
+
+ updateEntry(originalIndex, "year", value)
+ }
+ type="number"
+ />
+
+
+
+ );
+ })}
+
+
+
+
+
+
+
+
{__("Timeline", "company-timeline")}
+ {years.map((year) => (
+
+ ))}
+
+
+
+
+ {sortedEntries.map((entry, index) => {
+ const originalIndex = entries.findIndex(
+ (e) =>
+ e.year === entry.year &&
+ e.title === entry.title &&
+ e.description === entry.description
+ );
+
+ return (
+
+
+
{entry.year}
+
+
+
+
+ updateEntry(originalIndex, "title", value)
+ }
+ placeholder={__(
+ "Enter milestone title...",
+ "company-timeline"
+ )}
+ className="timeline-title"
+ />
+
+
+ updateEntry(originalIndex, "description", value)
+ }
+ placeholder={__(
+ "Enter milestone description...",
+ "company-timeline"
+ )}
+ className="timeline-description"
+ />
+
+
+ {
+ updateEntry(originalIndex, "imageUrl", media.url);
+ updateEntry(originalIndex, "imageId", media.id);
+ }}
+ allowedTypes={["image"]}
+ value={entry.imageId}
+ render={({ open }) => (
+
+ {entry.imageUrl ? (
+ <>
+

+
+ >
+ ) : (
+
+ )}
+
+ )}
+ />
+
+
+
+ );
+ })}
+
+
+
+ >
+ );
+}
diff --git a/plugins/carhop-blocks/src/company-timeline/editor.scss b/plugins/carhop-blocks/src/company-timeline/editor.scss
new file mode 100644
index 0000000..fde11df
--- /dev/null
+++ b/plugins/carhop-blocks/src/company-timeline/editor.scss
@@ -0,0 +1,43 @@
+/**
+ * The following styles get applied inside the editor only.
+ *
+ * Replace them with your own styles or remove the file completely.
+ */
+
+.wp-block-telex-company-timeline {
+ .timeline-entry-content {
+ .timeline-title,
+ .timeline-description {
+ &:focus {
+ outline: 2px solid #3b82f6;
+ outline-offset: 2px;
+ }
+ }
+
+ .timeline-media {
+ button {
+ margin-top: 12px;
+ }
+ }
+ }
+}
+
+.components-panel__body {
+ .components-card {
+ margin-bottom: 12px;
+
+ .components-card__header {
+ border-bottom: 1px solid #e2e8f0;
+ }
+
+ .components-card__body {
+ .components-base-control {
+ margin-bottom: 16px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/carhop-blocks/src/company-timeline/index.js b/plugins/carhop-blocks/src/company-timeline/index.js
new file mode 100644
index 0000000..ade1e47
--- /dev/null
+++ b/plugins/carhop-blocks/src/company-timeline/index.js
@@ -0,0 +1,39 @@
+/**
+ * Registers a new block provided a unique name and an object defining its behavior.
+ *
+ * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
+ */
+import { registerBlockType } from '@wordpress/blocks';
+
+/**
+ * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
+ * All files containing `style` keyword are bundled together. The code used
+ * gets applied both to the front of your site and to the editor.
+ *
+ * @see https://www.npmjs.com/package/@wordpress/scripts#using-css
+ */
+import './style.scss';
+
+/**
+ * Internal dependencies
+ */
+import Edit from './edit';
+import save from './save';
+import metadata from './block.json';
+
+/**
+ * Every block starts by registering a new block type definition.
+ *
+ * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
+ */
+registerBlockType( metadata.name, {
+ /**
+ * @see ./edit.js
+ */
+ edit: Edit,
+
+ /**
+ * @see ./save.js
+ */
+ save,
+} );
diff --git a/plugins/carhop-blocks/src/company-timeline/save.js b/plugins/carhop-blocks/src/company-timeline/save.js
new file mode 100644
index 0000000..a7bfa9f
--- /dev/null
+++ b/plugins/carhop-blocks/src/company-timeline/save.js
@@ -0,0 +1,88 @@
+/**
+ * React hook that is used to mark the block wrapper element.
+ * It provides all the necessary props like the class name.
+ *
+ * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
+ */
+import { useBlockProps, RichText } from '@wordpress/block-editor';
+
+/**
+ * The save function defines the way in which the different attributes should
+ * be combined into the final markup, which is then serialized by the block
+ * editor into `post_content`.
+ *
+ * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
+ *
+ * @param {Object} props Block properties
+ * @return {Element} Element to render.
+ */
+export default function save( { attributes } ) {
+ const { entries } = attributes;
+
+ const sortedEntries = [ ...entries ].sort( ( a, b ) =>
+ parseInt( a.year ) - parseInt( b.year )
+ );
+
+ const years = [ ...new Set( sortedEntries.map( entry => entry.year ) ) ];
+
+ return (
+
+
+
+
+
Timeline
+ { years.map( ( year ) => (
+
+ { year }
+
+ ) ) }
+
+
+
+
+ { sortedEntries.map( ( entry, index ) => (
+
+
+
{ entry.year }
+
+
+
+ { entry.title && (
+
+ ) }
+
+ { entry.description && (
+
+ ) }
+
+ { entry.imageUrl && (
+
+

+
+ ) }
+
+
+ ) ) }
+
+
+
+ );
+}
diff --git a/plugins/carhop-blocks/src/company-timeline/style.scss b/plugins/carhop-blocks/src/company-timeline/style.scss
new file mode 100644
index 0000000..37f96cf
--- /dev/null
+++ b/plugins/carhop-blocks/src/company-timeline/style.scss
@@ -0,0 +1,198 @@
+/**
+ * The following styles get applied both on the front of your site
+ * and in the editor.
+ *
+ * Replace them with your own styles or remove the file completely.
+ */
+
+.wp-block-telex-company-timeline {
+ display: flex;
+ gap: 60px;
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 40px 20px;
+ position: relative;
+
+ .timeline-sidebar {
+ flex: 0 0 200px;
+ position: sticky;
+ top: 100px;
+ height: fit-content;
+ align-self: flex-start;
+
+ .timeline-years {
+ background: #f8f9fa;
+ border-radius: 8px;
+ padding: 24px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+
+ h3 {
+ margin: 0 0 20px 0;
+ font-size: 18px;
+ font-weight: 700;
+ color: #1e293b;
+ border-bottom: 2px solid #e2e8f0;
+ padding-bottom: 12px;
+ }
+
+ .year-link {
+ display: block;
+ padding: 12px 16px;
+ margin-bottom: 8px;
+ text-decoration: none;
+ color: #64748b;
+ font-weight: 600;
+ font-size: 16px;
+ border-radius: 6px;
+ transition: all 0.3s ease;
+ cursor: pointer;
+ background: transparent;
+ border: none;
+ width: 100%;
+ text-align: left;
+
+ &:hover {
+ background: #e2e8f0;
+ color: #1e293b;
+ transform: translateX(4px);
+ }
+
+ &.active {
+ background: #3b82f6;
+ color: white;
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
+ }
+ }
+ }
+ }
+
+ .timeline-content {
+ flex: 1;
+ min-width: 0;
+
+ .timeline-entry {
+ margin-bottom: 80px;
+ scroll-margin-top: 100px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .timeline-year-marker {
+ margin-bottom: 24px;
+ position: relative;
+ padding-left: 40px;
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 24px;
+ height: 24px;
+ background: #3b82f6;
+ border-radius: 50%;
+ box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2);
+ }
+
+ h2 {
+ margin: 0;
+ font-size: 32px;
+ font-weight: 800;
+ color: #1e293b;
+ line-height: 1;
+ }
+ }
+
+ .timeline-entry-content {
+ background: white;
+ border-radius: 12px;
+ padding: 32px;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+ border-left: 4px solid #3b82f6;
+
+ .timeline-title {
+ margin: 0 0 16px 0;
+ font-size: 24px;
+ font-weight: 700;
+ color: #1e293b;
+ }
+
+ .timeline-description {
+ margin: 0 0 24px 0;
+ font-size: 16px;
+ line-height: 1.8;
+ color: #475569;
+ }
+
+ .timeline-media {
+ margin-top: 24px;
+
+ img {
+ width: 100%;
+ height: auto;
+ border-radius: 8px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ }
+ }
+ }
+ }
+ }
+
+ @media (max-width: 768px) {
+ flex-direction: column;
+ gap: 30px;
+ padding: 20px 15px;
+
+ .timeline-sidebar {
+ position: static;
+ flex: 1;
+
+ .timeline-years {
+ padding: 16px;
+
+ h3 {
+ font-size: 16px;
+ margin-bottom: 12px;
+ }
+
+ .year-link {
+ padding: 10px 12px;
+ font-size: 14px;
+ }
+ }
+ }
+
+ .timeline-content {
+ .timeline-entry {
+ margin-bottom: 50px;
+
+ .timeline-year-marker {
+ padding-left: 30px;
+
+ &::before {
+ width: 18px;
+ height: 18px;
+ }
+
+ h2 {
+ font-size: 24px;
+ }
+ }
+
+ .timeline-entry-content {
+ padding: 20px;
+
+ .timeline-title {
+ font-size: 20px;
+ }
+
+ .timeline-description {
+ font-size: 15px;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/carhop-blocks/src/company-timeline/view.js b/plugins/carhop-blocks/src/company-timeline/view.js
new file mode 100644
index 0000000..c277630
--- /dev/null
+++ b/plugins/carhop-blocks/src/company-timeline/view.js
@@ -0,0 +1,67 @@
+/**
+ * Use this file for JavaScript code that you want to run in the front-end
+ * on posts/pages that contain this block.
+ */
+
+document.addEventListener( 'DOMContentLoaded', function() {
+ const timeline = document.querySelector( '.wp-block-telex-company-timeline' );
+
+ if ( ! timeline ) {
+ return;
+ }
+
+ const sidebar = timeline.querySelector( '.timeline-sidebar' );
+ const yearLinks = timeline.querySelectorAll( '.year-link' );
+ const entries = timeline.querySelectorAll( '.timeline-entry' );
+
+ if ( ! sidebar || yearLinks.length === 0 || entries.length === 0 ) {
+ return;
+ }
+
+ // Smooth scroll to year when clicking sidebar link
+ yearLinks.forEach( link => {
+ link.addEventListener( 'click', function( e ) {
+ e.preventDefault();
+ const year = this.getAttribute( 'data-year' ) || this.getAttribute( 'href' ).replace( '#year-', '' );
+ const targetEntry = timeline.querySelector( `[data-year="${ year }"]` );
+
+ if ( targetEntry ) {
+ targetEntry.scrollIntoView( {
+ behavior: 'smooth',
+ block: 'start'
+ } );
+ }
+ } );
+ } );
+
+ // Update active year on scroll
+ const observerOptions = {
+ root: null,
+ rootMargin: '-20% 0px -70% 0px',
+ threshold: 0
+ };
+
+ const observerCallback = ( entries ) => {
+ entries.forEach( entry => {
+ if ( entry.isIntersecting ) {
+ const year = entry.target.getAttribute( 'data-year' );
+
+ // Remove active class from all links
+ yearLinks.forEach( link => link.classList.remove( 'active' ) );
+
+ // Add active class to current year
+ const activeLink = timeline.querySelector( `.year-link[data-year="${ year }"]` );
+ if ( activeLink ) {
+ activeLink.classList.add( 'active' );
+ }
+ }
+ } );
+ };
+
+ const observer = new IntersectionObserver( observerCallback, observerOptions );
+
+ // Observe all timeline entries
+ entries.forEach( entry => {
+ observer.observe( entry );
+ } );
+} );