npm.io
4.0.92 • Published 5d ago

@getmicdrop/venue-calendar

Licence
MIT
Version
4.0.92
Deps
6
Size
14.0 MB
Vulns
0
Weekly
1.6K

@getmicdrop/venue-calendar

A beautiful, customizable calendar component built with Svelte for displaying comedy events. Perfect for comedy clubs, venues, and event organizers who want to showcase their upcoming shows.

Features

Three View Modes: List, Gallery, and Calendar views Beautiful UI: Modern, responsive design built with Tailwind CSS Mobile-Friendly: Swipe gestures, touch-optimized, responsive design Easy Integration: Works with React, Vue, vanilla JS, and more One script tag: Self-hosted bundle — paste one <script>, no build step Styles included: The bundle injects its own CSS — no separate stylesheet to link Auto-Mount: Automatically finds and mounts to designated containers Customizable: Configure views, navigation, and more Dark Mode: Built-in light, dark, and high-contrast themes Accessible: ARIA labels, keyboard navigation, screen reader support Event Status: Visual badges for "On Sale", "Selling Fast", "Sold Out"

Installation

Add one <script> tag pointing at the Micdrop-hosted bundle. The package is private (not on npm/jsDelivr) — it is delivered from get-micdrop.com:

<script
  defer
  src="https://get-micdrop.com/embed/venue-calendar.iife.js"
