npm package: @lequyettien/angular-calendar
Description: Modern Angular Calendar Component with TailwindCSS and multiple event dots support
Author: Le Quyet Tien
Latest version: 1.0.1

# Angular Calendar

A modern, lightweight calendar component for Angular with TailwindCSS styling and multiple event dot support.

## ✨ Features

- ✅ **Standalone Component** - Built with Angular's standalone API for easy integration
- ✅ **Signals** - Leverages Angular Signals for reactive state management
- ✅ **TailwindCSS Styling** - Beautiful, customizable design with TailwindCSS
- ✅ **Multiple Event Dots** - Display multiple events on the same day with different colors
- ✅ **Internationalization** - Support for English, Spanish, and Vietnamese
- ✅ **Responsive Design** - Works seamlessly across all screen sizes
- ✅ **Accessible** - Follows WCAG accessibility standards
- ✅ **Fully Typed** - Complete TypeScript support with strict mode
- ✅ **Zero Dependencies** - No external dependencies like moment.js or lodash
- ✅ **Tree-shakeable** - Optimized bundle size with modern build tools

## 📦 Installation

### NPM

```bash
npm install @lequyettien/angular-calendar
```

### Yarn

```bash
yarn add @lequyettien/angular-calendar
```

### Prerequisites

This package requires:
- Angular 18.0.0 or higher
- TailwindCSS 3.0.0 or higher

### TailwindCSS Setup

If you don't have TailwindCSS installed in your Angular project:

```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
```

Configure `tailwind.config.js`:

```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{html,ts}",
    "./node_modules/@lequyettien/angular-calendar/**/*.{html,ts,js,mjs}"
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```

Add to `src/styles.css`:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

## 🚀 Quick Start

### Basic Usage

Import the component in your Angular standalone component or module:

```typescript
import { Component } from '@angular/core';
import { CalendarComponent, DateObj, SingularDate } from '@lequyettien/angular-calendar';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CalendarComponent],
  template: `
    <div class="container mx-auto p-4">
      <h1 class="text-2xl font-bold mb-4">My Calendar</h1>
      <ng-calendar
        [events]="events"
        [lang]="'en'"
        (onDaySelect)="handleDaySelect($event)"
        (onMonthSelect)="handleMonthChange($event)">
      </ng-calendar>
    </div>
  `
})
export class AppComponent {
  // Define events with colors
  events: SingularDate[] = [
    { year: 2026, month: 1, date: 5, color: '#3b82f6' },   // Blue
    { year: 2026, month: 1, date: 5, color: '#ef4444' },   // Red (same day)
    { year: 2026, month: 1, date: 10, color: '#10b981' },  // Green
    { year: 2026, month: 1, date: 15, color: '#f59e0b' },  // Orange
    { year: 2026, month: 1, date: 15, color: '#8b5cf6' },  // Purple
    { year: 2026, month: 1, date: 15, color: '#ec4899' },  // Pink
    { year: 2026, month: 1, date: 20, color: '#14b8a6' },  // Teal
  ];

  handleDaySelect(day: DateObj) {
    console.log('Selected day:', day);
    console.log('Events on this day:', day.eventDots);
  }

  handleMonthChange(event: { year: number; month: number }) {
    console.log('Month changed:', event);
  }
}
```

### Using with NgModule

```typescript
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CalendarComponent } from '@lequyettien/angular-calendar';

@NgModule({
  imports: [
    BrowserModule,
    CalendarComponent  // Import standalone component
  ],
  // ...
})
export class AppModule { }
```

## 📖 API Reference

### Component Inputs

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `events` | `SingularDate[]` | `[]` | Array of events to display on the calendar |
| `lang` | `string` | `'en'` | Language for month/day names (`'en'`, `'es'`, `'vi'`) |

### Component Outputs

| Event | Payload | Description |
|-------|---------|-------------|
| `onDaySelect` | `DateObj` | Emitted when a user selects a day |
| `onMonthSelect` | `MonthChangeEvent` | Emitted when the displayed month changes |

## 🎨 Customization

### Custom Styling

You can customize the calendar appearance using TailwindCSS utility classes:

```typescript
// Example: Change primary color from blue to purple
<ng-calendar 
  class="[&_.bg-blue-500]:bg-purple-500 [&_.ring-blue-500]:ring-purple-500">
</ng-calendar>
```

## 💡 Advanced Examples

### Loading Events from an API

```typescript
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { CalendarComponent, SingularDate, DateObj } from '@lequyettien/angular-calendar';

@Component({
  selector: 'app-event-calendar',
  standalone: true,
  imports: [CalendarComponent, HttpClientModule],
  template: `
    <ng-calendar
      [events]="events"
      [lang]="'en'"
      (onDaySelect)="showEventDetails($event)">
    </ng-calendar>
  `
})
export class EventCalendarComponent implements OnInit {
  events: SingularDate[] = [];

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.loadEvents();
  }

  loadEvents() {
    this.http.get<any[]>('/api/events').subscribe(apiEvents => {
      this.events = apiEvents.map(event => ({
        year: new Date(event.date).getFullYear(),
        month: new Date(event.date).getMonth(),
        date: new Date(event.date).getDate(),
        color: event.type === 'meeting' ? '#3b82f6' : '#10b981'
      }));
    });
  }

  showEventDetails(day: DateObj) {
    if (day.hasEvent) {
      console.log(`Found ${day.eventDots?.length} events on this day`);
      // Show modal or navigate to event details
    }
  }
}
```

