@jpahd/kalendus 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +406 -0
  3. package/custom-elements.json +4443 -0
  4. package/dist/components/Context.d.ts +9 -0
  5. package/dist/components/Context.d.ts.map +1 -0
  6. package/dist/components/Day.d.ts +11 -0
  7. package/dist/components/Day.d.ts.map +1 -0
  8. package/dist/components/Entry.d.ts +43 -0
  9. package/dist/components/Entry.d.ts.map +1 -0
  10. package/dist/components/Header.d.ts +16 -0
  11. package/dist/components/Header.d.ts.map +1 -0
  12. package/dist/components/Menu.d.ts +28 -0
  13. package/dist/components/Menu.d.ts.map +1 -0
  14. package/dist/components/Month.d.ts +21 -0
  15. package/dist/components/Month.d.ts.map +1 -0
  16. package/dist/components/Week.d.ts +36 -0
  17. package/dist/components/Week.d.ts.map +1 -0
  18. package/dist/components/Year.d.ts +20 -0
  19. package/dist/components/Year.d.ts.map +1 -0
  20. package/dist/generated/locale-codes.d.ts +14 -0
  21. package/dist/generated/locale-codes.d.ts.map +1 -0
  22. package/dist/generated/locales/ar.d.ts +33 -0
  23. package/dist/generated/locales/ar.d.ts.map +1 -0
  24. package/dist/generated/locales/bn.d.ts +33 -0
  25. package/dist/generated/locales/bn.d.ts.map +1 -0
  26. package/dist/generated/locales/de-DE.d.ts +33 -0
  27. package/dist/generated/locales/de-DE.d.ts.map +1 -0
  28. package/dist/generated/locales/de.d.ts +33 -0
  29. package/dist/generated/locales/de.d.ts.map +1 -0
  30. package/dist/generated/locales/es.d.ts +33 -0
  31. package/dist/generated/locales/es.d.ts.map +1 -0
  32. package/dist/generated/locales/fr.d.ts +33 -0
  33. package/dist/generated/locales/fr.d.ts.map +1 -0
  34. package/dist/generated/locales/hi.d.ts +33 -0
  35. package/dist/generated/locales/hi.d.ts.map +1 -0
  36. package/dist/generated/locales/id.d.ts +33 -0
  37. package/dist/generated/locales/id.d.ts.map +1 -0
  38. package/dist/generated/locales/it.d.ts +33 -0
  39. package/dist/generated/locales/it.d.ts.map +1 -0
  40. package/dist/generated/locales/ja.d.ts +33 -0
  41. package/dist/generated/locales/ja.d.ts.map +1 -0
  42. package/dist/generated/locales/ko.d.ts +33 -0
  43. package/dist/generated/locales/ko.d.ts.map +1 -0
  44. package/dist/generated/locales/nl.d.ts +33 -0
  45. package/dist/generated/locales/nl.d.ts.map +1 -0
  46. package/dist/generated/locales/pl.d.ts +33 -0
  47. package/dist/generated/locales/pl.d.ts.map +1 -0
  48. package/dist/generated/locales/pt.d.ts +33 -0
  49. package/dist/generated/locales/pt.d.ts.map +1 -0
  50. package/dist/generated/locales/ru.d.ts +33 -0
  51. package/dist/generated/locales/ru.d.ts.map +1 -0
  52. package/dist/generated/locales/th.d.ts +33 -0
  53. package/dist/generated/locales/th.d.ts.map +1 -0
  54. package/dist/generated/locales/tr.d.ts +33 -0
  55. package/dist/generated/locales/tr.d.ts.map +1 -0
  56. package/dist/generated/locales/uk.d.ts +33 -0
  57. package/dist/generated/locales/uk.d.ts.map +1 -0
  58. package/dist/generated/locales/vi.d.ts +33 -0
  59. package/dist/generated/locales/vi.d.ts.map +1 -0
  60. package/dist/generated/locales/zh-Hans.d.ts +33 -0
  61. package/dist/generated/locales/zh-Hans.d.ts.map +1 -0
  62. package/dist/kalendus.js +1806 -0
  63. package/dist/kalendus.js.map +1 -0
  64. package/dist/lib/DirectionalCalendarDateCalculator.d.ts +29 -0
  65. package/dist/lib/DirectionalCalendarDateCalculator.d.ts.map +1 -0
  66. package/dist/lib/LayoutCalculator.d.ts +47 -0
  67. package/dist/lib/LayoutCalculator.d.ts.map +1 -0
  68. package/dist/lib/SlotManager.d.ts +130 -0
  69. package/dist/lib/SlotManager.d.ts.map +1 -0
  70. package/dist/lib/ViewStateController.d.ts +22 -0
  71. package/dist/lib/ViewStateController.d.ts.map +1 -0
  72. package/dist/lib/allDayLayout.d.ts +24 -0
  73. package/dist/lib/allDayLayout.d.ts.map +1 -0
  74. package/dist/lib/catchError.d.ts +2 -0
  75. package/dist/lib/catchError.d.ts.map +1 -0
  76. package/dist/lib/getColorTextWithContrast.d.ts +8 -0
  77. package/dist/lib/getColorTextWithContrast.d.ts.map +1 -0
  78. package/dist/lib/getOverlappingEntitiesIndices.d.ts +8 -0
  79. package/dist/lib/getOverlappingEntitiesIndices.d.ts.map +1 -0
  80. package/dist/lib/getSortedGradingsByIndex.d.ts +2 -0
  81. package/dist/lib/getSortedGradingsByIndex.d.ts.map +1 -0
  82. package/dist/lib/localization.d.ts +34 -0
  83. package/dist/lib/localization.d.ts.map +1 -0
  84. package/dist/lib/messages.d.ts +4 -0
  85. package/dist/lib/messages.d.ts.map +1 -0
  86. package/dist/lib/partitionOverlappingIntervals.d.ts +6 -0
  87. package/dist/lib/partitionOverlappingIntervals.d.ts.map +1 -0
  88. package/dist/lib/weekDisplayContext.d.ts +31 -0
  89. package/dist/lib/weekDisplayContext.d.ts.map +1 -0
  90. package/dist/lib/weekStartHelper.d.ts +57 -0
  91. package/dist/lib/weekStartHelper.d.ts.map +1 -0
  92. package/dist/lms-calendar.d.ts +166 -0
  93. package/dist/lms-calendar.d.ts.map +1 -0
  94. package/package.json +118 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Paul Derscheid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,406 @@