></script>
  • No stylesheet to link. The bundle injects its own CSS at runtime, so a plain page with just this <script> renders fully styled.
  • Use defer (or async) so the bundle never blocks page parse. It is ~310 KB gzipped.
  • Serve your page over HTTPS. Checkout stores a Secure cart cookie, which Safari drops on non-secure (http://) pages.

Heads-up: the exact hosted URL is being finalized (Micdrop ticket MIC-1130). Confirm the address with Micdrop before going live.

The import { ... } from '@getmicdrop/venue-calendar' examples further down are for Micdrop-internal apps that build with a bundler and have registry access to the private package. Public sites (comedy clubs, etc.) use the <script> tag above — not npm install.

Quick Start

Method 1: Auto-Mount (Easiest)

Simply add a div with the class micdrop-calendar-container and the calendar will automatically mount:

<!DOCTYPE html>
<html>
  <head>
    <title>My Comedy Club</title>
    <!-- Preload the bundle while the page parses. defer keeps the
       <script> non-blocking; preload starts the fetch earlier. -->
    <link
      rel="preload"
      as="script"
      href="https://get-micdrop.com/embed/venue-calendar.iife.js"
    />
    <script
      defer
      src="https://get-micdrop.com/embed/venue-calendar.iife.js"
    ></script>
  </head>
  <body>
    <!-- Calendar auto-mounts here. Use data-organization-id to show all of an
       organization's shows, or data-venue-id for a single venue. -->
    <div
      class="micdrop-calendar-container"
      data-organization-id="your-organization-id"
      data-view="calendar"
      data-show-view-options="true"
      data-show-month-switcher="true"
      data-locale="en-US"
    ></div>
  </body>
</html>
Method 2: Web Component

Use the custom <micdrop-calendar> element:

<!DOCTYPE html>
<html>
  <head>
    <title>My Comedy Club</title>
    <script
      defer
      src="https://get-micdrop.com/embed/venue-calendar.iife.js"
    ></script>
  </head>
  <body>
    <!-- Web Component -->
    <micdrop-calendar
      venue-id="your-venue-id"
      view="calendar"
      show-view-options="true"
      show-month-switcher="true"
      locale="en-US"
    >
    </micdrop-calendar>
  </body>
</html>
Method 3: JavaScript API

For more control, use the JavaScript API:

<!DOCTYPE html>
<html>
  <head>
    <title>My Comedy Club</title>
  </head>
  <body>
    <div id="my-calendar"></div>

    <!-- Load the bundle, then call the global it exposes. -->
    <script
      defer
      src="https://get-micdrop.com/embed/venue-calendar.iife.js"
    ></script>
    <script>
      window.addEventListener('load', function () {
        window.VenueCalendar.initVenueCalendar({
          target: '#my-calendar',
          organizationId: 'your-organization-id',
          view: 'calendar',
          showViewOptions: true,
          showMonthSwitcher: true,
        });
      });
    </script>
  </body>
</html>

Framework Integration

React
import React, { useEffect, useRef } from 'react';
import { initVenueCalendar, unmount } from '@getmicdrop/venue-calendar';

function VenueCalendarComponent({ venueId, view = 'calendar' }) {
  const calendarRef = useRef(null);
  const instanceRef = useRef(null);

  useEffect(() => {
    if (!calendarRef.current) return;
    instanceRef.current = initVenueCalendar({
      target: calendarRef.current,
      venueId,
      view,
      events: [],
      showViewOptions: true,
      showMonthSwitcher: true,
    });

    return () => {
      // Svelte 5 — components mounted via `mount()` are destroyed via
      // the `unmount` helper, not `.$destroy()` (that was Svelte 4).
      if (instanceRef.current) {
        try {
          unmount(instanceRef.current);
        } catch {}
        instanceRef.current = null;
      }
    };
  }, [venueId, view]);

  return <div ref={calendarRef}></div>;
}

export default VenueCalendarComponent;
Error reporting and runtime config

Wire any errors caught by the widget into your existing monitoring:

import { configureVenueCalendar } from '@getmicdrop/venue-calendar';

configureVenueCalendar({
  onError: (err, { source }) => {
    Sentry.captureException(err, { tags: { source, micdrop: true } });
  },
  // Optional overrides for self-hosted backends or regional failover.
  // apiBaseUrl: 'https://api.eu.micdrop.com',
  // apiTimeout: 15000,
  // apiRetries: 2,
});

For ad-hoc support diagnostics, the widget exposes its version on window:

window.__MICDROP_CALENDAR__.version; // e.g. "3.6.23"

Usage in React App:

import React, { useState } from 'react';
import VenueCalendarComponent from './VenueCalendarComponent';

function App() {
  const [venueId, setVenueId] = useState('comedy-club-123');
  const [view, setView] = useState('calendar');

  return (
    <div style={{ padding: '20px' }}>
      <h1>Event Viewer</h1>

      <div style={{ marginBottom: '20px' }}>
        <label>Venue ID:</label>
        <input
          type="text"
          value={venueId}
          onChange={e => setVenueId(e.target.value)}
        />
      </div>

      <div style={{ marginBottom: '20px' }}>
        <label>Select View:</label>
        <label>
          <input
            type="radio"
            value="list"
            checked={view === 'list'}
            onChange={e => setView(e.target.value)}
          />
          List
        </label>
        <label>
          <input
            type="radio"
            value="gallery"
            checked={view === 'gallery'}
            onChange={e => setView(e.target.value)}
          />
          Gallery
        </label>
        <label>
          <input
            type="radio"
            value="calendar"
            checked={view === 'calendar'}
            onChange={e => setView(e.target.value)}
          />
          Calendar
        </label>
      </div>

      <VenueCalendarComponent venueId={venueId} view={view} />
    </div>
  );
}

export default App;
Vue 3
<template>
  <div ref="calendarContainer"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { initVenueCalendar } from '@getmicdrop/venue-calendar';

const props = defineProps({
  venueId: String,
  view: {
    type: String,
    default: 'calendar',
  },
});

const calendarContainer = ref(null);
let calendarInstance = null;

onMounted(() => {
  calendarInstance = initVenueCalendar({
    target: calendarContainer.value,
    venueId: props.venueId,
    view: props.view,
    events: [],
    showViewOptions: true,
    showMonthSwitcher: true,
  });
});

onUnmounted(() => {
  if (calendarInstance && calendarInstance.$destroy) {
    calendarInstance.$destroy();
  }
});

watch(
  () => props.venueId,
  newId => {
    if (calendarInstance) {
      calendarInstance.$destroy();
      calendarInstance = initVenueCalendar({
        target: calendarContainer.value,
        venueId: newId,
        view: props.view,
        events: [],
        showViewOptions: true,
        showMonthSwitcher: true,
      });
    }
  }
);
</script>
Svelte
<script>
  import { VenueCalendar } from '@getmicdrop/venue-calendar';
  import { Calendar, Grid, List } from 'carbon-icons-svelte';
  import { writable } from 'svelte/store';

  let venueId = 'your-venue-id';
  let currentMonth = writable(new Date().getUTCMonth());
  let currentYear = writable(new Date().getUTCFullYear());

  function handleNext() {
    currentMonth.update(m => m + 1);
  }

  function handlePrev() {
    currentMonth.update(m => m - 1);
  }
</script>

<VenueCalendar
  showViewOptions={[
    { id: 0, text: 'List view', icon: List },
    { id: 1, text: 'Gallery view', icon: Grid },
    { id: 2, text: 'Calendar view', icon: Calendar },
  ]}
  showMonthSwitcher={true}
  events={[]}
  {currentMonth}
  {currentYear}
  {handleNext}
  {handlePrev}
  on:eventClick={e => console.log('Event clicked:', e.detail)}
/>
Angular
import {
  Component,
  OnInit,
  OnDestroy,
  ElementRef,
  ViewChild,
} from '@angular/core';
import { initVenueCalendar } from '@getmicdrop/venue-calendar';

@Component({
  selector: 'app-venue-calendar',
  template: '<div #calendarContainer></div>',
})
export class VenueCalendarComponent implements OnInit, OnDestroy {
  @ViewChild('calendarContainer', { static: true })
  calendarContainer!: ElementRef;
  private calendarInstance: any;

  ngOnInit() {
    this.calendarInstance = initVenueCalendar({
      target: this.calendarContainer.nativeElement,
      venueId: 'your-venue-id',
      view: 'calendar',
      events: [],
      showViewOptions: true,
      showMonthSwitcher: true,
    });
  }

  ngOnDestroy() {
    if (this.calendarInstance && this.calendarInstance.$destroy) {
      this.calendarInstance.$destroy();
    }
  }
}

Configuration Options

Data Attributes (for auto-mount)
Attribute Type Default Description
data-venue-id string '' The venue ID to fetch events for
data-view string 'calendar' Initial view: 'list', 'gallery', or 'calendar'
data-show-view-options boolean true Show view switcher buttons
data-show-month-switcher boolean true Show month navigation controls
JavaScript API Options
initVenueCalendar({
  target: '.my-calendar', // CSS selector or HTMLElement (required)
  venueId: 'venue-123', // Venue ID (optional)
  view: 'calendar', // 'list', 'gallery', or 'calendar' (default: 'calendar')
  events: [], // Array of event objects (default: [])
  showViewOptions: true, // Show view switcher (default: true)
  showMonthSwitcher: true, // Show month navigation (default: true)
});
Event Object Structure
{
  id: 'event-123',
  name: 'Comedy Night',
  date: '2024-10-25T20:00:00Z',
  image: 'https://example.com/image.jpg',
  status: 'On Sale',
  timeline: '8:00 PM - 10:00 PM',
  // ... other fields
}

Views

Calendar View

The default view showing events in a monthly calendar grid. Perfect for venues with regular shows.

List View

A vertical list layout showing all upcoming events with details. Great for mobile experiences.

A grid layout displaying event posters in a gallery format. Ideal for showcasing event imagery.

WordPress Integration

For WordPress sites, you can add this to your page/post HTML:

<div
  class="micdrop-calendar-container"
  data-venue-id="your-venue-id"
  data-view="calendar"
></div>

<script src="https://get-micdrop.com/embed/venue-calendar.iife.js"></script>

Or add the script to your theme's footer and use the div anywhere in your content.

Styling

The calendar comes with built-in styles using Tailwind CSS. If you need to customize the appearance, you can override the CSS classes or add your own styles.

/* Example: Custom styling */
.micdrop-calendar-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

Theming

The calendar supports comprehensive theming via CSS custom properties and JavaScript utilities.

Using CSS Custom Properties

Override the default theme by setting CSS custom properties:

/* Custom brand colors */
.micdrop-calendar-container {
  --Brand-Primary: 270 76% 60%; /* Purple */
  --Text-Primary: 0 0% 10%;
  --BG-Primary: 0 0% 100%;
}

/* Dark mode */
.dark .micdrop-calendar-container,
[data-theme='dark'] .micdrop-calendar-container {
  --Brand-Primary: 270 76% 70%;
  --Text-Primary: 0 0% 95%;
  --BG-Primary: 0 0% 10%;
}
Available CSS Variables
Variable Description Default (Light)
--Brand-Primary Primary brand color 217 91% 60% (Blue)
--Text-Primary Main text color 0 0% 0%
--Text-Secondary Secondary text 0 0% 40%
--BG-Primary Main background 0 0% 100%
--BG-Secondary Secondary background 0 0% 98%
--Stroke-Primary Border colors 0 0% 80%
--Status-OnSale "On Sale" badge 217 91% 60%
--Status-SellingFast "Selling Fast" badge 38 92% 50%
--Status-SoldOut "Sold Out" badge 0 84% 60%
--Today-BG Today's date background 217 91% 97%
--Focus-Ring Keyboard focus ring 217 91% 60%
Using JavaScript Theme Utilities
import {
  applyTheme,
  themes,
  generateThemeCSS,
} from '@getmicdrop/venue-calendar';

// Apply a preset theme
applyTheme(themes.dark);

// Apply to a specific container
const container = document.querySelector('.micdrop-calendar-container');
applyTheme(themes.dark, container);

// Create a custom theme
const myTheme = {
  brandPrimary: '270 76% 60%', // Purple
  textPrimary: '0 0% 10%',
  bgPrimary: '0 0% 100%',
  statusOnSale: '142 71% 45%', // Green for on sale
};
applyTheme(myTheme);

// Generate CSS string for embedding
const cssString = generateThemeCSS(myTheme);
console.log(cssString);
// Output: :root { --Brand-Primary: 270 76% 60%; ... }
Preset Themes

Three themes are included out of the box:

import { themes } from '@getmicdrop/venue-calendar';

// Light theme (default)
applyTheme(themes.light);

// Dark theme
applyTheme(themes.dark);

// High contrast (accessibility)
applyTheme(themes.highContrast);
Automatic Dark Mode

The calendar automatically respects the user's system preference:

/* Automatically applied when user prefers dark mode */
@media (prefers-color-scheme: dark) {
  /* Dark theme variables are applied */
}

You can also manually toggle dark mode:

<!-- Add 'dark' class to enable dark theme -->
<div class="dark">
  <div class="micdrop-calendar-container" data-venue-id="123"></div>
</div>

<!-- Or use data-theme attribute -->
<div data-theme="dark">
  <div class="micdrop-calendar-container" data-venue-id="123"></div>
</div>

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)
  • Mobile browsers (iOS Safari, Chrome Mobile)

