Как можно сделать линию привязанную к ячейке таблицы с возможностью кастомизации по сторонам?

Я делаю сайт для себя, как пет-проект, а точнее - календарь для методики Scrum. Подглядел на одном из сайтов хорошую идею реализации планировки в плане визуала, а именно - линию.

Я сделал скелет сайта, сделал таблицу и всё такое, добавил линию, написал код на JS, но он работает не так, как я хотел.

Задача заключается в следующем: Есть 12 ячеек, (24, учитывая ещё месяцы года), и в нижних 12-и (которые изначально пустые) мне нужно добавить линию, которая имеет два свойства:

  1. При наведении на ячейку появляется эта самая линия в полупрозрачном стиле, затем пропадает, если не подтвердить появление (при помощи ЛКМ);
  2. В ином случае - если уже произошло подтверждение - линия должна сохраниться и стать непрозрачной, а так же получить возможность кастомизации по сторонам (в ширину, соответственно).

По итогу, из моего кода вышло так:

  • Во-первых, линия появляется изначально вне зависимости от действий пользователя;
  • Во-вторых, она передаёт смысл одной из задумок (наводка на неё, действительно делает её непрозрачной), однако она по-прежнему, после того, как убирается курсор остается полупрозрачной и так же не фиксируется;
  • Помимо этого она сама находится под ячейками, а не внутри неё.

const table = document.getElementById('table');
const tds = table.getElementsByTagName('td');

for (let i = 0; i < tds.length; i++) {
  const td = tds[i];
  const line = document.createElement('div');
  line.id = `line-${i}`;
  line.style.height = '5px'; // Высота линии линии
  line.style.backgroundColor = 'gray'; // Цвет линии
  line.style.opacity = '0.5'; // Начальная прозрачность линии

  let isResizing = false;
  let initialWidth;

  td.appendChild(line);

  td.addEventListener('mouseover', () => {
    line.style.opacity = '0.5'; // Линия становится полупрозрачной при наведении
  });

  td.addEventListener('mouseleave', () => {
    if (!isResizing) {
      line.style.opacity = '0'; // Линия исчезает при покидании ячейки, если не происходит изменение размера
    }
  });

  line.addEventListener('mousedown', (event) => {
    isResizing = true;
    initialWidth = line.offsetWidth;
    line.style.opacity = '1'; // Линия становится непрозрачной при нажатии
  });

  document.addEventListener('mousemove', (event) => {
    if (isResizing) {
      const newWidth = initialWidth + (event.clientX - event.pageX);
      line.style.width = `${newWidth}px`;
    }
  });

  document.addEventListener('mouseup', () => {
    isResizing = false;
    if (td.nextElementSibling) {
      td.nextElementSibling.firstChild.style.opacity = '0.5';
    }
  });
}
/* Основные стили */

body {
  font-family: sans-serif;
  margin: 0;
  padding: 0;
}

header {
  background-color: #f0f0f0;
  padding: 20px;
  text-align: center;
}

header img {
  max-width: 200px;
  height: auto;
}

.container {
  display: flex;
  max-width: 1000px;
  margin: 0 auto;
  padding: 20px;
}

.sidebar {
  width: 250px;
  background-color: #eee;
  padding: 20px;
}

.sidebar ul {
  list-style: none;
  padding: 0;
}

.sidebar li {
  margin-bottom: 10px;
}

.sidebar a {
  display: block;
  padding: 10px;
  text-decoration: none;
  color: #333;
}

.sidebar a:hover {
  background-color: #ddd;
}

.main-content {
  flex: 1;
  padding: 20px;
}

h2 {
  font-size: 24px;
  margin-bottom: 20px;
}

table {
  border-collapse: collapse;
  width: 100%;
}

th,
td {
  border: 1px solid #ddd;
  padding: 8px;
}


/* Стили для отдельных разделов */

#chronology {
  /* ... */
}

#backlog {
  /* ... */
}

#board {
  /* ... */
}

#calendar {
  /* ... */
}

#list {
  /* ... */
}

#goals {
  /* ... */
}


/* Добавьте стили для каждого раздела, как описано в HTML-коде */

#line {
  background-color: #000;
  height: 5px;
  transform: translateY(-50%);
  border-radius: 2px;
  cursor: pointer;
  opacity: 0.5;
}

#line:hover {
  cursor: pointer;
  opacity: 0.5;
}

#line:active {
  resize: both;
  opacity: 1;
}

#line:active {
  z-index: 100;
  /* Переместить линию наверх */
  cursor: move;
}

.editable:hover #line {
  opacity: 0.5;
  /* Полупрозрачность линии при наведении на ячейку */
}

.editable:active #line {
  opacity: 1;
  /* Полная непрозрачность линии при нажатии на ячейку */
}
<header>
  <img src="logo.png" alt="Логотип компании">
</header>
<div class="container">
  <div class="sidebar">
    <ul>
      <li><a href="#chronology">Хронология</a></li>
      <li><a href="#backlog">Бэклог</a></li>
      <li><a href="#board">Доска</a></li>
      <li><a href="#calendar">Календарь</a></li>
      <li><a href="#list">Список</a></li>
      <li><a href="#goals">Цели</a></li>
    </ul>
  </div>
  <div class="main-content">
    <div id="chronology">
      <h2>Хронология</h2>
      <table id="table">
        <tr>
          <th>Спринты</th>
          <th>Январь</th>
          <th>Февраль</th>
          <th>Март</th>
          <th>Апрель</th>
          <th>Май</th>
          <th>Июнь</th>
          <th>Июль</th>
          <th>Август</th>
          <th>Сентябрь</th>
          <th>Октябрь</th>
          <th>Ноябрь</th>
          <th>Декабрь</th>
        </tr>
        <tr>
          <td><input type="text" placeholder="Введите задачу спринта"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <td class="editable"></td>
          <tr>
            <td colspan="12">
              <div id="line"></div>
            </td>
          </tr>
      </table>
    </div>
  </div>
</div>


Ответы (0 шт):