Создание подобного Google Calendar компонента с помощью React - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь создать свой собственный компонент еженедельного календаря, используя React и Luxon.

Мой компонент реакции отображает таблицу HTML, каждая ячейка представляет день и время в дне.

Я успешно создал события по щелчку td, используя его идентификатор, событие создает дочерний компонент Event в td.

Однако у меня возникают проблемы при попытке расширить мой компонент Event, чтобы он занимал дополнительные строки.

1) Мне не удалось реализовать успешную функцию изменения размера компонента Event. Я использовал свойство «resize: vertical» css, но когда я отпускаю щелчок, он возвращается к своему первоначальному размеру.

2) Я до сих пор не знаю, будет ли это правильный подход, поскольку я не знаю, есть ли способ, которым я могу сказать реагировать, что мой измененный компонент теперь занимает 2+ строки.

3) Мне интересно, возможно ли расширить дочерний компонент над другой строкой и настроить его на полную высоту новая строка.

Это мой (очень незаконченный) компонент (я также использую Bulma для CSS)

import React, { useState } from 'react'
import { DateTime, Duration } from 'luxon'

function Calendar() {

  const startTime = Duration.fromObject({ hours: 8 })
  const endTime = Duration.fromObject({ hours: 20 })
  const start = DateTime.local().startOf('day').plus(startTime)
  const end = DateTime.local().startOf('day').plus(endTime)
  const dur = Duration.fromObject({ minutes: 15 })
  const range = end.diff(start, ['hours']).hours
  const today = DateTime.local()

  // const [cellData, setcellData] = useState()
  const [activeWeek, setactiveWeek] = useState(today.startOf('week'))
  const [events, setevents] = useState({})
  const [month, setmonth] = useState(activeWeek.toLocaleString({ month: 'long', }))

  // const testTime = DateTime.fromMillis(1586438100000)
  // const testDay = DateTime.fromMillis(1586232000000)
  // console.log('time', testTime.c.hour)
  // console.log('day', testDay.plus({ hours: testTime.c.hour, minutes: testTime.c.minute }).toLocaleString(DateTime.DATETIME_FULL))


  const getTimeSlots = (start, dur, range) => {
    let slotRange = range * 4
    let arr = []
    for (let i = 0; i <= slotRange; i++) {
      arr = [...arr, {
        formatted: start.toLocaleString(DateTime.TIME_24_SIMPLE),
        date: start
      }]
      start = start.plus(dur)
    }
    return arr
  }

  const getWeekDays = () => {
    let arr = []
    for (let i = 0; i < 7; i++) {
      let dayOfWeek = activeWeek.plus({ days: i })

      let dayDisplayFormat = {
        letters: dayOfWeek.toFormat('EEE'),
        number: dayOfWeek.toFormat('dd')
      }
      arr = [...arr, {
        formatted: dayDisplayFormat,
        date: dayOfWeek
      }]
    }
    return arr
  }

  const weekDays = getWeekDays()
  const timeSlots = getTimeSlots(start, dur, range)
  // console.log(timeSlots)


  const handleEntryCreation = (e) => {
    setevents({
      ...events,
      [e.target.id]: {
        date: DateTime.fromFormat(e.target.id, 'EEE dd')
      }
    })
    console.log(events)
  }

  const calculateSlotDate = (day, time) => {
    const slotDate = day.plus({ hours: time.c.hour, minutes: time.c.minute })
    return slotDate
  }

  const handleWeekChange = (action) => {
    action === 'forward' ?
      setactiveWeek(activeWeek.plus({ week: 1 })) :
      setactiveWeek(activeWeek.minus({ week: 1 }))
    setmonth(activeWeek.toLocaleString({ month: 'long', }))
  }

  const Box = () => {
    return (
      <div className="calendarbox-container">
        <div className="calendarbox">
        </div>

      </div>
    )
  }

  return (
    <div className="calendar">
      <h1 className="title calendar-title">{month}</h1>
      < table className="table is-bordered is-fullwidth" >
        <thead>
          <tr>
            <th onClick={() => handleWeekChange('back')}>{'<'}</th>
            {weekDays.map((day) => (
              <th key={day.date.ts}>
                {day.formatted.letters}
                <br />
                <span className={
                  today.hasSame(day.date, 'day') ?
                    'calendar-today' :
                    'calendar-notToday'
                }>{day.formatted.number}</span>
              </th>
            ))}
            <th onClick={() => handleWeekChange('forward')}>{'>'}</th>
          </tr>
        </thead>
        <tbody>
          {timeSlots.map((time) => (
            <tr key={time.date.ts}>
              <td key={`right_${time.date.ts}`}>
                {time.formatted}
              </td>
              {weekDays.map((day) => {
                const slotValue = calculateSlotDate(day.date, time.date)
                return (
                  <td
                    key={slotValue.toMillis()}
                    id={slotValue.toMillis()}
                    onClick={handleEntryCreation}
                  >
                    {events[slotValue.toMillis()] ?
                      <Box /> :
                      null
                    }

                  </td>
                )
              })}
              <td key={`left_${time.date.ts}`}>{time.formatted}</td>
            </tr>
          ))}
        </tbody>
      </table >
    </div>
  )
}

export default Calendar
.calendar {
  td {
    &:hover {
      background-color: yellow;
    }
    width: 100%;
    height: 50px;
    display: flex;
    justify-content: center;
    padding: 0.25rem;
    border-left: 0;
    border-bottom: 0;
    // user-select: none;
  }
  tr {
    display: flex;
    justify-content: center;
    // height: 50px;
    // align-items: center;
  }
  th {
    text-align: center !important;
    align-items: center;
    justify-content: center;
    border: 0 !important;
    width: 100%;
    user-select: none;
  }
  table {
    // table-layout: fixed;
  }
  &-title {
    text-align: center;
    text-transform: capitalize;
  }
  &-today {
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto;
    background-color: blue;
    border-radius: 100%;
    height: 40px;
    width: 40px;
  }
  &-notToday {
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto;
    height: 40px;
    width: 40px;
  }
}

.calendarbox {
  &-container {
    max-width: 100%;
    display: flex;
    margin: 0;
    // position: relative;
    z-index: 60;
  }
  // position: absolute;
  width: 100px;
  overflow: hidden;
  height: 10px;
  flex-grow: 1;
  background-color: blue;
  resize: vertical !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...