@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.
- package/LICENSE +21 -0
- package/README.md +406 -0
- package/custom-elements.json +4443 -0
- package/dist/components/Context.d.ts +9 -0
- package/dist/components/Context.d.ts.map +1 -0
- package/dist/components/Day.d.ts +11 -0
- package/dist/components/Day.d.ts.map +1 -0
- package/dist/components/Entry.d.ts +43 -0
- package/dist/components/Entry.d.ts.map +1 -0
- package/dist/components/Header.d.ts +16 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Menu.d.ts +28 -0
- package/dist/components/Menu.d.ts.map +1 -0
- package/dist/components/Month.d.ts +21 -0
- package/dist/components/Month.d.ts.map +1 -0
- package/dist/components/Week.d.ts +36 -0
- package/dist/components/Week.d.ts.map +1 -0
- package/dist/components/Year.d.ts +20 -0
- package/dist/components/Year.d.ts.map +1 -0
- package/dist/generated/locale-codes.d.ts +14 -0
- package/dist/generated/locale-codes.d.ts.map +1 -0
- package/dist/generated/locales/ar.d.ts +33 -0
- package/dist/generated/locales/ar.d.ts.map +1 -0
- package/dist/generated/locales/bn.d.ts +33 -0
- package/dist/generated/locales/bn.d.ts.map +1 -0
- package/dist/generated/locales/de-DE.d.ts +33 -0
- package/dist/generated/locales/de-DE.d.ts.map +1 -0
- package/dist/generated/locales/de.d.ts +33 -0
- package/dist/generated/locales/de.d.ts.map +1 -0
- package/dist/generated/locales/es.d.ts +33 -0
- package/dist/generated/locales/es.d.ts.map +1 -0
- package/dist/generated/locales/fr.d.ts +33 -0
- package/dist/generated/locales/fr.d.ts.map +1 -0
- package/dist/generated/locales/hi.d.ts +33 -0
- package/dist/generated/locales/hi.d.ts.map +1 -0
- package/dist/generated/locales/id.d.ts +33 -0
- package/dist/generated/locales/id.d.ts.map +1 -0
- package/dist/generated/locales/it.d.ts +33 -0
- package/dist/generated/locales/it.d.ts.map +1 -0
- package/dist/generated/locales/ja.d.ts +33 -0
- package/dist/generated/locales/ja.d.ts.map +1 -0
- package/dist/generated/locales/ko.d.ts +33 -0
- package/dist/generated/locales/ko.d.ts.map +1 -0
- package/dist/generated/locales/nl.d.ts +33 -0
- package/dist/generated/locales/nl.d.ts.map +1 -0
- package/dist/generated/locales/pl.d.ts +33 -0
- package/dist/generated/locales/pl.d.ts.map +1 -0
- package/dist/generated/locales/pt.d.ts +33 -0
- package/dist/generated/locales/pt.d.ts.map +1 -0
- package/dist/generated/locales/ru.d.ts +33 -0
- package/dist/generated/locales/ru.d.ts.map +1 -0
- package/dist/generated/locales/th.d.ts +33 -0
- package/dist/generated/locales/th.d.ts.map +1 -0
- package/dist/generated/locales/tr.d.ts +33 -0
- package/dist/generated/locales/tr.d.ts.map +1 -0
- package/dist/generated/locales/uk.d.ts +33 -0
- package/dist/generated/locales/uk.d.ts.map +1 -0
- package/dist/generated/locales/vi.d.ts +33 -0
- package/dist/generated/locales/vi.d.ts.map +1 -0
- package/dist/generated/locales/zh-Hans.d.ts +33 -0
- package/dist/generated/locales/zh-Hans.d.ts.map +1 -0
- package/dist/kalendus.js +1806 -0
- package/dist/kalendus.js.map +1 -0
- package/dist/lib/DirectionalCalendarDateCalculator.d.ts +29 -0
- package/dist/lib/DirectionalCalendarDateCalculator.d.ts.map +1 -0
- package/dist/lib/LayoutCalculator.d.ts +47 -0
- package/dist/lib/LayoutCalculator.d.ts.map +1 -0
- package/dist/lib/SlotManager.d.ts +130 -0
- package/dist/lib/SlotManager.d.ts.map +1 -0
- package/dist/lib/ViewStateController.d.ts +22 -0
- package/dist/lib/ViewStateController.d.ts.map +1 -0
- package/dist/lib/allDayLayout.d.ts +24 -0
- package/dist/lib/allDayLayout.d.ts.map +1 -0
- package/dist/lib/catchError.d.ts +2 -0
- package/dist/lib/catchError.d.ts.map +1 -0
- package/dist/lib/getColorTextWithContrast.d.ts +8 -0
- package/dist/lib/getColorTextWithContrast.d.ts.map +1 -0
- package/dist/lib/getOverlappingEntitiesIndices.d.ts +8 -0
- package/dist/lib/getOverlappingEntitiesIndices.d.ts.map +1 -0
- package/dist/lib/getSortedGradingsByIndex.d.ts +2 -0
- package/dist/lib/getSortedGradingsByIndex.d.ts.map +1 -0
- package/dist/lib/localization.d.ts +34 -0
- package/dist/lib/localization.d.ts.map +1 -0
- package/dist/lib/messages.d.ts +4 -0
- package/dist/lib/messages.d.ts.map +1 -0
- package/dist/lib/partitionOverlappingIntervals.d.ts +6 -0
- package/dist/lib/partitionOverlappingIntervals.d.ts.map +1 -0
- package/dist/lib/weekDisplayContext.d.ts +31 -0
- package/dist/lib/weekDisplayContext.d.ts.map +1 -0
- package/dist/lib/weekStartHelper.d.ts +57 -0
- package/dist/lib/weekStartHelper.d.ts.map +1 -0
- package/dist/lms-calendar.d.ts +166 -0
- package/dist/lms-calendar.d.ts.map +1 -0
- 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.
|