Add entry image backgrounds and indicators to calendar !
This commit is contained in:
@@ -1,7 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
interface Entry {
|
||||||
|
date: string;
|
||||||
|
id: string;
|
||||||
|
image?: string;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
year = $bindable('2026'),
|
year = $bindable('2026'),
|
||||||
month = $bindable('0')
|
month = $bindable('0'),
|
||||||
|
entries
|
||||||
} = $props()
|
} = $props()
|
||||||
|
|
||||||
var headers = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
var headers = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||||
@@ -10,6 +18,16 @@
|
|||||||
let currentYear = $state(parseInt(year));
|
let currentYear = $state(parseInt(year));
|
||||||
let currentMonth = $state(parseInt(month));
|
let currentMonth = $state(parseInt(month));
|
||||||
|
|
||||||
|
// Helper function to find entry for a specific day
|
||||||
|
function getEntryForDay(year: number, month: number, date: number): Entry | undefined {
|
||||||
|
if (!entries) return undefined;
|
||||||
|
const dateStr = new Date(year, month, date).toISOString().split('T')[0];
|
||||||
|
return entries.find(entry => {
|
||||||
|
const entryDate = entry.date.split('T')[0];
|
||||||
|
return entryDate === dateStr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Get current week when in week view
|
// Get current week when in week view
|
||||||
function getCurrentWeek() {
|
function getCurrentWeek() {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
@@ -23,13 +41,15 @@
|
|||||||
for (let i = 0; i < 7; i++) {
|
for (let i = 0; i < 7; i++) {
|
||||||
const day = new Date(monday);
|
const day = new Date(monday);
|
||||||
day.setDate(monday.getDate() + i);
|
day.setDate(monday.getDate() + i);
|
||||||
|
const entry = getEntryForDay(day.getFullYear(), day.getMonth(), day.getDate());
|
||||||
week.push({
|
week.push({
|
||||||
date: day.getDate(),
|
date: day.getDate(),
|
||||||
month: day.getMonth(),
|
month: day.getMonth(),
|
||||||
year: day.getFullYear(),
|
year: day.getFullYear(),
|
||||||
dayName: headers[i],
|
dayName: headers[i],
|
||||||
isCurrentMonth: day.getMonth() === today.getMonth(),
|
isCurrentMonth: day.getMonth() === today.getMonth(),
|
||||||
isToday: day.toDateString() === today.toDateString()
|
isToday: day.toDateString() === today.toDateString(),
|
||||||
|
entry
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return week;
|
return week;
|
||||||
@@ -51,13 +71,18 @@
|
|||||||
const prevMonthLastDay = new Date(year, month, 0).getDate();
|
const prevMonthLastDay = new Date(year, month, 0).getDate();
|
||||||
for (let i = startDay - 1; i >= 0; i--) {
|
for (let i = startDay - 1; i >= 0; i--) {
|
||||||
const dayIndex = days.length % 7;
|
const dayIndex = days.length % 7;
|
||||||
|
const dayDate = prevMonthLastDay - i;
|
||||||
|
const dayMonth = month - 1;
|
||||||
|
const dayYear = month === 0 ? year - 1 : year;
|
||||||
|
const entry = getEntryForDay(dayYear, dayMonth, dayDate);
|
||||||
days.push({
|
days.push({
|
||||||
date: prevMonthLastDay - i,
|
date: dayDate,
|
||||||
month: month - 1,
|
month: dayMonth,
|
||||||
year: month === 0 ? year - 1 : year,
|
year: dayYear,
|
||||||
dayName: headers[dayIndex],
|
dayName: headers[dayIndex],
|
||||||
isCurrentMonth: false,
|
isCurrentMonth: false,
|
||||||
isToday: false
|
isToday: false,
|
||||||
|
entry
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,13 +93,15 @@
|
|||||||
today.getMonth() === month &&
|
today.getMonth() === month &&
|
||||||
today.getFullYear() === year;
|
today.getFullYear() === year;
|
||||||
const dayIndex = days.length % 7;
|
const dayIndex = days.length % 7;
|
||||||
|
const entry = getEntryForDay(year, month, i);
|
||||||
days.push({
|
days.push({
|
||||||
date: i,
|
date: i,
|
||||||
month: month,
|
month: month,
|
||||||
year: year,
|
year: year,
|
||||||
dayName: headers[dayIndex],
|
dayName: headers[dayIndex],
|
||||||
isCurrentMonth: true,
|
isCurrentMonth: true,
|
||||||
isToday
|
isToday,
|
||||||
|
entry
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,13 +109,17 @@
|
|||||||
const remaining = 42 - days.length; // 6 rows * 7 days
|
const remaining = 42 - days.length; // 6 rows * 7 days
|
||||||
for (let i = 1; i <= remaining; i++) {
|
for (let i = 1; i <= remaining; i++) {
|
||||||
const dayIndex = days.length % 7;
|
const dayIndex = days.length % 7;
|
||||||
|
const dayMonth = month + 1;
|
||||||
|
const dayYear = month === 11 ? year + 1 : year;
|
||||||
|
const entry = getEntryForDay(dayYear, dayMonth, i);
|
||||||
days.push({
|
days.push({
|
||||||
date: i,
|
date: i,
|
||||||
month: month + 1,
|
month: dayMonth,
|
||||||
year: month === 11 ? year + 1 : year,
|
year: dayYear,
|
||||||
dayName: headers[dayIndex],
|
dayName: headers[dayIndex],
|
||||||
isCurrentMonth: false,
|
isCurrentMonth: false,
|
||||||
isToday: false
|
isToday: false,
|
||||||
|
entry
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,12 +186,24 @@
|
|||||||
|
|
||||||
<div class="calendar">
|
<div class="calendar">
|
||||||
{#each days as day, index}
|
{#each days as day, index}
|
||||||
<div class="day" class:other-month={!day.isCurrentMonth} class:today={day.isToday}>
|
<div
|
||||||
|
class="day"
|
||||||
|
class:other-month={!day.isCurrentMonth}
|
||||||
|
class:today={day.isToday}
|
||||||
|
class:has-image={day.entry?.image}
|
||||||
|
style={day.entry?.image ? `background-image: url(${day.entry.image}); background-size: cover; background-position: center;` : ''}
|
||||||
|
>
|
||||||
|
{#if day.entry?.image}
|
||||||
|
<div class="image-overlay"></div>
|
||||||
|
{/if}
|
||||||
<div class="day-header">
|
<div class="day-header">
|
||||||
{#if index < 7}
|
{#if index < 7}
|
||||||
<span class="day-name">{day.dayName}</span>
|
<span class="day-name">{day.dayName}</span>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="date">{day.date}</span>
|
<span class="date">{day.date}</span>
|
||||||
|
{#if day.entry}
|
||||||
|
<span class="entry-indicator"></span>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -187,7 +230,7 @@
|
|||||||
height: 36px;
|
height: 36px;
|
||||||
border: 1px solid rgba(166, 168, 179, 0.2);
|
border: 1px solid rgba(166, 168, 179, 0.2);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: #e9a1a7;
|
color: #009FB7;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -199,7 +242,7 @@
|
|||||||
|
|
||||||
.expand-btn:hover {
|
.expand-btn:hover {
|
||||||
background: rgba(233, 161, 167, 0.1);
|
background: rgba(233, 161, 167, 0.1);
|
||||||
border-color: #e9a1a7;
|
border-color: #009FB7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-btn {
|
.nav-btn {
|
||||||
@@ -207,7 +250,7 @@
|
|||||||
height: 32px;
|
height: 32px;
|
||||||
border: 1px solid rgba(166, 168, 179, 0.2);
|
border: 1px solid rgba(166, 168, 179, 0.2);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: #e9a1a7;
|
color: #009FB7;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -219,13 +262,13 @@
|
|||||||
|
|
||||||
.nav-btn:hover {
|
.nav-btn:hover {
|
||||||
background: rgba(233, 161, 167, 0.1);
|
background: rgba(233, 161, 167, 0.1);
|
||||||
border-color: #e9a1a7;
|
border-color: #009FB7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.month-year {
|
.month-year {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #e9a1a7;
|
color: #009FB7;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -248,17 +291,33 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.day.has-image {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.day-header {
|
.day-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.day-name {
|
.day-name {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: #e9a1a7;
|
color: #009FB7;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,6 +327,21 @@
|
|||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entry-indicator {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #4a9eff;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day.has-image .day-name,
|
||||||
|
.day.has-image .date {
|
||||||
|
color: white;
|
||||||
|
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
.day.other-month {
|
.day.other-month {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
@@ -277,7 +351,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.day.today .date {
|
.day.today .date {
|
||||||
color: #e9a1a7;
|
color: #009FB7;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Calendar />
|
<Calendar entries={data.all} />
|
||||||
|
|
||||||
<div class="flex flex-col md:flex-row space-y-4 w-full mt-6">
|
<div class="flex flex-col md:flex-row space-y-4 w-full mt-6">
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user