You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

140 lines
3.4 KiB

<script>
import Icon from '$/client/components/Icon.svelte';
import eachDayOfInterval from 'date-fns/eachDayOfInterval';
import add from 'date-fns/add';
import sub from 'date-fns/sub';
import isSunday from 'date-fns/isSunday';
import isSameDay from 'date-fns/isSameDay';
import {createEventDispatcher} from "svelte";
const dispatch = createEventDispatcher();
let today = new Date();
let year = today.getFullYear();
let month = today.getMonth();
let fom = new Date(year, month, 1);
let display_date = fom.toLocaleDateString("en-US", { year: "numeric", month: "long" });
/* Super American oriented, but future versions could use more of the Temporal API when it's more
prevalent. */
const first_sunday = () => {
if(isSunday(fom)) {
return fom; // awesome, it's a sunday
} else {
// looks like we have to find the previous sunday
let prev = sub(fom, {days: 1});
for(let i = 0; i < 7; i++) {
if(isSunday(prev)) {
return prev;
} else {
prev = sub(prev, {days: 1});
return prev;
}
}
}
}
let start = first_sunday(month);
let end = add(start, { days: 35});
const make_dates = () => {
end = add(start, { days: (6 * 7) - 1});
return eachDayOfInterval({start, end});
}
let dates = make_dates(month);
const update_month = () => {
year = fom.getFullYear();
month = fom.getMonth();
start = first_sunday();
end = add(start, { days: (6 * 7) - 1});
display_date = fom.toLocaleDateString("en-US", { year: "numeric", month: "long" });
dates = make_dates();
}
const next_month = () => {
fom = add(fom, {months: 1});
update_month();
dispatch("next", {fom});
}
const prev_month = () => {
fom = sub(fom, {months: 1});
update_month();
dispatch("previous", {fom});
}
</script>
<style>
content {
display: flex;
flex-grow: 1;
}
calendar {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: auto;
outline: 1px solid var(--color-accent);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
calendar day {
background-color: var(--color-bg-secondary);
font-weight: bold;
padding-left: 0.3rem;
padding-right: 0.3rem;
}
calendar month {
grid-column: span 5;
font-size: 1.5em;
font-weight: bold;
text-align: center;
justify-content: space-evenly;
}
calendar span {
text-align: center;
display: inline-block;
}
calendar date {
padding: 0.3rem;
padding-left: 0.5rem;
}
calendar date:hover {
background-color: var(--color-bg-secondary);
}
calendar date.not-month {
color: var(--color-inactive);
}
calendar date.today {
color: var(--color-bg);
background-color: var(--color);
}
</style>
<content>
<calendar>
<span on:click={ () => prev_month(-1) }><Icon name="arrow-left-circle" size="1.5em" /></span>
<month>
{ display_date }
</month>
<span on:click={ () => next_month(1) }><Icon name="arrow-right-circle" size="1.5em" /></span>
<day>Sun</day><day>Mon</day><day>Tue</day><day>Wed</day><day>Thu</day><day>Fri</day><day>Sat</day>
{#each dates as date}
<date class:today={ isSameDay(date, today) } class:not-month={ date.getMonth() !== fom.getMonth()} on:click={ () => dispatch("select", date) }>{date.getDate()}</date>
{/each}
</calendar>
</content>