276 lines
No EOL
6 KiB
Svelte
276 lines
No EOL
6 KiB
Svelte
<script lang="ts">
|
|
|
|
var dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
let monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
|
|
let headers: Array<string> = [];
|
|
let now = new Date();
|
|
let year = now.getFullYear(); // this is the month & year displayed
|
|
let month = now.getMonth();
|
|
var days: Array<Object> = []; // The days to display in each box
|
|
|
|
$: month,year,initContent();
|
|
|
|
// choose what date/day gets displayed in each date box.
|
|
function initContent() {
|
|
headers = dayNames;
|
|
initMonth();
|
|
}
|
|
|
|
function initMonth() {
|
|
days = [];
|
|
// find the last Monday of the previous month
|
|
var firstDay = new Date(year, month, 1).getDay();
|
|
//console.log('fd='+firstDay+' '+dayNames[firstDay]);
|
|
var daysInThisMonth = new Date(year, month+1, 0).getDate();
|
|
var daysInLastMonth = new Date(year, month, 0).getDate();
|
|
var prevMonth = month==0 ? 11 : month-1;
|
|
|
|
// show the days before the start of this month (disabled) - always less than 7
|
|
for (let i=daysInLastMonth-firstDay;i<daysInLastMonth;i++) {
|
|
let d = new Date(prevMonth==11?year-1:year,prevMonth,i+1);
|
|
days.push({name:''+(i+1),enabled:false,date:d,});
|
|
}
|
|
// show the days in this month (enabled) - always 28 - 31
|
|
for (let i=0;i<daysInThisMonth;i++) {
|
|
let d = new Date(year,month,i+1);
|
|
if (i==0) days.push({name:(i+1),enabled:true,date:d,});
|
|
else days.push({name:''+(i+1),enabled:true,date:d,});
|
|
//console.log('i='+i+' dt is '+d+' date() is '+d.getDate());
|
|
}
|
|
// show any days to fill up the last row (disabled) - always less than 7
|
|
for (let i=0;days.length%7;i++) {
|
|
let d = new Date((month==11?year+1:year),(month+1)%12,i+1);
|
|
if (i==0) days.push({name:(i+1),enabled:false,date:d,});
|
|
else days.push({name:''+(i+1),enabled:false,date:d,});
|
|
}
|
|
}
|
|
|
|
function next() {
|
|
month++;
|
|
if (month == 12) {
|
|
year++;
|
|
month=0;
|
|
}
|
|
}
|
|
function prev() {
|
|
if (month==0) {
|
|
month=11;
|
|
year--;
|
|
} else {
|
|
month--;
|
|
}
|
|
}
|
|
|
|
let selected: Object;
|
|
|
|
function isCurrent(date: Date) {
|
|
if (now.getDate() == date.getDate() &&
|
|
now.getMonth() == date.getMonth() &&
|
|
now.getFullYear() == date.getFullYear())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
function set_day(day: Object) {
|
|
selected = day;
|
|
return null;
|
|
}
|
|
</script>
|
|
|
|
<div class="calendar input rounded">
|
|
<div class="month">
|
|
<ul>
|
|
<button class="prev" onclick={prev}>❮</button>
|
|
<button class="next" onclick={next}>❯</button>
|
|
<li>{monthNames[month]} {year}</li>
|
|
</ul>
|
|
</div>
|
|
<ul class="weekdays">
|
|
{#each headers as weekday}
|
|
<li>{weekday}</li>
|
|
{/each}
|
|
</ul>
|
|
<ul class="days">
|
|
{#each days as day}
|
|
<li>
|
|
{#if selected == day}
|
|
<button class="active {isCurrent(day.date) ? "current":""}">{day.name}</button>
|
|
{:else}
|
|
<button class="nonactive {isCurrent(day.date) ? "current":""}" onclick={() => set_day(day)}>{day.name}</button>
|
|
{/if}
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
</div>
|
|
|
|
<style>
|
|
ul {list-style-type: none;}
|
|
|
|
.calendar {
|
|
padding: 0;
|
|
}
|
|
|
|
.calendar * {
|
|
margin: 0;
|
|
}
|
|
|
|
.month {
|
|
width: 100%;
|
|
text-align: center;
|
|
align-content: center;
|
|
}
|
|
|
|
.month ul {
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.month ul li {
|
|
text-transform: uppercase;
|
|
letter-spacing: 3px;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.month ul button {
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.month .prev {
|
|
float: inline-start;
|
|
cursor: pointer;
|
|
background: none;
|
|
}
|
|
|
|
.month .next {
|
|
float: inline-end;
|
|
cursor: pointer;
|
|
background: none;
|
|
}
|
|
|
|
.weekdays {
|
|
padding: 10px 0 0 0;
|
|
}
|
|
|
|
.weekdays li {
|
|
display: inline-block;
|
|
width: 14.2%;
|
|
text-align: center;
|
|
}
|
|
|
|
.days {
|
|
padding: 10px 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.days li {
|
|
list-style-type: none;
|
|
display: inline-block;
|
|
width: 14.2%;
|
|
text-align: center;
|
|
margin-bottom: 5px;
|
|
font-size: smaller;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.days li .current {
|
|
height: 2em;
|
|
padding: 5px;
|
|
aspect-ratio: 1/1;
|
|
border-radius: 30%;
|
|
}
|
|
|
|
.days li .active {
|
|
height: 2em;
|
|
padding: 5px;
|
|
border-radius: 30%;
|
|
aspect-ratio: 1/1;
|
|
}
|
|
|
|
.days li .nonactive {
|
|
height: 2em;
|
|
padding: 5px;
|
|
background: none;
|
|
aspect-ratio: 1/1;
|
|
}
|
|
|
|
@media (prefers-color-scheme: light) {
|
|
.month {
|
|
background: #5C8DC0;
|
|
}
|
|
|
|
.month ul button {
|
|
color: white;
|
|
}
|
|
|
|
.month ul li {
|
|
color: white;
|
|
}
|
|
|
|
.weekdays {
|
|
background-color: #F4F4F4;
|
|
}
|
|
|
|
.weekdays li {
|
|
color: black;
|
|
}
|
|
|
|
.days {
|
|
background: #F4F4F4;
|
|
}
|
|
|
|
.days li button {
|
|
color: black;
|
|
}
|
|
|
|
.days li .active {
|
|
color: white !important;
|
|
background: #5C8DC0 !important;
|
|
}
|
|
|
|
.days li .current {
|
|
color: white !important;
|
|
background: red;
|
|
}
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
.month {
|
|
background: #2791FF;
|
|
}
|
|
|
|
.month ul button {
|
|
color: white;
|
|
}
|
|
|
|
.month ul li {
|
|
color: white;
|
|
}
|
|
|
|
.weekdays {
|
|
background-color: #192431;
|
|
}
|
|
|
|
.weekdays li {
|
|
color: white;
|
|
}
|
|
|
|
.days {
|
|
background: #192431;
|
|
}
|
|
|
|
.days li button {
|
|
color: white;
|
|
}
|
|
|
|
.days li .active {
|
|
color: white !important;
|
|
background: #2791FF !important;
|
|
}
|
|
|
|
.days li .current {
|
|
color: white !important;
|
|
background: red;
|
|
}
|
|
}
|
|
</style> |