From 9abb54d3e85aa129ff17019cddc42f9538f948cc Mon Sep 17 00:00:00 2001 From: Gustavo Rodrigo Gularte Arend Date: Fri, 26 Apr 2024 00:20:53 -0300 Subject: [PATCH 1/2] calendar component --- package.json | 1 + pnpm-lock.yaml | 7 + .../Calendar/components/DateButton/index.js | 28 +++ .../Calendar/components/DateButton/index.scss | 63 +++++ .../Calendar/components/DateSelector/index.js | 219 ++++++++++++++++++ .../components/DateSelector/index.scss | 92 ++++++++ .../Calendar/components/Day/index.js | 43 ++++ .../Calendar/components/Day/index.scss | 53 +++++ .../Calendar/components/Days/index.js | 54 +++++ .../Calendar/components/NavButton/index.js | 36 +++ .../Calendar/components/NavButton/index.scss | 41 ++++ src/components/Calendar/images/arrows.svg | 4 + src/components/Calendar/images/navButton.svg | 3 + src/components/Calendar/index.js | 200 ++++++++++++++++ src/components/Calendar/index.scss | 77 ++++++ src/stories/Calendar.stories.js | 14 ++ 16 files changed, 935 insertions(+) create mode 100644 src/components/Calendar/components/DateButton/index.js create mode 100644 src/components/Calendar/components/DateButton/index.scss create mode 100644 src/components/Calendar/components/DateSelector/index.js create mode 100644 src/components/Calendar/components/DateSelector/index.scss create mode 100644 src/components/Calendar/components/Day/index.js create mode 100644 src/components/Calendar/components/Day/index.scss create mode 100644 src/components/Calendar/components/Days/index.js create mode 100644 src/components/Calendar/components/NavButton/index.js create mode 100644 src/components/Calendar/components/NavButton/index.scss create mode 100644 src/components/Calendar/images/arrows.svg create mode 100644 src/components/Calendar/images/navButton.svg create mode 100644 src/components/Calendar/index.js create mode 100644 src/components/Calendar/index.scss create mode 100644 src/stories/Calendar.stories.js diff --git a/package.json b/package.json index 7204c5b0..8ddbd7d9 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "vitest": "^1.2.2" }, "dependencies": { + "dayjs": "1.11.10", "pet-dex-utilities": "^1.0.1", "reset-css": "^5.0.2", "vite": "^5.0.12", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 909c5d44..59b4bbad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + dayjs: + specifier: 1.11.10 + version: 1.11.10 pet-dex-utilities: specifier: ^1.0.1 version: 1.0.1 @@ -4455,6 +4458,10 @@ packages: es-errors: 1.3.0 is-data-view: 1.0.1 + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: false + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: diff --git a/src/components/Calendar/components/DateButton/index.js b/src/components/Calendar/components/DateButton/index.js new file mode 100644 index 00000000..0b75dc66 --- /dev/null +++ b/src/components/Calendar/components/DateButton/index.js @@ -0,0 +1,28 @@ +import { Component } from 'pet-dex-utilities'; +import './index.scss'; + +const html = ` +
  • +`; + +export default function DateButton(date) { + Component.call(this, { html }); + + const $button = this.selected.get('date').children[0]; + $button.innerText = date; +} + +DateButton.prototype = Object.assign( + DateButton.prototype, + Component.prototype, + { + active() { + this.selected.get('date').classList.add('active'); + }, + + setYear(year) { + const $button = this.selected.get('date').children[0]; + $button.innerText = year; + }, + }, +); diff --git a/src/components/Calendar/components/DateButton/index.scss b/src/components/Calendar/components/DateButton/index.scss new file mode 100644 index 00000000..8c5a228e --- /dev/null +++ b/src/components/Calendar/components/DateButton/index.scss @@ -0,0 +1,63 @@ +@use '~styles/base.scss'; +@use '~styles/colors.scss' as colors; +@use '~styles/fonts.scss' as fonts; +@use '~styles/breakpoints.scss' as breakpoints; + +.date { + button { + font-family: fonts.$primaryFont; + color: colors.$gray500; + font-size: 1.4rem; + font-weight: fonts.$medium; + line-height: 2rem; + + border: 0; + + background-color: transparent; + + cursor: pointer; + } +} + +.date.active { + button { + color: colors.$primary200; + font-size: 2.6rem; + font-weight: fonts.$bold; + line-height: 3.4rem; + + padding: 0.6rem 1.2rem; + border: 0.1rem solid rgb(209, 230, 255); + + background-color: rgba(209, 230, 255, 0.502); + border-radius: 1.4rem; + } +} + +@include breakpoints.from667 { + .date { + display: none; + + button { + width: 100%; + + font-size: fonts.$md; + line-height: 34px; + } + } + + .date.active { + display: flex; + + button { + color: colors.$gray800; + font-size: 2.6rem; + font-weight: fonts.$regular; + + padding: 0.6rem; + border: 0; + + background-color: transparent; + } + } +} diff --git a/src/components/Calendar/components/DateSelector/index.js b/src/components/Calendar/components/DateSelector/index.js new file mode 100644 index 00000000..ad50af7f --- /dev/null +++ b/src/components/Calendar/components/DateSelector/index.js @@ -0,0 +1,219 @@ +import { Component } from 'pet-dex-utilities'; +import './index.scss'; +import { listenBreakpoint } from '../../../../utils/breakpoints/breakpoints'; +import DateButton from '../DateButton'; + +const events = ['changeMonth', 'changeYear']; + +const html = ` + +`; + +const monthsBR = [ + 'Janeiro', + 'Fevereiro', + 'Março', + 'Abril', + 'Maio', + 'Junho', + 'Julho', + 'Agosto', + 'Setembro', + 'Outubro', + 'Novembro', + 'Dezembro', +]; + +let handleTouchStart; +let handleTouchMove; +function addTouchEvents(selector) { + let startTouch; + + handleTouchStart = (event) => { + startTouch = selector.isDesktop + ? event.touches[0].clientY + : event.touches[0].clientX; + }; + + handleTouchMove = (event) => { + event.preventDefault(); + const currentTouch = selector.isDesktop + ? event.touches[0].clientY + : event.touches[0].clientX; + let move = 0; + const moveRange = 20; + move = currentTouch - startTouch; + + if (Math.abs(move) > moveRange) { + const isSlideNext = move < 0; + const nextYear = +selector.dates[3].children[0].innerText; + const prevYear = +selector.dates[1].children[0].innerText; + const nextMonth = monthsBR.indexOf( + selector.dates[3].children[0].innerText, + ); + const prevMonth = monthsBR.indexOf( + selector.dates[1].children[0].innerText, + ); + if (isSlideNext && selector.isYear) selector.setYear(nextYear); + if (!isSlideNext && selector.isYear) selector.setYear(prevYear); + if (isSlideNext && !selector.isYear) selector.setMonth(nextMonth); + if (!isSlideNext && !selector.isYear) selector.setMonth(prevMonth); + startTouch = currentTouch; + } + }; + selector.dateSelector.addEventListener('touchstart', handleTouchStart); + selector.dateSelector.addEventListener('touchmove', handleTouchMove); +} + +let handleScroll; +function scrollModal(selector) { + const $dateSelector = selector.dateSelector; + + handleScroll = (event) => { + event.preventDefault(); + const isScrollNext = event.deltaY > 0; + + if (selector.isYear) { + const nextYear = +selector.dates[3].children[0].innerText; + const prevYear = +selector.dates[1].children[0].innerText; + const newYear = isScrollNext ? nextYear : prevYear; + selector.setYear(newYear); + } else { + const nextMonth = monthsBR.indexOf( + selector.dates[3].children[0].innerText, + ); + const prevMonth = monthsBR.indexOf( + selector.dates[1].children[0].innerText, + ); + const newMonth = isScrollNext ? nextMonth : prevMonth; + selector.setMonth(newMonth); + } + }; + + $dateSelector.addEventListener('wheel', handleScroll); + addTouchEvents(selector); +} + +function openModal(selector) { + const $dateSelector = selector.dateSelector; + $dateSelector.classList.add('active'); + const $activeDate = selector.date; + $activeDate.scrollIntoView({ + behavior: 'instant', + block: 'center', + inline: 'center', + }); +} + +function closeModal(selector, event) { + const $dateSelector = selector.dateSelector; + if ( + $dateSelector.classList.contains('active') && + !$dateSelector.contains(event.target) + ) { + $dateSelector.classList.remove('active'); + } +} + +export default function DateSelector(dateArray) { + Component.call(this, { html, events }); + + this.dateSelector = this.selected.get('date-selector'); + this.dateArray = dateArray; + + this.dateArray.forEach((item, index) => { + const dateButton = new DateButton(item); + dateButton.mount(this.dateSelector); + if (index === 2) { + dateButton.active(); + } + }); + + this.dates = this.dateSelector.querySelectorAll('li'); + this.date = this.dateSelector.querySelector('li.active'); + this.isYear = !Number.isNaN(+this.date.innerText); + listenBreakpoint('from667', (matches) => { + this.isDesktop = matches; + }); + + this.dateClickHandle = (index) => () => { + if (this.isYear) { + this.setYear(this.dateArray[index]); + } else { + this.setMonth(monthsBR.indexOf(this.dateArray[index])); + } + }; + + this.dates.forEach(($date, index) => { + $date.addEventListener('click', this.dateClickHandle(index)); + }); + this.openModalHandle = () => openModal(this); + this.dateSelector.addEventListener('click', this.openModalHandle); + + this.closeModalHandle = (event) => closeModal(this, event); + window.addEventListener('click', this.closeModalHandle); + + scrollModal(this); + + setTimeout(() => { + this.date.scrollIntoView({ + behavior: 'instant', + block: 'center', + inline: 'center', + }); + }); + + this.unmount(() => { + this.dateSelector.removeEventListener('click', this.openModalHandle); + window.removeEventListener('click', this.closeModalHandle); + this.dates.forEach(($date, index) => { + $date.removeEventListener('click', this.dateClickHandle(index)); + }); + this.dateSelector.removeEventListener('wheel', handleScroll); + this.dateSelector.removeEventListener('touchstart', handleTouchStart); + this.dateSelector.removeEventListener('touchmove', handleTouchMove); + }); +} + +DateSelector.prototype = Object.assign( + DateSelector.prototype, + Component.prototype, + { + setMonth(newMonth) { + for (let i = 0; i < this.dateArray.length; i += 1) { + const index = (newMonth - (2 - i) + 12) % 12; + this.dateArray[i] = monthsBR[index]; + } + + this.dateArray.forEach((item, index) => { + this.dates[index].children[0].innerText = item; + }); + + this.date.scrollIntoView({ + behavior: 'instant', + block: 'center', + inline: 'center', + }); + + this.emit('changeMonth', newMonth); + }, + + setYear(newYear) { + for (let i = 0; i < this.dateArray.length; i += 1) { + this.dateArray[i] = newYear - (2 - i); + } + + this.dateArray.forEach((item, index) => { + this.dates[index].children[0].innerText = item; + }); + + this.date.scrollIntoView({ + behavior: 'instant', + block: 'center', + inline: 'center', + }); + + this.emit('changeYear', newYear); + }, + }, +); diff --git a/src/components/Calendar/components/DateSelector/index.scss b/src/components/Calendar/components/DateSelector/index.scss new file mode 100644 index 00000000..5ab3b7d2 --- /dev/null +++ b/src/components/Calendar/components/DateSelector/index.scss @@ -0,0 +1,92 @@ +@use '~styles/base.scss'; +@use '~styles/colors.scss' as colors; +@use '~styles/fonts.scss' as fonts; +@use '~styles/breakpoints.scss' as breakpoints; + +.date-selector { + max-width: 33rem; + overflow-x: hidden; + + display: flex; + gap: 0.8rem; + + align-items: center; + + margin-bottom: 2.4rem; + padding-bottom: 2.4rem; + border-bottom: 0.1rem solid colors.$gray100; + + &:first-child { + order: 2; + } +} + +@include breakpoints.from667 { + .date-selector { + margin-bottom: 0; + padding: 0; + border-bottom: 0; + + &:last-child { + display: flex; + + align-items: center; + + order: 2; + + &::after { + width: 1.6rem; + height: 2.3rem; + + display: inline; + + background-image: url('../../images/arrows.svg'); + + content: ''; + } + } + } + + .date-selector.active { + width: 23.1rem; + max-height: 22.8rem; + overflow-y: hidden; + + display: grid; + gap: 0.6rem; + + position: absolute; + left: -4rem; + + background-color: colors.$secondary100; + + .date { + display: block; + } + + .date.active { + &::after { + width: 1.6rem; + height: 2.3rem; + + display: inline-block; + + margin-top: 1.4rem; + + position: absolute; + right: 2rem; + + background-image: url('../../images/arrows.svg'); + + content: ''; + } + + button { + font-weight: fonts.$bold; + + border-top: 0.1rem solid colors.$gray100; + border-bottom: 0.1rem solid colors.$gray100; + } + } + } +} diff --git a/src/components/Calendar/components/Day/index.js b/src/components/Calendar/components/Day/index.js new file mode 100644 index 00000000..97e08897 --- /dev/null +++ b/src/components/Calendar/components/Day/index.js @@ -0,0 +1,43 @@ +import { Component } from 'pet-dex-utilities'; +import './index.scss'; + +const events = ['changeDay']; + +const html = ` + +`; + +export default function Day(day, dayClass) { + Component.call(this, { html, events }); + + this.$day = this.selected.get('day-button'); + this.$day.innerText = day; + this.$day.setAttribute('aria-label', `Dia ${day}`); + if (dayClass) this.setClass(dayClass); + + const setActiveDayHandle = (event) => this.setClassActive(event); + this.$day.addEventListener('click', setActiveDayHandle); + + this.unmount(() => { + this.$day.removeEventListener('click', setActiveDayHandle); + }); +} + +Day.prototype = Object.assign(Day.prototype, Component.prototype, { + setClass(dayClass) { + this.$day.classList.add(dayClass); + }, + + setClassPrevMonth() { + this.$day.classList.add('prev-month'); + }, + + setClassActive() { + this.$day.classList.add('active'); + this.emit('changeDay', this.$day); + }, + + setClassNextMonth() { + this.$day.classList.add('next-month'); + }, +}); diff --git a/src/components/Calendar/components/Day/index.scss b/src/components/Calendar/components/Day/index.scss new file mode 100644 index 00000000..987e96fd --- /dev/null +++ b/src/components/Calendar/components/Day/index.scss @@ -0,0 +1,53 @@ +@use '~styles/base.scss'; +@use '~styles/colors.scss' as colors; +@use '~styles/fonts.scss' as fonts; +@use '~styles/breakpoints.scss' as breakpoints; + +.day-button { + width: 4rem; + height: 4rem; + + font-family: fonts.$primaryFont; + color: colors.$gray500; + font-size: 1.6rem; + font-weight: fonts.$medium; + + padding: 0; + border: 0.1rem solid colors.$gray100; + + background-color: colors.$secondary100; + border-radius: 1rem; + + cursor: pointer; + + &.prev-month, + &.next-month { + color: rgb(160, 174, 192); + + background-color: rgb(247, 250, 252); + } + + &:hover, + &.active { + color: colors.$primary200; + font-weight: fonts.$semiBold; + + border: 0.1rem solid rgb(209, 230, 255); + + background-color: rgba(209, 230, 255, 0.502); + } +} + +@include breakpoints.from667 { + .day-button { + width: 5.4rem; + height: 5.4rem; + + font-size: 1.8rem; + + &:hover, + &.active { + border: 0.2rem solid rgb(209, 230, 255); + } + } +} diff --git a/src/components/Calendar/components/Days/index.js b/src/components/Calendar/components/Days/index.js new file mode 100644 index 00000000..6eda5ae1 --- /dev/null +++ b/src/components/Calendar/components/Days/index.js @@ -0,0 +1,54 @@ +import { Component } from 'pet-dex-utilities'; +import Day from '../Day'; + +const events = ['changeDay', 'changeToPrevMonth', 'changeToNextMonth']; + +const html = ` +
    +`; + +function changeDay(days, newDayActive) { + const day = +newDayActive.innerText; + const isDayInPrevMonth = newDayActive.classList.contains('prev-month'); + const isDayInNextMonth = newDayActive.classList.contains('next-month'); + + if (isDayInPrevMonth) days.emit('changeToPrevMonth', day); + else if (isDayInNextMonth) days.emit('changeToNextMonth', day); + else days.emit('changeDay', day); +} + +export default function Days( + year, + month, + day, + totalDaysOfMonth, + firstDayOfMonthInWeek, +) { + Component.call(this, { html, events }); + + const $container = this.selected.get('days-container'); + + const totalDaysInCalendar = 42; + for ( + let i = -firstDayOfMonthInWeek; + i < totalDaysInCalendar - firstDayOfMonthInWeek; + i += 1 + ) { + const date = new Date(year, month, i); + const dayNumber = date.getDate(); + const firstDayOfMonth = 1; + + const dayButton = new Day(dayNumber); + + if (i < firstDayOfMonth) dayButton.setClassPrevMonth(); + if (i > totalDaysOfMonth) dayButton.setClassNextMonth(); + if (i === day) dayButton.setClassActive(); + + dayButton.mount($container); + dayButton.listen('changeDay', (newDayActive) => + changeDay(this, newDayActive), + ); + } +} + +Days.prototype = Object.assign(Days.prototype, Component.prototype, {}); diff --git a/src/components/Calendar/components/NavButton/index.js b/src/components/Calendar/components/NavButton/index.js new file mode 100644 index 00000000..bef7bfb3 --- /dev/null +++ b/src/components/Calendar/components/NavButton/index.js @@ -0,0 +1,36 @@ +import { Component } from 'pet-dex-utilities'; +import './index.scss'; +import navButton from '../../images/navButton.svg'; + +const events = ['prev', 'next']; + +const html = ` + +`; + +export default function NavButton(position) { + Component.call(this, { html, events }); + + this.$navButton = this.selected.get('nav-button'); + this.$navButton.classList.add(position); + const isPrev = this.$navButton.classList.contains('prev'); + this.$navButton.setAttribute( + 'aria-label', + isPrev ? 'Ir para o mês anterior' : 'Ir para o próximo mês', + ); + + const navButtonClickHandle = () => { + if (isPrev) { + this.emit('prev'); + } else { + this.emit('next'); + } + }; + this.$navButton.addEventListener('click', navButtonClickHandle); +} + +NavButton.prototype = Object.assign( + NavButton.prototype, + Component.prototype, + {}, +); diff --git a/src/components/Calendar/components/NavButton/index.scss b/src/components/Calendar/components/NavButton/index.scss new file mode 100644 index 00000000..455f811e --- /dev/null +++ b/src/components/Calendar/components/NavButton/index.scss @@ -0,0 +1,41 @@ +@use '~styles/base.scss'; +@use '~styles/colors.scss' as colors; +@use '~styles/fonts.scss' as fonts; +@use '~styles/breakpoints.scss' as breakpoints; + +.nav-button { + display: none; +} + +@include breakpoints.from667 { + .nav-button { + width: 4.6rem; + height: 4.6rem; + + display: grid; + + align-items: center; + justify-content: center; + + font-family: Nato Sans; + color: colors.$gray300; + font-size: 2rem; + + border: 0.1rem solid rgb(160, 174, 192); + + background-color: transparent; + border-radius: 1.4rem; + + cursor: pointer; + } + + .prev { + grid-area: 1; + } + + .next { + justify-self: end; + + transform: rotate(180deg); + } +} diff --git a/src/components/Calendar/images/arrows.svg b/src/components/Calendar/images/arrows.svg new file mode 100644 index 00000000..1ebda089 --- /dev/null +++ b/src/components/Calendar/images/arrows.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/Calendar/images/navButton.svg b/src/components/Calendar/images/navButton.svg new file mode 100644 index 00000000..ea74a960 --- /dev/null +++ b/src/components/Calendar/images/navButton.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Calendar/index.js b/src/components/Calendar/index.js new file mode 100644 index 00000000..87b89c71 --- /dev/null +++ b/src/components/Calendar/index.js @@ -0,0 +1,200 @@ +import { Component } from 'pet-dex-utilities'; +import './index.scss'; +import dayjs from 'dayjs'; +import DateSelector from './components/DateSelector'; +import NavButton from './components/NavButton'; +import Days from './components/Days'; + +const events = ['changeDate', 'changeMonth', 'changeYear']; + +const monthsBR = [ + 'Janeiro', + 'Fevereiro', + 'Março', + 'Abril', + 'Maio', + 'Junho', + 'Julho', + 'Agosto', + 'Setembro', + 'Outubro', + 'Novembro', + 'Dezembro', +]; + +const currentMonth = dayjs().month(); +const months = new Array(5); +for (let i = 0; i < months.length; i += 1) { + const monthIndex = (currentMonth - (2 - i) + 12) % 12; + months[i] = monthsBR[monthIndex]; +} + +const currentYear = dayjs().year(); +const years = new Array(5); +for (let i = 0; i < years.length; i += 1) { + years[i] = currentYear - (2 - i); +} + +const html = ` +
    + +
    +
    +

    Dom

    +

    Seg

    +

    Ter

    +

    Qua

    +

    Qui

    +

    Sex

    +

    Sab

    +
    +
    +`; + +export default function Calendar() { + Component.call(this, { html, events }); + + this.setDate(); + + this.monthSelect = new DateSelector(months); + this.monthSelect.mount(this.selected.get('calendar-date')); + this.monthSelect.listen('changeMonth', (newMonth) => + this.setDate(this.day, newMonth, this.year), + ); + + this.yearSelect = new DateSelector(years); + this.yearSelect.mount(this.selected.get('calendar-date')); + this.yearSelect.listen('changeYear', (newYear) => + this.setDate(this.day, this.month, newYear), + ); + + this.navButton = new NavButton('prev'); + this.navButton.mount(this.selected.get('calendar-nav')); + this.navButton.listen('prev', () => this.goToPrevMonth()); + + this.navButton = new NavButton('next'); + this.navButton.mount(this.selected.get('calendar-nav')); + this.navButton.listen('next', () => this.goToNextMonth()); +} + +Calendar.prototype = Object.assign(Calendar.prototype, Component.prototype, { + getDate() { + return { + day: this.day, + month: this.month, + year: this.year, + }; + }, + + setDate(day, month, year) { + this.day = day || dayjs().date(); + this.month = month !== undefined ? month : dayjs().month(); + this.year = year || dayjs().year(); + this.totalDaysOfMonth = dayjs( + `${this.year}-${this.month + 1}`, + ).daysInMonth(); + this.firstDayOfMonthInWeek = + dayjs(`${this.year}-${this.month + 1}-1`).day() - 1; + + this.setDays(); + + this.emit('changeDate', { + day: this.day, + month: this.month, + year: this.year, + }); + }, + + getDay() { + return this.day; + }, + + setDay(day) { + if (day < 1 || day > this.totalDaysOfMonth) { + throw new Error('Dia inválido'); + } else if (typeof day !== 'number') { + throw new Error('O valor não é um number'); + } else { + this.setDate(day, this.month, this.year); + } + }, + + setDays() { + if (this.days) this.days.unmount(); + this.days = new Days( + this.year, + this.month, + this.day, + this.totalDaysOfMonth, + this.firstDayOfMonthInWeek, + ); + this.days.mount(this.selected.get('calendar-days')); + + this.days.listen('changeDay', (newDay) => { + this.setDate(newDay, this.month, this.year); + }); + + this.days.listen('changeToPrevMonth', (newDay) => { + this.goToPrevMonth(); + this.setDay(newDay); + }); + + this.days.listen('changeToNextMonth', (newDay) => { + this.goToNextMonth(); + this.setDay(newDay); + }); + }, + + getMonth() { + return this.month; + }, + + setMonth(month) { + if (month < 0 || month > 11) { + throw new Error('Mês inválido'); + } else if (typeof month !== 'number') { + throw new Error('O valor não é um number'); + } else { + this.setDate(this.day, month, this.year); + } + }, + + getYear() { + return this.year; + }, + + setYear(year) { + if (year < 0) { + throw new Error('Ano inválido'); + } else if (typeof year !== 'number') { + throw new Error('O valor não é um number'); + } else { + this.setDate(this.day, this.month, year); + } + }, + + goToPrevMonth() { + this.month -= 1; + if (this.month < 0) { + this.month = 11; + this.year -= 1; + this.yearSelect.setYear(this.year); + } + this.monthSelect.setMonth(this.month); + this.setDate(this.day, this.month, this.year); + }, + + goToNextMonth() { + this.month += 1; + if (this.month > 11) { + this.month = 0; + this.year += 1; + this.yearSelect.setYear(this.year); + } + this.monthSelect.setMonth(this.month); + this.setDate(this.day, this.month, this.year); + }, +}); diff --git a/src/components/Calendar/index.scss b/src/components/Calendar/index.scss new file mode 100644 index 00000000..b50dcef6 --- /dev/null +++ b/src/components/Calendar/index.scss @@ -0,0 +1,77 @@ +@use '~styles/base.scss'; +@use '~styles/colors.scss' as colors; +@use '~styles/fonts.scss' as fonts; +@use '~styles/breakpoints.scss' as breakpoints; + +.calendar-container { + display: grid; + + padding: 2.4rem 0; + + background-color: rgb(250, 250, 250); + + &__date { + width: 100%; + max-width: 34rem; + + margin: 0 auto; + + &-select { + display: grid; + + justify-items: center; + } + } + + &__days { + margin: 0 auto; + padding: 0 1rem; + + div { + display: grid; + grid-template-columns: repeat(7, 1fr); + gap: 0.8rem; + + justify-items: center; + } + + p { + font-family: Noto Sans; + color: colors.$gray300; + text-align: center; + font-size: 1.2rem; + font-weight: fonts.$regular; + line-height: 2rem; + + padding-bottom: 1.2rem; + } + } +} + +@include breakpoints.from667 { + .calendar-container { + &__days { + p { + font-size: 1.6rem; + } + } + + &__date { + max-width: 42rem; + + display: grid; + grid-template-columns: 1fr 1fr 1fr; + + align-items: center; + + margin: 0 auto; + padding-bottom: 3rem; + + &-select { + display: flex; + + position: relative; + } + } + } +} diff --git a/src/stories/Calendar.stories.js b/src/stories/Calendar.stories.js new file mode 100644 index 00000000..133cf423 --- /dev/null +++ b/src/stories/Calendar.stories.js @@ -0,0 +1,14 @@ +import Calendar from '../components/Calendar'; + +export default { + title: 'Components/Calendar', + render: (args) => { + const calendar = new Calendar(args); + const $container = document.createElement('div'); + calendar.mount($container); + + return $container; + }, +}; + +export const Default = {}; From ed43c0fbd66bc67bf1be6a72256a2914baa55e03 Mon Sep 17 00:00:00 2001 From: Gustavo Rodrigo Gularte Arend Date: Fri, 26 Apr 2024 01:26:42 -0300 Subject: [PATCH 2/2] removido o metodo setYear de dateButton --- src/components/Calendar/components/DateButton/index.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/Calendar/components/DateButton/index.js b/src/components/Calendar/components/DateButton/index.js index 0b75dc66..e2bae8a5 100644 --- a/src/components/Calendar/components/DateButton/index.js +++ b/src/components/Calendar/components/DateButton/index.js @@ -19,10 +19,5 @@ DateButton.prototype = Object.assign( active() { this.selected.get('date').classList.add('active'); }, - - setYear(year) { - const $button = this.selected.get('date').children[0]; - $button.innerText = year; - }, }, );