1
+ # kalendus
2
+
3
+ A sophisticated, responsive calendar web component built with Lit 3.x and TypeScript. Designed for Library Management Systems and other applications requiring advanced calendar functionality with support for overlapping events, multiple view modes, per-instance localization, and extensive customization.
4
+
5
+ ## Features
6
+
7
+ ### Multiple View Modes
8
+
9
+ - **Month View**: Traditional monthly calendar with color-coded event indicators
10
+ - **Week View**: 7-day view with hourly time slots, condensed windows (e.g., 3-day peeks) driven by CSS tokens, and pixel-perfect alignment
11
+ - **Day View**: Single-day view with detailed hourly scheduling
12
+ - **Year View**: 12 mini-month grids with density indicators (dot, heatmap, or count) and configurable drill targets for instant navigation
13
+
14
+ ### Advanced Event Handling
15
+
16
+ - **Smart Overlapping**: Cascading layout with progressive transparency preserves event visibility
17
+ - **Duration-Based Positioning**: Events positioned precisely by start time and duration via `LayoutCalculator`
18
+ - **Multi-Day Events**: Seamless spanning across multiple days with first/middle/last-day visual styling
19
+ - **All-Day Events**: Dedicated all-day section with row allocation via `allDayLayout`
20
+ - **Responsive Density**: Automatic layout optimization based on event count and viewport size
21
+
22
+ ### Modern Design
23
+
24
+ - **Responsive Design**: Mobile-first approach with adaptive layouts and container queries
25
+ - **Color Dot Indicators**: Scalable month view with color-coded event dots
26
+ - **Accessibility**: Full keyboard navigation, ARIA labels, focus trapping, and screen reader support
27
+ - **CSS Custom Properties**: 80+ design tokens for comprehensive theming
28
+
29
+ ### Per-Instance Localization
30
+
31
+ - **Independent Locale Per Instance**: Multiple calendars on the same page can each display a different locale
32
+ - **21 Built-in Locales**: English, German, Spanish, French, Hindi, Bengali, Russian, Indonesian, Korean, Turkish, Vietnamese, Italian, Thai, Polish, Ukrainian, Dutch, Japanese, Portuguese, Arabic, Chinese (Simplified), and German (DE)
33
+ - **Localized UI Strings**: All buttons, labels, and messages translated per instance
34
+ - **Localized Date Formatting**: Weekday names, month names, and date formats use the instance's locale
35
+ - **Configurable Week Start**: `firstDayOfWeek` property supports Monday (ISO), Sunday (US/JP), Saturday (AR), or any day
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pnpm add @jpahd/kalendus
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ See `docs/integration-guide.md` for end-to-end recipes covering vanilla HTML, React, Lit, theming tokens, and analytics hooks. A few quick snippets are included below.
46
+
47
+ ## Documentation Map
48
+
49
+ | Audience | Document | Highlights |
50
+ | ---------------------- | ------------------------------------------------------------ | -------------------------------------------------- |
51
+ | Integrators | [Integration Guide](docs/integration-guide.md) | Framework recipes, theming tokens, analytics hooks |
52
+ | Application Developers | [Library Usage](docs/library-usage.md) | API surface, data contracts, DOM events |
53
+ | Component Contributors | [Developer Guide](docs/developer-guide.md) | Internal architecture, debugging tips |
54
+ | Rendering Internals | [Rendering Calculations](docs/rendering-calculations.md) | Grid math, condensed weeks, density modes |
55
+ | Design Systems | [Design Token Refactoring](docs/design-token-refactoring.md) | Token audit and proposed hierarchy |
56
+ | Backend/API | [API Server Guide](docs/api-server.md) | REST + SSE backend, database + adapters |
57
+
58
+ ### Basic Usage
59
+
60
+ ```html
61
+ <lms-calendar
62
+ .heading="My Calendar"
63
+ .activeDate=${{ day: 15, month: 3, year: 2024 }}
64
+ .entries=${myEvents}
65
+ .color="#1976d2"
66
+ ></lms-calendar>
67
+ ```
68
+
69
+ ### Per-Instance Locale
70
+
71
+ By default, every calendar auto-detects its locale from the page's `<html lang="...">` attribute. You can override individual instances with the `locale` property:
72
+
73
+ ```html
74
+ <!-- Auto-detects from <html lang="de"> — no config needed -->
75
+ <lms-calendar .entries="${events}"></lms-calendar>
76
+
77
+ <!-- Explicitly override to Japanese with Sunday-first weeks -->
78
+ <lms-calendar .entries="${events}" locale="ja" .firstDayOfWeek="${0}"></lms-calendar>
79
+
80
+ <!-- Multiple locales on the same page - each fully independent -->
81
+ <lms-calendar locale="es"></lms-calendar>
82
+ <lms-calendar locale="fr"></lms-calendar>
83
+ <lms-calendar locale="zh-Hans"></lms-calendar>
84
+ ```
85
+
86
+ ### Event Structure
87
+
88
+ ```typescript
89
+ interface CalendarEntry {
90
+ heading: string;
91
+ content: string;
92
+ color: string;
93
+ isContinuation: boolean;
94
+ date: {
95
+ start: { day: number; month: number; year: number };
96
+ end: { day: number; month: number; year: number };
97
+ };
98
+ time: {
99
+ start: { hour: number; minute: number };
100
+ end: { hour: number; minute: number };
101
+ };
102
+ }
103
+ ```
104
+
105
+ ### Example Events
106
+
107
+ ```typescript
108
+ const events = [
109
+ {
110
+ heading: 'Team Meeting',
111
+ content: 'Weekly team sync',
112
+ color: '#1976d2',
113
+ isContinuation: false,
114
+ date: {
115
+ start: { day: 15, month: 3, year: 2024 },
116
+ end: { day: 15, month: 3, year: 2024 },
117
+ },
118
+ time: {
119
+ start: { hour: 9, minute: 0 },
120
+ end: { hour: 10, minute: 30 },
121
+ },
122
+ },
123
+ {
124
+ heading: 'Project Sprint',
125
+ content: 'Development sprint',
126
+ color: '#2e7d32',
127
+ isContinuation: false,
128
+ date: {
129
+ start: { day: 20, month: 3, year: 2024 },
130
+ end: { day: 22, month: 3, year: 2024 },
131
+ },
132
+ time: {
133
+ start: { hour: 8, minute: 0 },
134
+ end: { hour: 17, minute: 0 },
135
+ },
136
+ },
137
+ ];
138
+ ```
139
+
140
+ ### Year View Controls
141
+
142
+ The year overview makes it easy to hop between distant dates. Two properties tune how it behaves:
143
+
144
+ ```html
145
+ <lms-calendar
146
+ year-drill-target="day"
147
+ year-density-mode="heatmap"
148
+ .entries="${events}"
149
+ ></lms-calendar>
150
+ ```
151
+
152
+ - `year-drill-target` (`day` \| `month`): picking a day can either open the specific day or simply focus its month.
153
+ - `year-density-mode` (`dot` \| `heatmap` \| `count`): swap between subtle dots, tonal heatmaps, or explicit counts for per-day density.
154
+
155
+ ## Properties
156
+
157
+ | Property | Type | Default | Description |
158
+ | ----------------- | ------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------- |
159
+ | `heading` | `string` | `undefined` | Calendar title displayed in header |
160
+ | `activeDate` | `CalendarDate` | Current date | Initially displayed date |
161
+ | `entries` | `CalendarEntry[]` | `[]` | Array of calendar events |
162
+ | `color` | `string` | `'#000000'` | Primary theme color |
163
+ | `locale` | `string` | `document.documentElement.lang \|\| 'en'` | Locale for UI strings and date formatting (auto-detected from page, overridable per-instance) |
164
+ | `firstDayOfWeek` | `0-6` | `1` | First day of the week (0=Sun, 1=Mon, ..., 6=Sat) |
165
+ | `yearDrillTarget` | `'day' \| 'month'` | `'month'` | Determines whether a year-view click opens day or month view |
166
+ | `yearDensityMode` | `'dot' \| 'heatmap' \| 'count'` | `'dot'` | Chooses how per-day entry density is visualized in year view |
167
+
168
+ ### Supported Locales
169
+
170
+ | Code | Language | Default Week Start |
171
+ | --------- | -------------------- | ------------------ |
172
+ | `en` | English | Sunday |
173
+ | `de` | German | Monday |
174
+ | `de-DE` | German (Germany) | Monday |
175
+ | `es` | Spanish | Monday |
176
+ | `fr` | French | Monday |
177
+ | `hi` | Hindi | Sunday |
178
+ | `bn` | Bengali | Sunday |
179
+ | `ru` | Russian | Monday |
180
+ | `id` | Indonesian | Sunday |
181
+ | `ko` | Korean | Sunday |
182
+ | `tr` | Turkish | Monday |
183
+ | `vi` | Vietnamese | Monday |
184
+ | `it` | Italian | Monday |
185
+ | `th` | Thai | Sunday |
186
+ | `pl` | Polish | Monday |
187
+ | `uk` | Ukrainian | Monday |
188
+ | `nl` | Dutch | Monday |
189
+ | `ja` | Japanese | Sunday |
190
+ | `pt` | Portuguese | Sunday |
191
+ | `ar` | Arabic | Saturday |
192
+ | `zh-Hans` | Chinese (Simplified) | Sunday |
193
+
194
+ ## Styling & Theming
195
+
196
+ The calendar uses CSS custom properties for comprehensive theming:
197
+
198
+ ### Primary Colors
199
+
200
+ ```css
201
+ lms-calendar {
202
+ --primary-color: #1976d2;
203
+ --background-color: #ffffff;
204
+ --separator-light: rgba(0, 0, 0, 0.1);
205
+ --separator-dark: rgba(0, 0, 0, 0.7);
206
+ }
207
+ ```
208
+
209
+ ### Entry Styling
210
+
211
+ ```css
212
+ lms-calendar {
213
+ --entry-border-radius: 6px;
214
+ --entry-font-size: 0.75rem;
215
+ --entry-padding: 0.15em 0.25em;
216
+ --entry-min-height: 1.2em;
217
+ }
218
+ ```
219
+
220
+ ### Layout & Spacing
221
+
222
+ ```css
223
+ lms-calendar {
224
+ --header-height: 4em;
225
+ --day-padding: 0.5em;
226
+ --day-gap: 1px;
227
+ --time-column-width: 4em;
228
+ }
229
+ ```
230
+
231
+ ### Week Column Controls
232
+
233
+ ```css
234
+ lms-calendar {
235
+ --week-day-count: 7; /* full-width columns */
236
+ --week-mobile-day-count: 3; /* columns when condensed */
237
+ --week-mobile-breakpoint: 768px;
238
+ }
239
+ ```
240
+
241
+ `computeWeekDisplayContext` reads these tokens at runtime to decide how many day columns to render. Below the breakpoint the component centers a smaller window (e.g., three days) around the active date and exposes peek navigation so users can slide through the full week without sacrificing readability on narrow screens.
242
+
243
+ ### Year View Tokens
244
+
245
+ ```css
246
+ lms-calendar {
247
+ --year-grid-columns: 3;
248
+ --year-grid-columns-tablet: 2;
249
+ --year-grid-columns-mobile: 1;
250
+ --year-month-label-font-size: 0.875em;
251
+ --year-day-font-size: 0.7em;
252
+ --year-cell-size: 1.8em;
253
+ --year-dot-color: var(--indicator-color, var(--primary-color));
254
+ --year-heatmap-1: rgba(30, 144, 255, 0.15);
255
+ --year-heatmap-2: rgba(30, 144, 255, 0.35);
256
+ --year-heatmap-3: rgba(30, 144, 255, 0.55);
257
+ --year-heatmap-4: rgba(30, 144, 255, 0.75);
258
+ }
259
+ ```
260
+
261
+ Adjust these tokens to align the overview grid with your design system (e.g., forcing a single-column mobile layout or brand-specific heatmap shades).
262
+
263
+ ### Week View Tokens
264
+
265
+ ```css
266
+ lms-calendar {
267
+ --week-day-count: 7; /* columns at full width (1-7) */
268
+ --week-mobile-day-count: 3; /* columns below breakpoint (1-7) */
269
+ --week-mobile-breakpoint: 768px; /* width threshold */
270
+ }
271
+ ```
272
+
273
+ On narrow viewports the week view automatically condenses to show fewer day columns centered on the active date, with subtle peek indicators at the edges. Values are clamped to the 1-7 range.
274
+
275
+ ## Architecture
276
+
277
+ ### Component Structure
278
+
279
+ ```
280
+ src/
281
+ ├── lms-calendar.ts # Main calendar component & global types
282
+ ├── components/
283
+ │ ├── Header.ts # Navigation and view controls
284
+ │ ├── Month.ts # Monthly calendar grid
285
+ │ ├── Week.ts # Weekly time-based view
286
+ │ ├── Day.ts # Daily detailed view
287
+ │ ├── Year.ts # Year overview with drill targets and density modes
288
+ │ ├── Entry.ts # Individual event component
289
+ │ ├── Context.ts # Weekday header row (month view)
290
+ │ └── Menu.ts # Event detail popover with ICS export
291
+ ├── lib/
292
+ │ ├── messages.ts # Per-instance i18n via direct template lookup
293
+ │ ├── localization.ts # Locale-parameterized date/time formatting
294
+ │ ├── ViewStateController.ts # Per-instance view mode & date state
295
+ │ ├── LayoutCalculator.ts # Overlap detection & box layout
296
+ │ ├── SlotManager.ts # Slot naming & CSS position generation
297
+ │ ├── allDayLayout.ts # All-day event row allocation
298
+ │ ├── weekStartHelper.ts # Week start offset & locale mapping
299
+ │ ├── DirectionalCalendarDateCalculator.ts
300
+ │ ├── getOverlappingEntitiesIndices.ts
301
+ │ ├── getSortedGradingsByIndex.ts
302
+ │ ├── partitionOverlappingIntervals.ts
303
+ │ └── getColorTextWithContrast.ts
304
+ └── generated/
305
+ ├── locale-codes.ts # Source & target locale definitions
306
+ └── locales/ # Generated translation templates (hash ID → string)
307
+ ├── ar.ts, bn.ts, de.ts, de-DE.ts, es.ts, fr.ts, hi.ts
308
+ ├── id.ts, it.ts, ja.ts, ko.ts, nl.ts, pl.ts, pt.ts
309
+ ├── ru.ts, th.ts, tr.ts, uk.ts, vi.ts
310
+ └── zh-Hans.ts
311
+ ```
312
+
313
+ ### Key Technologies
314
+
315
+ - **Lit 3.x**: Modern web components with reactive properties and decorators
316
+ - **TypeScript**: Type-safe development with strict mode
317
+ - **Luxon**: Robust date/time manipulation and locale-aware formatting
318
+ - **Remeda**: Functional programming utilities for data transformations
319
+ - **ts-pattern**: Pattern matching for cleaner conditional logic
320
+ - **ts-ics**: ICS calendar file generation for event export
321
+ - **@lit/localize** (build-time only): Template extraction and generation via `lit-localize` CLI
322
+
323
+ ### Design Patterns
324
+
325
+ - **Per-instance state** via `ViewStateController` (Lit `ReactiveController`)
326
+ - **Per-instance localization** via direct template hash lookups (bypasses `@lit/localize` singleton)
327
+ - **Event bubbling** for component communication (`switchdate`, `switchview`, `expand`, `open-menu`)
328
+ - **CSS custom properties** for theming (80+ tokens)
329
+ - **Slot-based composition** for entry placement in view grids
330
+ - **Container queries** for responsive header layout
331
+
332
+ ## Testing
333
+
334
+ ```bash
335
+ # Run unit tests
336
+ pnpm test
337
+
338
+ # Run tests in watch mode
339
+ pnpm test:watch
340
+
341
+ # Run Storybook tests
342
+ pnpm test-storybook
343
+ ```
344
+
345
+ ### Test Categories
346
+
347
+ - **Unit tests** (`test/unit/lib/`): Pure function tests with Mocha + Chai
348
+ - **Component tests** (`test/unit/components/`): Lit component tests with @open-wc/testing
349
+ - **Visual tests**: Storybook stories for all views, locales, and edge cases
350
+
351
+ ## Storybook
352
+
353
+ Explore all features and variations in Storybook:
354
+
355
+ ```bash
356
+ pnpm storybook
357
+ ```
358
+
359
+ ### Available Stories
360
+
361
+ - **Default**: Basic calendar with sample events
362
+ - **Locale stories**: Individual stories for each supported locale (German, French, Spanish, Japanese, etc.)
363
+ - **LocaleShowcase**: 19 calendars on one page, each with a different locale
364
+ - **WeekStartComparison**: Side-by-side Monday-first vs Sunday-first
365
+ - **Heavy Event Load**: Stress testing with 200+ events
366
+ - **Overlapping Events**: Extreme overlap scenarios
367
+ - **Mobile View**: Responsive mobile experience
368
+ - **Custom Theming**: Theme variations and customization
369
+
370
+ ## Development
371
+
372
+ ```bash
373
+ pnpm install
374
+ pnpm storybook # Start Storybook dev server
375
+ pnpm build # Build with Vite
376
+ pnpm test # Run tests
377
+ pnpm lint # Run lit-analyzer + oxlint
378
+ pnpm format # Format with oxfmt
379
+ ```
380
+
381
+ See `docs/developer-guide.md` for internal architecture notes, troubleshooting checklists, and tips on extending condensed week layouts or localization.
382
+
383
+ ### API Server (optional)
384
+
385
+ The repository includes `@jpahd/kalendus-server`, a Hono + SQLite backend with REST/SSE endpoints.
386
+
387
+ ```bash
388
+ # From repo root
389
+ pnpm --filter @jpahd/kalendus-server db:migrate
390
+ pnpm --filter @jpahd/kalendus-server db:seed
391
+ pnpm --filter @jpahd/kalendus-server dev
392
+ ```
393
+
394
+ Configuration, endpoint overview, and adapter usage live in `docs/api-server.md`.
395
+
396
+ ### Adding a New Locale
397
+
398
+ 1. Add the locale code to `lit-localize.json` target locales
399
+ 2. Run `pnpm exec lit-localize extract` to generate the template file
400
+ 3. Translate strings in `src/generated/locales/<locale>.ts`
401
+ 4. Add the import and entry in `src/lib/messages.ts` (`allTemplates` map)
402
+ 5. Optionally add a `LUXON_LOCALE_MAP` entry in `localization.ts` if the locale code differs from Intl/Luxon conventions
403
+
404
+ ## License
405
+
406
+ MIT License - see LICENSE file for details.