{"id":31804847,"url":"https://github.com/devints47/cal7","last_synced_at":"2025-10-11T02:19:20.095Z","repository":{"id":306619835,"uuid":"1025826549","full_name":"devints47/cal7","owner":"devints47","description":"A zero-configuration React calendar component for displaying Google Calendar events in a responsive weekly view.","archived":false,"fork":false,"pushed_at":"2025-09-15T23:32:57.000Z","size":9088,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-10T04:07:13.391Z","etag":null,"topics":["calendar","calendar-api","calendar-component","calendar-widget","google-calendar","google-calendar-api","google-calendar-integration","nextjs","react"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/cal7","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devints47.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-24T21:40:21.000Z","updated_at":"2025-09-15T23:33:03.000Z","dependencies_parsed_at":"2025-07-26T21:03:33.891Z","dependency_job_id":null,"html_url":"https://github.com/devints47/cal7","commit_stats":null,"previous_names":["devints47/cal7"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/devints47/cal7","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devints47%2Fcal7","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devints47%2Fcal7/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devints47%2Fcal7/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devints47%2Fcal7/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devints47","download_url":"https://codeload.github.com/devints47/cal7/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devints47%2Fcal7/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279005928,"owners_count":26083998,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["calendar","calendar-api","calendar-component","calendar-widget","google-calendar","google-calendar-api","google-calendar-integration","nextjs","react"],"created_at":"2025-10-11T02:19:16.486Z","updated_at":"2025-10-11T02:19:20.088Z","avatar_url":"https://github.com/devints47.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cal7\n\nA zero-configuration React calendar component for displaying Google Calendar events in a responsive weekly view.\n\n## Installation\n\n```bash\nnpm install cal7\n```\n\n## Quick Start\n\n```tsx\nimport { Calendar } from \"cal7\";\nimport \"cal7/styles\";\n\n// Set environment variable: GOOGLE_CALENDAR_API_KEY=your_api_key\n\nexport default function MyApp() {\n  return \u003cCalendar showSubscribeButton={true} /\u003e;\n}\n```\n## Zero‑key ICS Quick Start (Recommended)\n\nUse a public Google Calendar ICS feed on the server, then render the client calendar with events. No Google API key required.\n\n1) Server: fetch the ICS and parse to events\n```tsx\n// app/events/page.tsx (Next.js App Router, Server Component)\nimport { parseICS } from \"cal7\";\nimport \"cal7/styles\"; // one CSS import\n\nasync function getEventsFromICS() {\n  // Replace with your public Google Calendar ICS URL\n  const ICS_URL = \"https://calendar.google.com/calendar/ical/your_calendar_id%40group.calendar.google.com/public/basic.ics\";\n  const res = await fetch(ICS_URL, { next: { revalidate: 300 } }); // cache 5min\n  if (!res.ok) throw new Error(\"Failed to fetch ICS\");\n  const icsText = await res.text();\n  return parseICS(icsText); // returns CalendarEvent[]\n}\n\nexport default async function EventsPage() {\n  const events = await getEventsFromICS();\n  // Pass serializable events to the client\n  return \u003cEventsCalendarClient events={events} /\u003e;\n}\n```\n\n2) Client: render the calendar\n```tsx\n// components/EventsCalendarClient.tsx (\"use client\")\n\"use client\";\n\nimport { CalendarClient } from \"cal7\";\n\nexport default function EventsCalendarClient({ events }: { events: any[] }) {\n  return (\n    \u003cCalendarClient\n      events={events}\n      locale=\"en-US\"\n      timeZone=\"America/New_York\"\n      calendarName=\"Our Events\"\n      showSubscribeButton\n      titleAlignment=\"center\"\n    /\u003e\n  );\n}\n```\n\n3) Theming in a few lines (optional)\n```tsx\n// app/events/page.tsx (wrap client render)\nimport { ThemeProvider, type CalendarTheme } from \"cal7\";\nimport \"cal7/styles\";\n\nconst theme: CalendarTheme = {\n  colors: {\n    primary: \"#059669\",         // brand green\n    today: \"#059669\",\n    todayBackground: \"#D1FAE5\",\n    eventBorder: \"#A7F3D0\",\n  },\n};\n\nexport default async function EventsPage() {\n  const events = await getEventsFromICS();\n  return (\n    \u003cThemeProvider config={{ theme }}\u003e\n      \u003cEventsCalendarClient events={events} /\u003e\n    \u003c/ThemeProvider\u003e\n  );\n}\n```\n\nNotes:\n- parseICS focuses on VEVENT blocks, DATE vs DATETIME, Z vs local, and all‑day detection. Recurrence should be pre‑expanded by your provider (Google does this in ICS).\n- For private calendars or advanced features (attendees, write access), use the API‑key flow described below.\n\n---\n\n## Next.js App Router Recipe (Client + Server)\n\n- Server components: fetch/parse ICS or fetch via the Google API if you need private calendars.\n- Client component: render \u003cCalendarClient /\u003e with the normalized events.\n- Styles: `import \"cal7/styles\"` once (global or server layout), or rely on ThemeProvider tokens to map to CSS variables.\n\n```tsx\n// app/layout.tsx\nimport \"cal7/styles\";\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return \u003chtml\u003e\u003cbody\u003e{children}\u003c/body\u003e\u003c/html\u003e;\n}\n```\n\n---\n\n## Placement and Portals (dropdowns, menus)\n\nDropdown menus can render via a fixed‑position portal to avoid clipping inside modals or containers.\n\nProps (1.2.0):\n- AddToCalendarButton, SubscribeButton:\n  - portalTarget?: HTMLElement | string; defaults to document.body when provided\n  - dropdownPlacement?: \"up\" | \"down\" | \"auto\" (auto chooses based on available space)\n  - offset?: number (px), default 8\n\nExample (subscribe opens upward by default):\n```tsx\n\u003cCalendarClient\n  events={events}\n  showSubscribeButton\n/\u003e\n```\n\nExample (explicit portal to body for add‑to‑calendar in a modal):\n```tsx\nimport { AddToCalendarButton } from \"cal7\";\n\n\u003cAddToCalendarButton\n  event={event}\n  portalTarget=\"body\"\n  dropdownPlacement=\"auto\"\n  offset={10}\n/\u003e\n```\n\n---\n\n## Theming Tokens Reference (excerpt)\n\nCal7 maps theme tokens to CSS variables. You can set tokens via ThemeProvider or override CSS vars globally.\n\nColors (examples):\n- primary, secondary, background, surface, text, textSecondary, textMuted\n- border, borderLight\n- today, todayBackground\n- eventBackground, eventBorder, eventText\n- headerEven, headerOdd, dayEven, dayOdd, dayHover\n\nOther:\n- typography: fontFamily, fontSize.{xs|sm|base|lg|xl|2xl}, fontWeight.{normal|medium|semibold|bold}\n- spacing: { xs, sm, md, lg, xl, 2xl }\n- borderRadius: { none, sm, md, lg, full }\n- shadows: { none, sm, md, lg, xl }\n- zIndex: { dropdown, modal, tooltip }\n\nCSS example:\n```css\n:root {\n  --cal7-color-primary: #059669;\n  --cal7-color-today: #059669;\n  --cal7-color-today-background: #D1FAE5;\n  --cal7-color-event-border: #A7F3D0;\n}\n```\n\n---\n\n## Accessibility\n\n- Roles: dialog, menu, menuitem with aria‑expanded/aria‑controls bound to triggers\n- Modal focus loop (dependency‑free) with Escape and outside‑click dismiss\n- Keyboard navigation: arrows in menus, Tab cycle in modal\n- Respects prefers‑reduced‑motion and high‑contrast\n\n\n## Features\n\n- 🚀 **Zero Configuration**: Just set your API key and go\n- 📱 **Responsive Design**: Adapts from desktop 7-day view to mobile-friendly layout\n- ♿ **Accessibility First**: Full keyboard navigation and screen reader support\n- 🎨 **Customizable Theming**: Extensive theme system with CSS custom properties\n- 🌙 **Dark Mode**: Built-in dark theme with system preference detection\n- 📅 **Add to Calendar**: Device-aware calendar integration (Google, Apple, iCal)\n- 🔒 **Secure**: Server-side API key handling, no client-side exposure\n- ⚡ **Performance**: Built-in caching and optimized rendering\n- 📦 **Zero runtime dependencies** by default; small bundle footprint\n- 🎯 **TypeScript**: Full type safety and IntelliSense support\n\n--------\n\u003cimg width=\"1205\" height=\"601\" alt=\"Screenshot 2025-07-26 at 11 32 54 AM\" src=\"https://github.com/user-attachments/assets/4b2927e5-0a2b-48ec-ad9d-4fc55747107e\" /\u003e\n\n\n## Framework Compatibility\n\nThis package is designed specifically for **React-based frameworks** with the following support levels:\n\n### ✅ Fully Supported\n- **Next.js 13+ (App Router)** - Primary target with full server-side rendering support\n- **Next.js 12+ (Pages Router)** - Full compatibility with getServerSideProps/getStaticProps\n\n### ⚠️ Partial Support  \n- **Create React App / Vite** - Client-side only, requires custom `fetcher` prop for API calls\n- **Remix** - May work with adaptation, but not officially tested\n\n### ❌ Not Compatible\n- **Vue/Nuxt, Svelte/SvelteKit, Angular** - Different framework ecosystems, would need separate packages\n\n**Recommended:** Use with Next.js for the best experience with server-side rendering and secure API key handling.\n\n## Basic Usage\n\n### Server Component (Recommended)\n\n```tsx\nimport { Calendar } from \"cal7\";\n\nexport default function EventsPage() {\n  return \u003cCalendar locale=\"en-US\" timeZone=\"America/New_York\" /\u003e;\n}\n```\n\n### With Theme Provider\n\n```tsx\nimport { Calendar, ThemeProvider } from \"cal7\";\n\nconst customTheme = {\n  colors: {\n    primary: \"#3b82f6\",\n    background: \"#ffffff\",\n    eventBackground: \"#f8fafc\",\n  },\n  typography: {\n    fontFamily: \"Inter, sans-serif\",\n    customFontUrl:\n      \"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700\u0026display=swap\",\n  },\n};\n\nexport default function App() {\n  return (\n    \u003cThemeProvider config={{ theme: customTheme }}\u003e\n      \u003cCalendar /\u003e\n    \u003c/ThemeProvider\u003e\n  );\n}\n```\n\n## Theming \u0026 Customization\n\nCal7 provides extensive theming capabilities through CSS custom properties and a comprehensive theme system.\n\n### Theme Configuration\n\n```tsx\nimport { Calendar, ThemeProvider, type CalendarTheme } from \"cal7\";\n\nconst customTheme: CalendarTheme = {\n  colors: {\n    // Primary colors\n    primary: \"#3b82f6\",\n    secondary: \"#6b7280\",\n    background: \"#ffffff\",\n    surface: \"#f9fafb\",\n\n    // Text colors\n    text: \"#111827\",\n    textSecondary: \"#374151\",\n    textMuted: \"#6b7280\",\n    eventPastText: \"#9ca3af\", // Color for past events\n\n    // Border colors\n    border: \"#e5e7eb\",\n    borderLight: \"#f3f4f6\",\n\n    // State colors\n    today: \"#92400e\",\n    todayBackground: \"#fef3c7\",\n    focus: \"#3b82f6\",\n    hover: \"#f3f4f6\",\n\n    // Day alternating colors\n    dayEven: \"#fafafa\",\n    dayOdd: \"#ffffff\",\n    dayHover: \"#f8fafc\",\n\n    // Header alternating colors\n    headerEven: \"#f3f4f6\",\n    headerOdd: \"#f9fafb\",\n\n    // Event colors\n    eventBackground: \"#ffffff\",\n    eventBorder: \"#e5e7eb\",\n    eventText: \"#111827\",\n  },\n\n  typography: {\n    fontFamily: \"Inter, -apple-system, BlinkMacSystemFont, sans-serif\",\n    customFontUrl:\n      \"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700\u0026display=swap\",\n    fontSize: {\n      xs: \"0.75rem\",\n      sm: \"0.875rem\",\n      base: \"1rem\",\n      lg: \"1.125rem\",\n      xl: \"1.25rem\",\n      \"2xl\": \"1.5rem\",\n    },\n    fontWeight: {\n      normal: 400,\n      medium: 500,\n      semibold: 600,\n      bold: 700,\n    },\n  },\n\n  spacing: {\n    xs: \"0.25rem\",\n    sm: \"0.5rem\",\n    md: \"1rem\",\n    lg: \"1.5rem\",\n    xl: \"2rem\",\n    \"2xl\": \"3rem\",\n  },\n\n  shadows: {\n    calendar:\n      \"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)\",\n    sm: \"0 1px 2px rgba(0, 0, 0, 0.05)\",\n    md: \"0 2px 4px rgba(0, 0, 0, 0.1)\",\n    lg: \"0 4px 6px rgba(0, 0, 0, 0.1)\",\n    xl: \"0 10px 15px rgba(0, 0, 0, 0.1)\",\n  },\n\n  event: {\n    height: \"auto\", // Customizable event section height\n    width: \"100%\", // Customizable event width\n    titleMinHeight: \"2.5rem\", // Minimum height for event titles (2 lines)\n  },\n};\n\nexport default function App() {\n  return (\n    \u003cThemeProvider config={{ theme: customTheme }}\u003e\n      \u003cCalendar /\u003e\n    \u003c/ThemeProvider\u003e\n  );\n}\n```\n\n### Dark Mode\n\n```tsx\nimport { ThemeProvider } from \"cal7\";\n\nexport default function App() {\n  return (\n    \u003cThemeProvider\n      config={{\n        mode: \"dark\", // 'light' | 'dark' | 'system'\n        theme: customLightTheme,\n        darkTheme: customDarkTheme,\n      }}\n    \u003e\n      \u003cCalendar /\u003e\n    \u003c/ThemeProvider\u003e\n  );\n}\n```\n\n### CSS Custom Properties\n\nYou can also customize the calendar using CSS custom properties:\n\n```css\n:root {\n  /* Colors */\n  --cal7-color-primary: #3b82f6;\n  --cal7-color-background: #ffffff;\n  --cal7-color-surface: #f9fafb;\n  --cal7-color-text: #111827;\n  --cal7-color-border: #e5e7eb;\n\n  /* Day alternating colors */\n  --cal7-color-day-even: #fafafa;\n  --cal7-color-day-odd: #ffffff;\n  --cal7-color-day-hover: #f8fafc;\n\n  /* Header alternating colors */\n  --cal7-color-header-even: #f3f4f6;\n  --cal7-color-header-odd: #f9fafb;\n\n  /* Past events */\n  --cal7-color-event-past-text: #9ca3af;\n\n  /* Typography */\n  --cal7-font-family: \"Inter\", sans-serif;\n  --cal7-font-size-base: 1rem;\n  --cal7-font-weight-bold: 700;\n\n  /* Event customization */\n  --cal7-event-height: auto;\n  --cal7-event-width: 100%;\n  --cal7-event-title-min-height: 2.5rem;\n\n  /* Shadows */\n  --cal7-shadow-calendar: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n\n  /* Spacing */\n  --cal7-spacing-sm: 0.5rem;\n  --cal7-spacing-md: 1rem;\n  --cal7-spacing-lg: 1.5rem;\n}\n```\n\n### Custom Font Integration\n\n```tsx\nconst themeWithCustomFont = {\n  typography: {\n    fontFamily: \"Poppins, sans-serif\",\n    customFontUrl:\n      \"https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700\u0026display=swap\",\n  },\n};\n```\n\n## Component Props\n\n### Calendar\n\n| Prop                   | Type                     | Default     | Description                                               |\n| ---------------------- | ------------------------ | ----------- | --------------------------------------------------------- |\n| `locale`               | `string`                 | `'en-US'`   | Locale for date/time formatting                           |\n| `timeZone`             | `string`                 | `'UTC'`     | Timezone for event display                                |\n| `revalidate`           | `number`                 | `300`       | Cache revalidation time in seconds                        |\n| `className`            | `string`                 | `''`        | Additional CSS classes                                    |\n| `theme`                | `CalendarTheme`          | `undefined` | Custom theme configuration                                |\n| `darkTheme`            | `CalendarTheme`          | `undefined` | Custom dark theme configuration                           |\n| `mode`                 | `ThemeMode`              | `'light'`   | Theme mode: 'light', 'dark', or 'system'                 |\n| `classPrefix`          | `string`                 | `'cal7'`    | CSS class prefix for custom styling                       |\n| `showSubscribeButton`  | `boolean`                | `false`     | Show \"Subscribe to Calendar!\" button with .ics download   |\n| `fetcher`              | `() =\u003e Promise\u003cEvent[]\u003e` | `undefined` | Custom data fetcher function                              |\n| `onError`              | `(error: Error) =\u003e void` | `undefined` | Error handler callback                                    |\n\n### ThemeProvider\n\n| Prop                 | Type                            | Default            | Description               |\n| -------------------- | ------------------------------- | ------------------ | ------------------------- |\n| `config.theme`       | `CalendarTheme`                 | `defaultTheme`     | Light theme configuration |\n| `config.darkTheme`   | `CalendarTheme`                 | `defaultDarkTheme` | Dark theme configuration  |\n| `config.mode`        | `'light' \\| 'dark' \\| 'system'` | `'light'`          | Theme mode                |\n| `config.classPrefix` | `string`                        | `'cal7'`           | CSS class prefix          |\n\n## Styling Features\n\n### Enhanced Visual Design\n\n- **Drop Shadow**: Entire calendar component has a subtle drop shadow\n- **Alternating Colors**: Days and headers alternate background colors for better visual separation\n- **Smooth Animations**: Hover effects with scale and smooth transitions\n- **Past Event Styling**: Past events are automatically greyed out using theme-appropriate colors\n\n### Event Card Enhancements\n\n- **Clock Icons**: Time displays include clock icons\n- **Start/End Times**: Shows both start and end times (e.g., \"8:00AM to 10:00PM\")\n- **Bold Titles**: Event titles are bold and have increased font size\n- **Minimum Height**: Event titles have a minimum 2-line height by default\n- **Location Icons**: SVG location icons instead of emoji pins\n- **Customizable Dimensions**: Event height and width can be customized via theme\n\n### Interactive Features\n\n- **Clickable Links**: Email addresses and URLs in event descriptions are automatically clickable\n- **Map Integration**: Event locations are clickable and open in device-appropriate map apps\n- **Add to Calendar**: Event modal dates are clickable with add-to-calendar functionality\n- **Themed Buttons**: Add-to-calendar buttons match the selected theme (no gradients)\n\n### Subscribe to Calendar Button\n\nWhen enabled with `showSubscribeButton={true}`, displays a prominent \"Subscribe to Calendar!\" button that provides:\n\n- **Full Calendar Subscription**: Users can subscribe to the entire calendar feed via URL\n- **Download .ics File**: Users can download all calendar events as a local .ics file\n- **Upward-Opening Menu**: Dropdown menu opens upward to avoid being cut off\n- **Theme Integration**: Button styling matches your current theme with orange gradient\n- **Desktop/Mobile Friendly**: Works across all devices and calendar applications\n\n### Navigation Improvements\n\n- **Current Week Indicator**: Shows \"Current Week\" badge when viewing the current week\n- **Themed Borders**: Themed border between week selector and calendar grid\n- **Date Format**: Week selector shows dates in \"Jul 20 - 26, 2025\" format\n- **Button Layout**: Navigation arrows positioned left and right of \"Today\" button\n\n## Environment Setup\n\nSet your Google Calendar API key as an environment variable:\n\n```bash\n# .env.local\nGOOGLE_CALENDAR_API_KEY=your_api_key_here\n```\n\n## TypeScript Support\n\nCal7 is built with TypeScript and provides full type definitions:\n\n```tsx\nimport type { CalendarTheme, CalendarEvent, ThemeConfig } from \"cal7\";\n\nconst theme: CalendarTheme = {\n  colors: {\n    primary: \"#3b82f6\",\n    // ... other theme properties with full IntelliSense\n  },\n};\n```\n\n## Accessibility\n\n- **Keyboard Navigation**: Full keyboard support with arrow keys, Enter, Space, and Escape\n- **Screen Reader Support**: Comprehensive ARIA labels and live region announcements\n- **Focus Management**: Proper focus trapping in modals and logical tab order\n- **High Contrast**: Supports high contrast mode preferences\n- **Reduced Motion**: Respects user's reduced motion preferences\n\n## Browser Support\n\n- Chrome 90+\n- Firefox 88+\n- Safari 14+\n- Edge 90+\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevints47%2Fcal7","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevints47%2Fcal7","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevints47%2Fcal7/lists"}