Development

Building the Package
# Install dependencies
npm install

# Build the library
npm run build:lib

# Development mode (SvelteKit app)
npm run dev

# Preview production build
npm run preview
Project Structure
venue-calendar/
├── src/
│   ├── components/         # Svelte components
│   │   ├── Calendar/
│   │   ├── CalendarContainer/
│   │   └── Button/
│   ├── lib/               # Library entry points
│   │   ├── VenueCalendar.js
│   │   └── web-component.js
│   └── routes/            # SvelteKit routes (for dev)
├── dist/                  # Built package (generated)
├── package.json
├── vite.config.lib.js     # Library build config
└── README.md
Lockfile policy

package-lock.json is the single canonical lockfile — CI and the publish workflow install with npm ci. Do not commit yarn.lock or pnpm-lock.yaml (both gitignored). Local dev machines may use pnpm for the svelte-components symlink workflow, but dependency changes must land in package-lock.json via npm.

API Reference

initVenueCalendar(options)

Initialize a calendar instance.

Parameters:

  • options (Object): Configuration options

Returns: Svelte component instance

Example:

const calendar = initVenueCalendar({
  target: '#calendar',
  venueId: 'venue-123',
  view: 'calendar',
});
autoMount()

Automatically mount calendars to all elements with class micdrop-calendar-container.

