WIP on master

This commit is contained in:
Janus C. H. Knudsen 2025-11-03 14:54:57 +01:00
parent b6ab1ff50e
commit 80aaab46f2
25 changed files with 6291 additions and 927 deletions

237
CLAUDE.md Normal file
View file

@ -0,0 +1,237 @@
# 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 to `wwwroot/js/calendar.js`
- **Watch:** `npm run watch` - Auto-rebuild on file changes
- **Clean:** `npm run clean` - Remove compiled output
### Testing
- **Run tests:** `npm test` or `vitest` - Interactive watch mode
- **Run once:** `npm run test:run` or `vitest 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 on `http://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 `CoreEvents` constants)
- **Dependency Injection** - Uses `@novadi/core` DI 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:
1. **CalendarConfig.initialize()** - Static config from DOM attributes (`<swp-calendar>`)
2. **Container setup** - Register all services, managers, renderers, utilities
3. **Manager initialization** - CalendarManager coordinates all other managers
4. **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:
```typescript
// 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 managers
- `ViewManager` - Handles view switching (day/week/month)
- `NavigationManager` - Prev/next/today navigation, date changes
- `EventManager` - Event CRUD operations, selection, lifecycle
- `GridManager` - Calendar grid structure and layout
- `HeaderManager` - Date headers and column rendering
- `AllDayManager` - All-day event section management
**Interaction Managers:**
- `DragDropManager` - Event drag-and-drop functionality
- `ResizeHandleManager` - Event resize handles
- `DragHoverManager` - Visual feedback during drag operations
- `EdgeScrollManager` - Auto-scroll when dragging near edges
- `ScrollManager` - Grid scroll behavior
**Support Managers:**
- `ConfigManager` - Event-driven config updates (wraps CalendarConfig) and manages CSS custom properties
- `EventLayoutCoordinator` - Coordinates event positioning
- `EventStackManager` - Handles overlapping events
- `EventFilterManager` - Filter events by criteria
- `WorkHoursManager` - Work hours highlighting
### Renderer Architecture
Renderers handle DOM creation and updates (separation of concerns from managers):
- `EventRenderingService` - Main event rendering coordinator
- `DateEventRenderer` / `AllDayEventRenderer` - Event DOM generation
- `DateHeaderRenderer` - Date header rendering
- `DateColumnRenderer` - Column structure
- `GridRenderer` - Grid structure and time slots
- `NavigationRenderer` - 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-fns` and `date-fns-tz` for 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 `eventId` from URL
### Repository Pattern
Event data is accessed through `IEventRepository` interface:
- `MockEventRepository` - Current implementation using mock data from `wwwroot/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
1. Create in `src/managers/YourManager.ts`
2. Use `@inject` for dependencies
3. Implement optional `initialize()` method if needed
4. Register in `src/index.ts` DI container
5. Listen to events via `eventBus.on()` (injected as `IEventBus`)
6. Emit events via `eventBus.emit()`
### Event Naming Convention
Events follow `category:action` pattern:
- `view:changed`, `view:rendered`
- `nav:date-changed`, `nav:navigation-completed`
- `data:loaded`, `data:error`
- `event:created`, `event:updated`, `event:deleted`
- `grid:rendered`, `grid:clicked`
### Grid Positioning
Events are positioned using CSS Grid and absolute positioning:
- Time slots are calculated via `CalendarConfig.slotHeight` and `minuteHeight`
- `PositionUtils` handles pixel ↔ time conversions
- Snap-to-grid uses `CalendarConfig.getGridSettings().snapInterval`
### Work Week Configuration
CalendarConfig supports work week presets:
- `standard` - Mon-Fri (default)
- `compressed` - Mon-Thu
- `midweek` - Wed-Fri
- `weekend` - Sat-Sun
- `fullweek` - 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:
```bash
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 styles
- `calendar-components-css.css` - UI components
- `calendar-events-css.css` - Event styling
- `calendar-layout-css.css` - Grid layout
- `calendar-popup-css.css` - Modals and popups
## Debugging
Enable EventBus debug mode (already enabled in `src/index.ts`):
```typescript
eventBus.setDebug(true);
```
Access debug interface in browser console:
```javascript
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>`:
```html
<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>
```