UNPKG

react-prayer-widget

Version:

Embeddable prayer times widget components for React applications

761 lines (598 loc) 29 kB
# React Prayer Widget Embeddable prayer times widget components for React applications. Perfect for adding Islamic prayer times to headers, sidebars, or dedicated sections of your website. ## Table of Contents - [Installation](#installation) - [Prerequisites](#prerequisites) - [Next.js Project Setup](#nextjs-project-setup) - [Quick Start](#quick-start) - [Components](#components) - [Settings & Configuration](#settings--configuration) - [Types](#types) - [Styling](#styling) - [Demo](#demo) - [Utilities](#utilities) - [Requirements](#requirements) - [License](#license) ## Installation Install the package using your preferred package manager: ```bash npm install react-prayer-widget # or bun add react-prayer-widget # or pnpm add react-prayer-widget # or yarn add react-prayer-widget ``` ## Prerequisites Before using this package, ensure your project has: - **React 19+** (required peer dependency) - **React DOM 19+** (required peer dependency) - **TypeScript 5+** (recommended) - **Tailwind CSS** (required for styling) - **Node.js 18+** ## Package outputs & exports - Ships prebuilt ESM and CJS bundles with typings from `dist/` - Tree-shakeable surface (`sideEffects: false`) via `react-prayer-widget` - Core exports: `TranslationProvider`, `useTranslation`, `cn`, `formatTimeDisplay`, `formatMinutesHHmm`, `formatCurrentTime` - Widgets: `WidgetPrayerCard`, `WidgetPrayerCardSkeleton`, `NextPrayerCard`, `PrayerGrid`, `MinimalTicker`, `ScrollingTicker`, `DualDateDisplay` - Navigation/settings: `TopBar`, `SettingsDialog`, `WidgetSettingsContext`, `SettingsDialogProps` - Types: `PrayerTimes`, `PrayerSettings`, `ExtendedPrayerSettings`, `Location`, `NextPrayer`, `WidgetPrayerCardProps`, `PrayerGridProps` ## Next.js Project Setup If you're setting up a new Next.js project or integrating this package into an existing one, follow these steps: ### 1. Create Next.js Project (if starting fresh) ```bash npx create-next-app@latest my-prayer-app cd my-prayer-app ``` ### 2. Install Dependencies ```bash npm install react-prayer-widget # or bun add react-prayer-widget ``` ### 3. Configure Tailwind CSS Ensure your `tailwind.config.js` (or `tailwind.config.ts`) includes the package's content paths: ```js /** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", "./app/**/*.{js,ts,jsx,tsx,mdx}", "./node_modules/react-prayer-widget/**/*.{js,ts,jsx,tsx}", // Add this ], theme: { extend: {}, }, plugins: [], }; ``` ### 4. Setup Global Styles Ensure your `app/globals.css` (or `styles/globals.css`) includes Tailwind directives: ```css @tailwind base; @tailwind components; @tailwind utilities; ``` ### 5. Run Development Server ```bash npm run dev # or bun dev # or pnpm dev ``` Visit `http://localhost:3000` to see your app. ## Quick Start > **Important**: All widgets require a `TranslationProvider` wrapper. Make sure to wrap your app or the component tree where you use the widgets with `TranslationProvider`. ### Setup Translation Provider Wrap your app or component tree with `TranslationProvider`: ```tsx import { TranslationProvider } from "react-prayer-widget"; function App() { return ( <TranslationProvider language="en"> {/* Your app content with widgets */} </TranslationProvider> ); } ``` ### Basic Usage - Prayer Card ```tsx import { WidgetPrayerCard, TranslationProvider } from "react-prayer-widget"; function Header() { return ( <TranslationProvider language="en"> <header> <WidgetPrayerCard name="Dhuhr" time="12:30" isCurrent={true} /> </header> </TranslationProvider> ); } ``` ### Next Prayer with Countdown ```tsx import { NextPrayerCard, TranslationProvider } from "react-prayer-widget"; function PrayerWidget() { const nextPrayer = { name: "Asr", time: "15:45", timeUntil: 125, // minutes until prayer progress: 0.65, // 0-1 progress value }; return ( <TranslationProvider language="en"> <NextPrayerCard nextPrayer={nextPrayer} timeFormat24h={true} language="en" /> </TranslationProvider> ); } ``` ### Prayer Grid (All 5 Prayers) ```tsx import { PrayerGrid, TranslationProvider } from "react-prayer-widget"; function PrayerTimesSection() { const prayerTimes = { fajr: "05:30", sunrise: "06:45", dhuhr: "12:15", asr: "15:45", maghrib: "18:20", isha: "19:45", date: "2025-01-15", hijri: "1446-07-14", }; return ( <TranslationProvider language="en"> <PrayerGrid prayerTimes={prayerTimes} currentOrNextName="Dhuhr" timeFormat24h={true} language="en" /> </TranslationProvider> ); } ``` ### Complete Example with Settings ```tsx import { NextPrayerCard, PrayerGrid, TopBar, TranslationProvider, WidgetSettingsContext, type ExtendedPrayerSettings, } from "react-prayer-widget"; import { useState } from "react"; function PrayerApp() { const [settings, setSettings] = useState<ExtendedPrayerSettings>({ calculationMethod: 4, asrMethod: 0, timeFormat24h: true, language: "en", showOtherPrayers: true, showCity: true, showTicker: true, showDate: true, showClock: true, dimPreviousPrayers: true, horizontalView: false, nextCardSize: "lg", otherCardSize: "sm", }); const prayerTimes = { fajr: "05:30", sunrise: "06:45", dhuhr: "12:15", asr: "15:45", maghrib: "18:20", isha: "19:45", date: new Date().toISOString().split("T")[0], hijri: "1446-07-14", }; const nextPrayer = { name: "Asr", time: "15:45", timeUntil: 125, progress: 0.65, }; return ( <TranslationProvider language={settings.language || "en"}> <WidgetSettingsContext settings={settings} onSettingsChange={(newSettings) => setSettings((prev) => ({ ...prev, ...newSettings })) } > <div className="p-8"> <TopBar currentTime={new Date()} location={{ city: "Cairo", country: "Egypt", countryCode: "EG" }} showDate={settings.showDate} showClock={settings.showClock} showCity={settings.showCity} timeFormat24h={settings.timeFormat24h} language={settings.language} /> <NextPrayerCard nextPrayer={nextPrayer} timeFormat24h={settings.timeFormat24h} language={settings.language} nextSize={settings.nextCardSize} /> {settings.showOtherPrayers && ( <PrayerGrid prayerTimes={prayerTimes} currentOrNextName={nextPrayer.name} dimPreviousPrayers={settings.dimPreviousPrayers} horizontalView={settings.horizontalView} timeFormat24h={settings.timeFormat24h} language={settings.language} size={settings.otherCardSize} /> )} </div> </WidgetSettingsContext> </TranslationProvider> ); } ``` ## Components ### `WidgetPrayerCard` Individual prayer card component for displaying a single prayer time. **Props:** | Prop | Type | Default | Description | | ---------------- | ---------------------------------------- | ------- | --------------------------------------------- | | `name` | `string` | - | Prayer name (Fajr, Dhuhr, Asr, Maghrib, Isha) | | `time` | `string` | - | Prayer time (e.g., "12:30") | | `timezone` | `string?` | - | IANA timezone for Friday detection | | `isFriday` | `boolean?` | `false` | Override Friday detection | | `isCurrent` | `boolean?` | `false` | Highlight as current prayer | | `isNext` | `boolean?` | `false` | Show as next prayer with countdown | | `progress` | `number?` | - | Progress value (0-1) for countdown | | `countdown` | `string?` | - | Countdown string (e.g., "02:05") | | `size` | `"xxs" \| "xs" \| "sm" \| "md" \| "lg"?` | `"md"` | Card size | | `horizontalView` | `boolean?` | `false` | Compact horizontal layout | | `showIcon` | `boolean?` | `true` | Show prayer icon | | `className` | `string?` | - | Additional CSS classes | ### `NextPrayerCard` Specialized card for displaying the next prayer with countdown. This is a convenience wrapper around `WidgetPrayerCard` with `isNext={true}`. **Props:** | Prop | Type | Default | Description | | --------------- | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------- | | `nextPrayer` | `NextPrayer` | - | Object with `name`, `time`, `timeUntil` (minutes), `progress` (0-1) | | `timeFormat24h` | `boolean?` | `true` | Use 24-hour format | | `language` | `"en" \| "ar"?` | `"en"` | Display language | | `size` | `"xxs" \| "xs" \| "sm" \| "md" \| "lg"?` | `"md"` | Card size | | `nextSize` | `"xxs" \| "xs" \| "sm" \| "md" \| "lg"?` | `"md"` | Size for next prayer card | | `gradientClass` | `string?` | - | Override gradient classes | | `showIcon` | `boolean?` | `true` | Show prayer icon | | `className` | `string?` | - | Additional CSS classes | | `maxWidth` | `"md" \| "lg" \| "xl" \| "2xl" \| "3xl" \| number \| string?` | - | Max width constraint | ### `PrayerGrid` Grid layout displaying all 5 prayers in a responsive grid. **Props:** | Prop | Type | Default | Description | | -------------------- | ----------------------- | ------- | ----------------------------------------------------------------- | | `prayerTimes` | `PrayerTimes` | - | Object with fajr, sunrise, dhuhr, asr, maghrib, isha, date, hijri | | `currentOrNextName` | `string` | - | Name of current/next prayer to highlight | | `dimPreviousPrayers` | `boolean?` | `true` | Dim past prayers | | `horizontalView` | `boolean?` | `false` | Horizontal layout | | `timeFormat24h` | `boolean?` | `true` | Use 24-hour format | | `language` | `"en" \| "ar"?` | `"en"` | Display language | | `timezone` | `string?` | - | IANA timezone | | `isFriday` | `boolean?` | - | Friday override | | `size` | `WidgetPrayerCardSize?` | `"sm"` | Card size | | `maxWidth` | `string?` | - | Max width of grid | ### `TopBar` Header component displaying date, time, and location information. **Props:** | Prop | Type | Default | Description | | --------------- | --------------- | ------- | --------------------------------- | | `showDate` | `boolean?` | `true` | Show date display | | `showClock` | `boolean?` | `true` | Show clock | | `showCity` | `boolean?` | `true` | Show city/location | | `currentTime` | `Date` | - | Current time to display | | `location` | `Location?` | - | Location object with city/country | | `timeFormat24h` | `boolean?` | `true` | Use 24-hour format | | `language` | `"en" \| "ar"?` | `"en"` | Display language | | `className` | `string?` | - | Additional CSS classes | | `classes` | `object?` | - | Fine-grained class overrides | ### `WidgetSettingsContext` Context provider that enables right-click settings menu on widgets. Wrap your widgets with this to allow users to customize settings via context menu. **Props:** | Prop | Type | Description | | ------------------ | ----------------------------------------------------- | ----------------------------- | | `settings` | `ExtendedPrayerSettings` | Current settings object | | `onSettingsChange` | `(settings: Partial<ExtendedPrayerSettings>) => void` | Callback when settings change | | `children` | `React.ReactNode` | Widget components to wrap | ### `DualDateDisplay` Component for displaying both Gregorian and Hijri dates side by side. **Props:** | Prop | Type | Description | | ----------- | --------- | ---------------------- | | `className` | `string?` | Additional CSS classes | ### `MinimalTicker` / `ScrollingTicker` Ticker components for displaying prayer times and rotating azkar (remembrances) in a scrolling format. **Props (MinimalTicker):** | Prop | Type | Default | Description | | ------------- | ------------- | ------- | --------------------------------- | | `prayerTimes` | `PrayerTimes` | - | Prayer times data | | `intervalMs` | `number?` | `5000` | Rotation interval in milliseconds | | `className` | `string?` | - | Additional CSS classes | **Props (ScrollingTicker):** Similar to MinimalTicker with additional scrolling animation options. ## Settings & Configuration The `ExtendedPrayerSettings` type provides comprehensive configuration options for all widgets. Here's a complete reference: ### Prayer Calculation Settings | Property | Type | Default | Description | | ------------------- | ---------- | ------- | ----------------------------------------------------------------------------- | | `calculationMethod` | `number` | `4` | Prayer calculation method (see [Calculation Methods](#calculation-methods)) | | `asrMethod` | `number` | `0` | Asr calculation method: `0` = Standard (Shafi, Maliki, Hanbali), `1` = Hanafi | | `fajrOffset` | `number` | `0` | Minutes offset for Fajr time | | `dhuhrOffset` | `number` | `0` | Minutes offset for Dhuhr time | | `asrOffset` | `number` | `0` | Minutes offset for Asr time | | `maghribOffset` | `number` | `0` | Minutes offset for Maghrib time | | `ishaOffset` | `number` | `0` | Minutes offset for Isha time | | `applySummerHour` | `boolean?` | - | Apply daylight saving time adjustment | | `forceHourMore` | `boolean?` | - | Force +1 hour adjustment | | `forceHourLess` | `boolean?` | - | Force -1 hour adjustment | ### Location & Timezone Settings | Property | Type | Default | Description | | -------------------- | ---------- | -------------- | --------------------------------------------------- | | `timezone` | `string?` | `"Asia/Mecca"` | IANA timezone identifier (e.g., "America/New_York") | | `countryCode` | `string?` | `"SA"` | ISO 3166-1 alpha-2 country code | | `city` | `string?` | - | City name | | `cityCode` | `string?` | - | City code identifier | | `autoDetectTimezone` | `boolean?` | `false` | Automatically detect timezone from browser | | `locationError` | `string?` | - | Error message for location/permission issues | ### Display Settings | Property | Type | Default | Description | | -------------------- | --------------- | ------- | ------------------------------------------- | | `showOtherPrayers` | `boolean?` | `true` | Show prayer grid with all 5 prayers | | `showCity` | `boolean?` | `true` | Show city name in TopBar | | `showTicker` | `boolean?` | `true` | Show ticker with azkar | | `showDate` | `boolean?` | `true` | Show date in TopBar | | `showClock` | `boolean?` | `true` | Show clock in TopBar | | `horizontalView` | `boolean?` | `false` | Use horizontal layout for prayer grid | | `timeFormat24h` | `boolean?` | `true` | Use 24-hour time format (false for 12-hour) | | `dimPreviousPrayers` | `boolean?` | `true` | Dim past prayers in grid | | `language` | `"en" \| "ar"?` | `"en"` | Display language (English or Arabic) | ### Visual Customization | Property | Type | Default | Description | | ---------------------- | ---------------------------------------------------------- | ----------- | ---------------------------------------- | | `nextCardSize` | `"xxs" \| "xs" \| "sm" \| "md" \| "lg"?` | `"md"` | Size of the next prayer card | | `otherCardSize` | `"xxs" \| "xs" \| "sm" \| "md" \| "lg"?` | `"sm"` | Size of other prayer cards in grid | | `appWidth` | `"xxs" \| "xs" \| "md" \| "lg" \| "xl" \| "2xl" \| "3xl"?` | `"xl"` | Max width for the overall container | | `prayerNameColor` | `string?` | `"#ffffff"` | Custom color for prayer name text | | `prayerTimeColor` | `string?` | `"#ffffff"` | Custom color for prayer time text | | `prayerCountdownColor` | `string?` | `"#ffffff"` | Custom color for countdown text | | `tickerIntervalMs` | `number?` | `5000` | Ticker rotation interval in milliseconds | ### Azan (Adhan) Settings | Property | Type | Default | Description | | ---------------------- | ----------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------- | | `azanEnabled` | `boolean?` | `true` | Enable azan playback at prayer times | | `azanPerPrayer` | `boolean?` | `false` | Customize azan per prayer (vs. global) | | `azanByPrayer` | `Partial<Record<"Fajr" \| "Dhuhr" \| "Asr" \| "Maghrib" \| "Isha", string>>?` | - | Per-prayer azan selection (default\|short\|fajr\|beep\|off\|custom) | | `azanGlobalChoice` | `string?` | `"default"` | Global azan choice when not per-prayer | | `azanVolume` | `number?` | `1` | Azan volume (0-1) | | `azanEditMode` | `boolean?` | `false` | Enable drag-drop azan file upload mode | | `azanCustomNames` | `Partial<Record<"Fajr" \| "Dhuhr" \| "Asr" \| "Maghrib" \| "Isha", string>>?` | - | Display names for custom uploaded azan files | | `azanGlobalCustomName` | `string?` | - | Global custom azan file name | ### Calculation Methods The `calculationMethod` property accepts the following values: | Value | Method | | ----- | --------------------------------------------- | | `1` | University of Islamic Sciences, Karachi | | `2` | Islamic Society of North America (ISNA) | | `3` | Muslim World League | | `4` | Umm Al-Qura University, Makkah (default) | | `5` | Egyptian General Authority of Survey | | `7` | Institute of Geophysics, University of Tehran | | `8` | Gulf Region | | `9` | Kuwait | | `10` | Qatar | | `11` | Majlis Ugama Islam Singapura, Singapore | | `12` | Union Organization islamic de France | | `13` | Diyanet İşleri Başkanlığı, Turkey | ### Azan Types When configuring azan, you can use these values: - `"default"` - Full azan (default) - `"short"` - Short azan - `"fajr"` - Special Fajr azan - `"beep"` - Beep only - `"off"` - Disabled - `"custom"` - Custom uploaded file ### Example: Complete Settings Configuration ```tsx import type { ExtendedPrayerSettings } from "react-prayer-widget"; const settings: ExtendedPrayerSettings = { // Calculation calculationMethod: 4, // Umm Al-Qura University asrMethod: 0, // Standard fajrOffset: 0, dhuhrOffset: 0, asrOffset: 0, maghribOffset: 0, ishaOffset: 0, // Location timezone: "America/New_York", countryCode: "US", city: "New York", autoDetectTimezone: true, // Display showOtherPrayers: true, showCity: true, showTicker: true, showDate: true, showClock: true, horizontalView: false, timeFormat24h: false, // 12-hour format dimPreviousPrayers: true, language: "en", // Visual nextCardSize: "lg", otherCardSize: "sm", appWidth: "xl", prayerNameColor: "#ffffff", prayerTimeColor: "#ffffff", prayerCountdownColor: "#ffffff", tickerIntervalMs: 5000, // Azan azanEnabled: true, azanPerPrayer: false, azanGlobalChoice: "default", azanVolume: 0.8, azanEditMode: false, }; ``` ## Types ### `PrayerTimes` ```typescript type PrayerTimes = { fajr: string; // Fajr prayer time (HH:mm format) sunrise: string; // Sunrise time (HH:mm format) dhuhr: string; // Dhuhr prayer time (HH:mm format) asr: string; // Asr prayer time (HH:mm format) maghrib: string; // Maghrib prayer time (HH:mm format) isha: string; // Isha prayer time (HH:mm format) date: string; // Date string (ISO format: YYYY-MM-DD) hijri: string; // Hijri date string (YYYY-MM-DD) }; ``` ### `NextPrayer` ```typescript type NextPrayer = { name: string; // Prayer name (Fajr, Dhuhr, Asr, Maghrib, Isha) time: string; // Prayer time (HH:mm format) timeUntil: number; // Minutes until prayer progress: number; // Progress value (0-1) for countdown visualization }; ``` ### `Location` ```typescript type Location = { latitude?: number; longitude?: number; city?: string | null; country?: string | null; countryCode?: string | null; }; ``` ### `WidgetPrayerCardSize` ```typescript type WidgetPrayerCardSize = "xxs" | "xs" | "sm" | "md" | "lg"; ``` | Size | Description | | ----- | ----------------- | | `xxs` | Extra extra small | | `xs` | Extra small | | `sm` | Small | | `md` | Medium (default) | | `lg` | Large | ## Styling This package uses **Tailwind CSS** for styling. Make sure your project has Tailwind CSS configured. ### Customization Options Components are fully customizable via: - **`className` prop** - Additional CSS classes for the root element - **`classes` prop** - Fine-grained styling of internal elements (object with nested class names) - **`gradientClass` prop** - Override gradient classes for prayer cards - **`style` prop** - Inline styles ### Example: Custom Styling ```tsx <WidgetPrayerCard name="Dhuhr" time="12:30" className="my-custom-class" classes={{ container: "bg-blue-500", time: "text-xl font-bold", }} gradientClass="bg-gradient-to-r from-blue-500 to-purple-500" /> ``` ## Demo A comprehensive live demo is available at `/demo` route in this repository. The demo showcases: - Next Prayer Card with countdown - Prayer Grid with all 5 prayers - TopBar with date, time, and location - Minimal Ticker with rotating azkar - Different widget sizes (xxs, xs, sm, md, lg) - Right-click settings menu (via `WidgetSettingsContext`) - All settings variations and configurations ### Running the Demo Locally ```bash # Clone the repository git clone https://github.com/dahshury/react-prayer-widget.git cd react-prayer-widget # Install dependencies bun install # or npm install # Run development server bun dev # or npm run dev # Visit http://localhost:3000/demo ``` ## Utilities The package exports several utility functions: ### `formatCurrentTime(date: Date, format24h?: boolean): string` Format a Date object as a time string. ```tsx import { formatCurrentTime } from "react-prayer-widget"; const time = formatCurrentTime(new Date(), true); // "14:30" const time12h = formatCurrentTime(new Date(), false); // "2:30 PM" ``` ### `formatMinutesHHmm(minutes: number): string` Format minutes as HH:mm string. ```tsx import { formatMinutesHHmm } from "react-prayer-widget"; const time = formatMinutesHHmm(125); // "02:05" ``` ### `formatTimeDisplay(time: string, format24h?: boolean): string` Format a time string (HH:mm) to 12-hour format if needed. ```tsx import { formatTimeDisplay } from "react-prayer-widget"; const time24h = formatTimeDisplay("14:30", true); // "14:30" const time12h = formatTimeDisplay("14:30", false); // "2:30 PM" ``` ### `countryToFlag(countryCode: string): string` Get flag emoji for a country code. ```tsx import { countryToFlag } from "react-prayer-widget"; const flag = countryToFlag("US"); // "🇺🇸" const flag2 = countryToFlag("SA"); // "🇸🇦" ``` ### `useTranslation(): Translations` Hook to access translations in your components. ```tsx import { useTranslation } from "react-prayer-widget"; function MyComponent() { const t = useTranslation(); return <div>{t.prayers.fajr}</div>; // "Fajr" } ``` ### `cn(...classes): string` Utility for merging class names (similar to `clsx`). ```tsx import { cn } from "react-prayer-widget"; const className = cn("base-class", condition && "conditional-class"); ``` ## Requirements - **React 19+** (peer dependency) - **React DOM 19+** (peer dependency) - **TypeScript 5+** (recommended) - **Tailwind CSS** (required for styling) - **Node.js 18+** ## License MIT