Example:

import { autoMount } from '@getmicdrop/venue-calendar';
autoMount();
Component Events

The calendar component emits events that you can listen to:

const calendar = initVenueCalendar({
  target: '#calendar',
  // ... other options
});

// Listen to component events (if using Svelte component directly)
calendar.$on('eventClick', event => {
  console.log('Event clicked:', event.detail);
});

Troubleshooting

Calendar not appearing
  1. Check the script is loaded: Open browser console and verify no errors
  2. Verify container exists: Make sure the target element exists in the DOM
  3. Check data attributes: Ensure attributes are correctly formatted with data- prefix
Styles not applying
  1. CSS not loaded: The styles are bundled in the JS file and auto-injected — no separate stylesheet needed
  2. CSS conflicts: Check if other styles are overriding the calendar styles
  3. Bundle didn't load: Confirm the <script src> points at the Micdrop-hosted bundle and returns 200 (not 404)
Events not showing
  1. Check event data format: Ensure events match the expected structure
  2. Date format: Use ISO 8601 format for dates (YYYY-MM-DDTHH:mm:ssZ)
  3. Venue ID: Verify the venue ID is correct

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT MicDrop

Support

For issues, questions, or feature requests, please visit: https://github.com/get-micdrop/venue-calendar/issues


Made with by the MicDrop team

Keywords