### Multiple Calendars Side by Side

```typescript
import { Component } from '@angular/core';
import { CalendarComponent, SingularDate } from '@lequyettien/angular-calendar';

@Component({
  selector: 'app-multi-calendar',
  standalone: true,
  imports: [CalendarComponent],
  template: `
    <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
      <div>
        <h2 class="text-lg font-semibold mb-2">Personal</h2>
        <ng-calendar [events]="personalEvents" [lang]="'en'"></ng-calendar>
      </div>
      <div>
        <h2 class="text-lg font-semibold mb-2">Work</h2>
        <ng-calendar [events]="workEvents" [lang]="'en'"></ng-calendar>
      </div>
    </div>
  `
})
export class MultiCalendarComponent {
  personalEvents: SingularDate[] = [
    { year: 2026, month: 1, date: 14, color: '#ec4899' }, // Valentine's Day
    { year: 2026, month: 1, date: 20, color: '#10b981' }, // Birthday
  ];
  
  workEvents: SingularDate[] = [
    { year: 2026, month: 1, date: 5, color: '#3b82f6' },  // Team Meeting
    { year: 2026, month: 1, date: 15, color: '#ef4444' }, // Project Deadline
  ];
}
```

## 📝 TypeScript Interfaces

```typescript
/**
 * Represents a single day in the calendar grid
 */
interface DateObj {
  year: number;
  month: number;
  date: number;
  isThisMonth: boolean;
  isToday?: boolean;
  isSelect?: boolean;
  hasEvent?: boolean;
  eventDots?: string[]; // Array of color hex codes for multiple events
}

/**
 * Represents a single event on the calendar
 */
interface SingularDate {
  year: number;
  month: number; // 0-11 (JavaScript Date convention)
  date: number;  // 1-31
  color?: string; // Hex color code (e.g., '#3b82f6')
}

/**
 * Event emitted when the displayed month changes
 */
interface MonthChangeEvent {
  year: number;
  month: number; // 0-11
}
```

## 🌐 Internationalization

The calendar supports multiple languages out of the box:

- **English** (`en`) - Default
- **Spanish** (`es`)
- **Vietnamese** (`vi`)

To add a new language, you can extend the `weekHeads` and `monthNames` objects in your component or create a custom pipe.

## 🎯 Key Features Explained

### Multiple Event Dots

Display multiple events on the same day with different colors:

```typescript
events: SingularDate[] = [
  { year: 2026, month: 1, date: 15, color: '#3b82f6' },  // Blue dot
  { year: 2026, month: 1, date: 15, color: '#ef4444' },  // Red dot (same day)
  { year: 2026, month: 1, date: 15, color: '#10b981' },  // Green dot (same day)
];
```

Up to 3 dots will be displayed on a single day. If there are more events, they will still be tracked in the `eventDots` array.

### Angular Signals

The component uses Angular Signals for reactive state management, providing better performance and cleaner code:

```typescript
displayYear = signal(this.currentYear);
displayMonth = signal(this.currentMonth);
weekHead = computed(() => this.weekHeads[this.lang] || this.weekHeads['en']);
```

### Zero Dependencies

Unlike many calendar libraries, this component has **no runtime dependencies**. It uses native JavaScript `Date` APIs instead of libraries like moment.js or date-fns, resulting in a smaller bundle size.

## 🏗️ Project Structure

```
@lequyettien/angular-calendar/
├── src/
│   ├── calendar.component.ts      # Main calendar component
│   ├── calendar.component.html    # Calendar template
│   ├── calendar.component.css     # Calendar styles
│   ├── calendar.types.ts          # TypeScript interfaces
│   ├── month-name.pipe.ts         # Month name transformation pipe
│   ├── calendar-example.component.ts  # Example usage component
│   └── index.ts                   # Public API
├── dist/                          # Built package
├── README.md
├── package.json
└── ng-package.json
```

## 🔧 Development

### Prerequisites

- Node.js 18.x or higher
- Angular CLI 18.x or higher

### Build

```bash
npm run build
```

### Pack for testing

```bash
npm run pack
```

This will create a `.tgz` file in the `dist` folder that you can install locally for testing.

## 🤝 Contributing

Contributions are welcome! Please follow these steps:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## 📄 License

MIT License - see the [LICENSE](LICENSE) file for details.

## 🙏 Acknowledgments

Built with modern Angular features and TailwindCSS for a clean, performant calendar solution.

## 📞 Support

- **Issues**: [GitHub Issues](https://github.com/LeQuyetTien/angular-calendar/issues)
- **Discussions**: [GitHub Discussions](https://github.com/LeQuyetTien/angular-calendar/discussions)

## 🚀 Roadmap

- [ ] Drag and drop support for events
- [ ] Week view and day view modes
- [ ] Custom event templates
- [ ] Date range selection
- [ ] Keyboard navigation improvements
- [ ] Dark mode support
- [ ] More language support

---

**Made with ❤️ using Angular and TailwindCSS**