8.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build and Development Commands
TypeScript Build
- Build:
npm run build- Uses esbuild with NovaDI plugin to bundle towwwroot/js/calendar.js - Watch:
npm run watch- Auto-rebuild on file changes - Clean:
npm run clean- Remove compiled output
Testing
- Run tests:
npm testorvitest- Interactive watch mode - Run once:
npm run test:runorvitest run - Test UI:
npm run test:ui- Visual test interface - Tests use Vitest with jsdom environment (see
vitest.config.ts)
CSS Build
- Build CSS:
npm run css:build- PostCSS with nesting support - Watch CSS:
npm run css:watch- Auto-rebuild CSS on changes - Production CSS:
npm run css:build:prod- Minified with PurgeCSS - Analyze CSS:
npm run css:analyze- CSS statistics and analysis
Server
- Start:
dotnet run- ASP.NET Core Kestrel server onhttp://localhost:8000
Architecture Overview
Core Architectural Pattern
This is a manager-based, event-driven calendar application using pure TypeScript with no UI frameworks. Communication happens exclusively through DOM CustomEvents via a central EventBus.
Key Principles:
- No global state - State lives in managers
- Event-driven - All inter-component communication via CustomEvents (see
CoreEventsconstants) - Dependency Injection - Uses
@novadi/coreDI container - Pure DOM - No React/Vue/Angular, just vanilla TypeScript + DOM manipulation
Dependency Injection Flow
The application initializes in src/index.ts following this sequence:
- CalendarConfig.initialize() - Static config from DOM attributes (
<swp-calendar>) - Container setup - Register all services, managers, renderers, utilities
- Manager initialization - CalendarManager coordinates all other managers
- Deep linking - Handle URL-based event navigation
All dependencies are auto-wired using NovaDI's @inject decorators (configured in build.js).
Event System
EventBus (src/core/EventBus.ts) wraps DOM CustomEvents with debugging/logging:
// Emit
eventBus.emit('view:changed', { view: 'week', date: new Date() });
// Listen
eventBus.on('view:changed', (event: CustomEvent) => {
const { view, date } = event.detail;
});
Core events are defined in src/constants/CoreEvents.ts (~20 essential events organized by category: lifecycle, view, navigation, data, grid, event management, system, filter, rendering).
Manager Architecture
Managers are the core organizational units. Each has a specific responsibility:
Primary Managers:
CalendarManager- Main coordinator, initializes all managersViewManager- Handles view switching (day/week/month)NavigationManager- Prev/next/today navigation, date changesEventManager- Event CRUD operations, selection, lifecycleGridManager- Calendar grid structure and layoutHeaderManager- Date headers and column renderingAllDayManager- All-day event section management
Interaction Managers:
DragDropManager- Event drag-and-drop functionalityResizeHandleManager- Event resize handlesDragHoverManager- Visual feedback during drag operationsEdgeScrollManager- Auto-scroll when dragging near edgesScrollManager- Grid scroll behavior
Support Managers:
ConfigManager- Event-driven config updates (wraps CalendarConfig) and manages CSS custom propertiesEventLayoutCoordinator- Coordinates event positioningEventStackManager- Handles overlapping eventsEventFilterManager- Filter events by criteriaWorkHoursManager- Work hours highlighting
Renderer Architecture
Renderers handle DOM creation and updates (separation of concerns from managers):
EventRenderingService- Main event rendering coordinatorDateEventRenderer/AllDayEventRenderer- Event DOM generationDateHeaderRenderer- Date header renderingDateColumnRenderer- Column structureGridRenderer- Grid structure and time slotsNavigationRenderer- Navigation controls
Core Services
CalendarConfig (src/core/CalendarConfig.ts):
- Static configuration class
- Loads settings from DOM data attributes on
<swp-calendar>element - Provides computed values (hourHeight, snapInterval, totalSlots, etc.)
- ConfigManager wraps it for event-driven updates and automatically syncs CSS custom properties to the DOM
DateService (src/utils/DateService.ts):
- Uses
date-fnsanddate-fns-tzfor date calculations - Default timezone:
Europe/Copenhagen, locale:da-DK
TimeFormatter (src/utils/TimeFormatter.ts):
- Consistent time/date formatting across the app
- Configured via CalendarConfig
PositionUtils (src/utils/PositionUtils.ts):
- Convert between pixels and times
- Snap-to-grid calculations
URLManager (src/utils/URLManager.ts):
- Deep linking to events
- Parses
eventIdfrom URL
Repository Pattern
Event data is accessed through IEventRepository interface:
MockEventRepository- Current implementation using mock data fromwwwroot/data/mock-events.json- Ready for API implementation swap
Code Organization
src/
├── constants/ # CoreEvents and other constants
├── core/ # EventBus, CalendarConfig (core infrastructure)
├── data/ # Data models and utilities
├── elements/ # Custom HTML elements (if any)
├── managers/ # Manager classes (business logic)
├── renderers/ # DOM rendering logic
├── repositories/ # Data access layer (IEventRepository, MockEventRepository)
├── types/ # TypeScript interfaces and types
├── utils/ # Utility functions (DateService, PositionUtils, etc.)
└── index.ts # Application entry point and DI setup
Important Patterns
Adding a New Manager
- Create in
src/managers/YourManager.ts - Use
@injectfor dependencies - Implement optional
initialize()method if needed - Register in
src/index.tsDI container - Listen to events via
eventBus.on()(injected asIEventBus) - Emit events via
eventBus.emit()
Event Naming Convention
Events follow category:action pattern:
view:changed,view:renderednav:date-changed,nav:navigation-completeddata:loaded,data:errorevent:created,event:updated,event:deletedgrid:rendered,grid:clicked
Grid Positioning
Events are positioned using CSS Grid and absolute positioning:
- Time slots are calculated via
CalendarConfig.slotHeightandminuteHeight PositionUtilshandles pixel ↔ time conversions- Snap-to-grid uses
CalendarConfig.getGridSettings().snapInterval
Work Week Configuration
CalendarConfig supports work week presets:
standard- Mon-Fri (default)compressed- Mon-Thumidweek- Wed-Friweekend- Sat-Sunfullweek- Mon-Sun
Change via CalendarConfig.setWorkWeek('preset-id')
Testing
Tests are written using Vitest with jsdom. Setup file: test/setup.ts
Run individual test file:
vitest run path/to/test-file.test.ts
CSS Architecture
CSS is modular and built with PostCSS:
- Source:
wwwroot/css/src/(uses PostCSS nesting) - Output:
wwwroot/css/ - Main file:
calendar.css(currently used)
Planned modular CSS files:
calendar-base-css.css- Variables and base stylescalendar-components-css.css- UI componentscalendar-events-css.css- Event stylingcalendar-layout-css.css- Grid layoutcalendar-popup-css.css- Modals and popups
Debugging
Enable EventBus debug mode (already enabled in src/index.ts):
eventBus.setDebug(true);
Access debug interface in browser console:
window.calendarDebug.eventBus.getEventLog(); // All events
window.calendarDebug.eventManager; // Access EventManager
window.calendarDebug.calendarManager; // Access CalendarManager
Configuration via HTML
Set calendar options via data attributes on <swp-calendar>:
<swp-calendar
data-view="week"
data-week-days="7"
data-snap-interval="15"
data-day-start-hour="6"
data-day-end-hour="22"
data-hour-height="60"
data-fit-to-width="false">
</swp-calendar>