diff --git a/src/elements/SwpEventElement.ts b/src/elements/SwpEventElement.ts
index 6acbbb5..9f288e3 100644
--- a/src/elements/SwpEventElement.ts
+++ b/src/elements/SwpEventElement.ts
@@ -60,6 +60,13 @@ export abstract class BaseSwpEventElement extends HTMLElement {
this.dataset.title = value;
}
+ get description(): string {
+ return this.dataset.description || '';
+ }
+ set description(value: string) {
+ this.dataset.description = value;
+ }
+
get type(): string {
return this.dataset.type || 'work';
}
@@ -77,7 +84,7 @@ export class SwpEventElement extends BaseSwpEventElement {
* Observed attributes - changes trigger attributeChangedCallback
*/
static get observedAttributes() {
- return ['data-start', 'data-end', 'data-title', 'data-type'];
+ return ['data-start', 'data-end', 'data-title', 'data-description', 'data-type'];
}
/**
@@ -199,6 +206,7 @@ export class SwpEventElement extends BaseSwpEventElement {
this.innerHTML = `
${timeRange}
${this.title}
+ ${this.description ? `${this.description}` : ''}
`;
}
@@ -208,6 +216,7 @@ export class SwpEventElement extends BaseSwpEventElement {
private updateDisplay(): void {
const timeEl = this.querySelector('swp-event-time');
const titleEl = this.querySelector('swp-event-title');
+ const descEl = this.querySelector('swp-event-description');
if (timeEl && this.dataset.start && this.dataset.end) {
const start = new Date(this.dataset.start);
@@ -223,6 +232,20 @@ export class SwpEventElement extends BaseSwpEventElement {
if (titleEl && this.dataset.title) {
titleEl.textContent = this.dataset.title;
}
+
+ if (this.dataset.description) {
+ if (descEl) {
+ descEl.textContent = this.dataset.description;
+ } else if (this.description) {
+ // Add description element if it doesn't exist
+ const newDescEl = document.createElement('swp-event-description');
+ newDescEl.textContent = this.description;
+ this.appendChild(newDescEl);
+ }
+ } else if (descEl) {
+ // Remove description element if description is empty
+ descEl.remove();
+ }
}
@@ -265,6 +288,7 @@ export class SwpEventElement extends BaseSwpEventElement {
element.dataset.eventId = event.id;
element.dataset.title = event.title;
+ element.dataset.description = event.description || '';
element.dataset.start = dateService.toUTC(event.start);
element.dataset.end = dateService.toUTC(event.end);
element.dataset.type = event.type;
@@ -280,6 +304,7 @@ export class SwpEventElement extends BaseSwpEventElement {
return {
id: element.dataset.eventId || '',
title: element.dataset.title || '',
+ description: element.dataset.description || undefined,
start: new Date(element.dataset.start || ''),
end: new Date(element.dataset.end || ''),
type: element.dataset.type || 'work',
diff --git a/src/types/CalendarTypes.ts b/src/types/CalendarTypes.ts
index 77dbd8c..9c7cb50 100644
--- a/src/types/CalendarTypes.ts
+++ b/src/types/CalendarTypes.ts
@@ -17,6 +17,7 @@ export interface IRenderContext {
export interface ICalendarEvent {
id: string;
title: string;
+ description?: string;
start: Date;
end: Date;
type: string; // Flexible event type - can be any string value
diff --git a/wwwroot/css/calendar-events-css.css b/wwwroot/css/calendar-events-css.css
index 5feab37..927b485 100644
--- a/wwwroot/css/calendar-events-css.css
+++ b/wwwroot/css/calendar-events-css.css
@@ -12,7 +12,14 @@ swp-day-columns swp-event {
right: 2px;
color: var(--color-text);
font-size: 12px;
- padding: 2px 4px;
+ padding: 4px 6px;
+
+ /* CSS Grid layout for time, title, and description */
+ display: grid;
+ grid-template-columns: auto 1fr;
+ grid-template-rows: auto 1fr;
+ gap: 2px 4px;
+ align-items: start;
/* Event types */
&[data-type="meeting"] {
@@ -137,16 +144,66 @@ swp-resize-handle::before {
}
swp-day-columns swp-event-time {
- display: block;
+ grid-column: 1;
+ grid-row: 1;
font-size: 0.875rem;
font-weight: 500;
- margin-bottom: 4px;
+ white-space: nowrap;
}
swp-day-columns swp-event-title {
+ grid-column: 2;
+ grid-row: 1;
+ font-size: 0.875rem;
+ font-weight: 500;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+swp-day-columns swp-event-description {
+ grid-column: 1 / -1;
+ grid-row: 2;
display: block;
font-size: 0.875rem;
+ opacity: 0.8;
line-height: 1.3;
+ overflow: hidden;
+ word-wrap: break-word;
+}
+
+/* Hide description if event is too short (<60px) */
+swp-day-columns swp-event[style*="height: 30px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 31px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 32px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 33px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 34px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 35px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 36px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 37px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 38px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 39px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 40px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 41px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 42px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 43px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 44px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 45px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 46px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 47px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 48px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 49px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 50px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 51px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 52px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 53px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 54px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 55px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 56px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 57px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 58px"] swp-event-description,
+swp-day-columns swp-event[style*="height: 59px"] swp-event-description {
+ display: none;
}
/* Multi-day events */
diff --git a/wwwroot/data/mock-events.json b/wwwroot/data/mock-events.json
index 9c5e552..ed8e4d4 100644
--- a/wwwroot/data/mock-events.json
+++ b/wwwroot/data/mock-events.json
@@ -3251,6 +3251,7 @@
{
"id": "NOV10-001",
"title": "Morgen Standup",
+ "description": "Daily team sync - status updates",
"start": "2025-11-10T05:00:00Z",
"end": "2025-11-10T05:30:00Z",
"type": "meeting",
@@ -3264,6 +3265,7 @@
{
"id": "NOV10-002",
"title": "Sprint Planning",
+ "description": "Plan backlog items and estimate story points",
"start": "2025-11-10T06:00:00Z",
"end": "2025-11-10T07:30:00Z",
"type": "meeting",
@@ -3277,6 +3279,7 @@
{
"id": "NOV10-003",
"title": "Udvikling af ny feature",
+ "description": "Implement user authentication module with OAuth2 support, JWT tokens, refresh token rotation, and secure password hashing using bcrypt. Include comprehensive unit tests and integration tests for all authentication flows.",
"start": "2025-11-10T08:00:00Z",
"end": "2025-11-10T11:00:00Z",
"type": "work",
@@ -3290,6 +3293,7 @@
{
"id": "NOV10-004",
"title": "Frokostmøde med klient",
+ "description": "Discuss project requirements and timeline",
"start": "2025-11-10T08:00:00Z",
"end": "2025-11-10T09:00:00Z",
"type": "meal",
@@ -3316,6 +3320,7 @@
{
"id": "NOV11-001",
"title": "Morgen Standup",
+ "description": "Quick sync on progress and blockers",
"start": "2025-11-11T05:00:00Z",
"end": "2025-11-11T05:30:00Z",
"type": "meeting",
@@ -3329,6 +3334,7 @@
{
"id": "NOV11-002",
"title": "Arkitektur Review",
+ "description": "Review system design and scalability",
"start": "2025-11-11T07:00:00Z",
"end": "2025-11-11T08:30:00Z",
"type": "meeting",
@@ -3342,6 +3348,7 @@
{
"id": "NOV11-003",
"title": "Code Review Session",
+ "description": "Review pull requests and provide feedback",
"start": "2025-11-11T10:00:00Z",
"end": "2025-11-11T11:30:00Z",
"type": "work",
@@ -3355,6 +3362,7 @@
{
"id": "NOV11-004",
"title": "Database Optimering",
+ "description": "Optimize queries and add indexes",
"start": "2025-11-11T13:00:00Z",
"end": "2025-11-11T15:00:00Z",
"type": "work",
@@ -3381,6 +3389,7 @@
{
"id": "NOV12-001",
"title": "Morgen Standup",
+ "description": "Team alignment and daily planning",
"start": "2025-11-12T05:00:00Z",
"end": "2025-11-12T05:30:00Z",
"type": "meeting",
@@ -3394,6 +3403,7 @@
{
"id": "NOV12-002",
"title": "Teknisk Workshop",
+ "description": "Learn new frameworks and best practices",
"start": "2025-11-12T06:00:00Z",
"end": "2025-11-12T08:00:00Z",
"type": "meeting",
@@ -3407,6 +3417,7 @@
{
"id": "NOV12-003",
"title": "API Udvikling",
+ "description": "Build REST endpoints for mobile app including user profile management, push notifications, real-time chat functionality, file upload with image compression, and comprehensive API documentation using OpenAPI specification. Implement rate limiting and caching strategies.",
"start": "2025-11-12T09:00:00Z",
"end": "2025-11-12T12:00:00Z",
"type": "work",
@@ -3420,6 +3431,7 @@
{
"id": "NOV12-004",
"title": "Klient Præsentation",
+ "description": "Demo new features and gather feedback",
"start": "2025-11-12T13:00:00Z",
"end": "2025-11-12T14:30:00Z",
"type": "meeting",
@@ -3433,6 +3445,7 @@
{
"id": "NOV13-001",
"title": "Morgen Standup",
+ "description": "Daily sync and impediment removal",
"start": "2025-11-13T05:00:00Z",
"end": "2025-11-13T05:30:00Z",
"type": "meeting",
@@ -3446,6 +3459,7 @@
{
"id": "NOV13-002",
"title": "Performance Testing",
+ "description": "Load testing and bottleneck analysis",
"start": "2025-11-13T07:00:00Z",
"end": "2025-11-13T09:00:00Z",
"type": "work",
@@ -3459,6 +3473,7 @@
{
"id": "NOV13-003",
"title": "Sikkerhedsgennemgang",
+ "description": "Security audit and vulnerability scan",
"start": "2025-11-13T10:00:00Z",
"end": "2025-11-13T11:30:00Z",
"type": "meeting",
@@ -3472,6 +3487,7 @@
{
"id": "NOV13-004",
"title": "Bug Fixing Session",
+ "description": "Fix critical bugs from production",
"start": "2025-11-13T13:00:00Z",
"end": "2025-11-13T15:00:00Z",
"type": "work",
@@ -3498,6 +3514,7 @@
{
"id": "NOV14-001",
"title": "Morgen Standup",
+ "description": "Sprint wrap-up and final status check",
"start": "2025-11-14T05:00:00Z",
"end": "2025-11-14T05:30:00Z",
"type": "meeting",
@@ -3511,6 +3528,7 @@
{
"id": "NOV14-002",
"title": "Sprint Review",
+ "description": "Demo completed work to stakeholders",
"start": "2025-11-14T06:00:00Z",
"end": "2025-11-14T07:00:00Z",
"type": "meeting",
@@ -3524,6 +3542,7 @@
{
"id": "NOV14-003",
"title": "Retrospektiv",
+ "description": "Reflect on sprint and identify improvements",
"start": "2025-11-14T07:30:00Z",
"end": "2025-11-14T08:30:00Z",
"type": "meeting",
@@ -3537,6 +3556,7 @@
{
"id": "NOV14-004",
"title": "Dokumentation",
+ "description": "Update technical documentation including architecture diagrams, API reference with request/response examples, deployment guides for production and staging environments, troubleshooting section with common issues and solutions, and developer onboarding documentation with setup instructions.",
"start": "2025-11-14T10:00:00Z",
"end": "2025-11-14T12:00:00Z",
"type": "work",
@@ -3550,6 +3570,7 @@
{
"id": "NOV14-005",
"title": "Deployment Planning",
+ "description": "Plan release strategy and rollback",
"start": "2025-11-14T13:00:00Z",
"end": "2025-11-14T14:00:00Z",
"type": "meeting",
@@ -3563,6 +3584,7 @@
{
"id": "NOV15-001",
"title": "Morgen Standup",
+ "description": "New sprint kickoff and goal setting",
"start": "2025-11-15T05:00:00Z",
"end": "2025-11-15T05:30:00Z",
"type": "meeting",
@@ -3576,6 +3598,7 @@
{
"id": "NOV15-002",
"title": "Feature Demo",
+ "description": "Showcase new functionality to team",
"start": "2025-11-15T07:00:00Z",
"end": "2025-11-15T08:00:00Z",
"type": "meeting",
@@ -3589,6 +3612,7 @@
{
"id": "NOV15-003",
"title": "Refactoring Session",
+ "description": "Clean up technical debt and improve code",
"start": "2025-11-15T09:00:00Z",
"end": "2025-11-15T11:00:00Z",
"type": "work",
@@ -3602,6 +3626,7 @@
{
"id": "NOV15-004",
"title": "Klient Opkald",
+ "description": "Weekly status update and next steps",
"start": "2025-11-15T13:00:00Z",
"end": "2025-11-15T14:00:00Z",
"type": "meeting",
@@ -3628,6 +3653,7 @@
{
"id": "NOV16-001",
"title": "Weekend Projekt",
+ "description": "Personal coding project and experimentation",
"start": "2025-11-16T06:00:00Z",
"end": "2025-11-16T10:00:00Z",
"type": "work",
@@ -3641,6 +3667,7 @@
{
"id": "NOV16-002",
"title": "Personlig Udvikling",
+ "description": "Learn new technologies and skills",
"start": "2025-11-16T11:00:00Z",
"end": "2025-11-16T13:00:00Z",
"type": "work",