planby

repository·master·Indexed 23 days ago

https://github.com/karolkozer/planby

A React-based component library for implementing Electronic Program Guides (EPGs), schedules, timelines, and live streaming interfaces. Version 2.0.0 features a custom virtual view for efficient handling of large datasets, a hook-based approach via useEpg for data management, and customizable layout rendering for programs and channels.

Tokens
7.5K
Snippets
13
Records
33
Agent score
81%

What's inside planby

  1. Inject custom global styles and fonts

    master

    Use the globalStyles option in useEpg to inject custom CSS and fonts. This allows you to target specific Planby internal classes to customize the look and feel.

    Available CSS Classes

    You can target the following classes within your injected styles:

    • .planby: The root container.
    • .planby-layout: The main layout container.
    • .planby-line: The live tracking line.
    • .planby-current-time: The current time indicator.
    • .planby-current-content: Content within the current time indicator.
    • .planby-channels: The channel sidebar container.
    • .planby-channel: Individual channel items.
    • .planby-program: Individual program items.
    • .planby-program-content, .planby-program-flex, .planby-program-stack, .planby-program-title, .planby-program-text: Program internal elements.
    • .planby-timeline-wrapper, .planby-timeline-box, .planby-timeline-time, .planby-timeline-dividers: Timeline elements.

    Note: Using globalStyles is a PRO feature.

  2. Customize timeline rendering with renderTimeline

    master

    You can implement a custom timeline by providing a renderTimeline function to the Layout component. Use the useTimeline hook to get the necessary time data, dividers, and formatting functions. The hook requires numberOfHoursInDay and isBaseTimeFormat as arguments.

    To support RTL, pass the isRTL prop to TimelineTime components.

    import {
      TimelineWrapper,
      TimelineBox,
      TimelineTime,
      TimelineDivider,
      TimelineDividers,
      useTimeline,
    } from 'planby';
    
    interface TimelineProps {
      isBaseTimeFormat: boolean;
      isSidebar: boolean;
      dayWidth: number;
      hourWidth: number;
      numberOfHoursInDay: number;
      offsetStartHoursRange: number;
      sidebarWidth: number;
      isRTL?: boolean;
    }
    
    export function Timeline({
      isBaseTimeFormat,
      isSidebar,
      dayWidth,
      hourWidth,
      numberOfHoursInDay,
      offsetStartHoursRange,
      sidebarWidth,
      isRTL,
    }: TimelineProps) {
      const { time, dividers, formatTime } = useTimeline(
        numberOfHoursInDay,
        isBaseTimeFormat
      );
    
      const renderTime = (index: number) => (
        <TimelineBox key={index} width={hourWidth}>
          <TimelineTime isBaseTimeFormat={isBaseTimeFormat} isRTL={isRTL}>
            {formatTime(index + offsetStartHoursRange).toLowerCase()}
          </TimelineTime>
          <TimelineDividers>
            {dividers.map((_, idx) => (
              <TimelineDivider key={idx} width={hourWidth} />
            ))}
          </TimelineDividers>
        </TimelineBox>
      );
    
      return (
        <TimelineWrapper
          dayWidth={dayWidth}
          sidebarWidth={sidebarWidth}
          isSidebar={isSidebar}
        >
          {time.map((_, index) => renderTime(index))}
        </TimelineWrapper>
      );
    }
    
    function App() {
      const { getEpgProps, getLayoutProps } = useEpg({
        epg,
        channels,
        startDate: '2022/02/02',
      });
    
      return (
        <div style={{ height: '600px', width: '1200px' }}>
          <Epg {...getEpgProps()}>
            <Layout
                {...getLayoutProps()}
                renderTimeline={(props) => <Timeline {...props} />}
              />
          </Epg>
        </div>
      );
    }
  3. Customize program rendering with renderProgram

    master

    You can customize how individual programs are displayed by providing a renderProgram function to the Layout component. Inside your custom component, use the useProgram hook to access styling and formatting utilities like styles, formatTime, isLive, and isMinWidth.

    To support 12-hour time formats, use set12HoursTimeFormat() within formatTime. For RTL (Right-to-Left) support, use isRTL from useProgram and the helper functions getRTLSinceTime and getRTLTillTime to format time strings correctly.

    import {
      useEpg,
      Epg,
      Layout,
      ProgramBox,
      ProgramContent,
      ProgramFlex,
      ProgramStack,
      ProgramTitle,
      ProgramText,
      ProgramImage,
      useProgram,
      ProgramItem
    } from "planby";
    
    const Item = ({ program,...rest }: ProgramItem) => {
      const { styles, formatTime, isLive, isMinWidth } = useProgram({ program,...rest });
    
      const { data } = program;
      const { image, title, since, till } = data;
    
      const sinceTime = formatTime(since);
      const tillTime = formatTime(till);
    
      return (
        <ProgramBox width={styles.width} style={styles.position}>
          <ProgramContent
            width={styles.width}
            isLive={isLive}
          >
            <ProgramFlex>
              {isLive && isMinWidth && <ProgramImage src={image} alt="Preview" />}
              <ProgramStack>
                <ProgramTitle>{title}</ProgramTitle>
                <ProgramText>
                  {sinceTime} - {tillTime}
                </ProgramText>
              </ProgramStack>
            </ProgramFlex>
          </ProgramContent>
        </ProgramBox>
      );
    };
    
    function App() {
      const { getEpgProps, getLayoutProps } = useEpg({
        epg,
        channels,
        startDate: '2022/02/02',
      });
    
      return (
        <div style={{ height: '600px', width: '1200px' }}>
          <Epg {...getEpgProps()}>
            <Layout
                {...getLayoutProps()}
                renderProgram={({ program,...rest }) => (
                  <Item key={program.data.id} program={program} {...rest} />
                )}
              />
          </Epg>
        </div>
      );
    }
  4. Implement a basic EPG with useEpg

    master

    Planby uses a hook-based approach to manage Electronic Program Guide (EPG) data. You provide epg data, channels data, and a startDate, and the useEpg hook returns props that can be spread onto the <Epg /> and <Layout /> components to render the schedule.

    Key steps:

    1. Define your channels array with unique uuids.
    2. Define your epg array, ensuring each item has a channelUuid matching a channel, a since time, and a till time.
    3. Initialize useEpg with your data.
    4. Spread getEpgProps() onto the <Epg /> component and getLayoutProps() onto the <Layout /> component.
    import { useEpg, Epg, Layout } from 'planby';
    
    const channels = React.useMemo(
      () => [
        {
          logo: 'https://via.placeholder.com',
          uuid: '10339a4b-7c48-40ab-abad-f3bcaf95d9fa',
          ...
        },
      ],
      []
    );
    
    const epg = React.useMemo(
      () => [
        {
          channelUuid: '30f5ff1c-1346-480a-8047-a999dd908c1e',
          description:
            'Ut anim nisi consequat minim deserunt...',
          id: 'b67ccaa3-3dd2-4121-8256-33dbddc7f0e6',
          image: 'https://via.placeholder.com',
          since: "2022-02-02T23:50:00",
          till: "2022-02-02T00:55:00",
          title: 'Title',
          ...
        },
      ],
      []
    );
    
    const {
      getEpgProps,
      getLayoutProps,
      onScrollToNow,
      onScrollLeft,
      onScrollRight,
    } = useEpg({
      epg,
      channels,
      startDate: '2022-02-02T00:00:00'
    });
    
    return (
      <div>
        <div style={{ height: '600px', width: '1200px' }}>
          <Epg {...getEpgProps()}>
            <Layout
              {...getLayoutProps()}
            />
          </Epg>
        </div>
      </div>
    );
  5. Customize channel rendering with renderChannel

    master

    To customize the appearance of channels in the EPG, provide a renderChannel function to the Layout component. The function receives a channel object (of type Channel). You can use Planby's style components like ChannelBox and ChannelLogo to build your custom UI.

    import { useEpg, Epg, Layout, ChannelBox, ChannelLogo, Channel } from 'planby';
    
    interface ChannelItemProps {
      channel: Channel;
    }
    
    const ChannelItem = ({ channel }: ChannelItemProps) => {
      const { position, logo } = channel;
      return (
        <ChannelBox {...position}>
          <ChannelLogo
            onClick={() => console.log('channel', channel)}
            src={logo}
            alt="Logo"
          />
        </ChannelBox>
      );
    };
    
    function App() {
      const { getEpgProps, getLayoutProps } = useEpg({
        epg,
        channels,
        startDate: '2022/02/02',
      });
    
      return (
        <div style={{ height: '600px', width: '1200px' }}>
          <Epg {...getEpgProps()}>
            <Layout
                {...getLayoutProps()}
                renderChannel={({ channel }) => (
                  <ChannelItem key={channel.uuid} channel={channel} />
                )}
              />
          </Epg>
        </div>
      );
    }
  6. Configure the EPG theme

    master

    The useEpg hook accepts a theme object to customize the visual identity of the EPG. The theme schema includes keys for primary, grey, white, green, loader, scrollbar, gradient, text, and timeline. Many keys support nested objects for specific sub-elements (e.g., timeline.divider.bg or scrollbar.thumb.bg).

    const theme = {
      primary: {
        600: '#1a202c',
        900: '#171923',
      },
      grey: { 300: '#d1d1d1' },
      white: '#fff',
      green: {
        300: '#2C7A7B',
      },
      loader: {
        teal: '#5DDADB',
        purple: '#3437A2',
        pink: '#F78EB6',
        bg: '#171923db',
      },
      scrollbar: {
        border: '#ffffff',
        thumb: {
          bg: '#e1e1e1',
        },
      },
      gradient: {
        blue: {
          300: '#002eb3',
          600: '#002360',
          900: '#051937',
        },
      },
      text: {
        grey: {
          300: '#a0aec0',
          500: '#718096',
        },
      },
      timeline: {
        divider: {
          bg: '#718096',
        },
      },
    };
  7. Configure useEpg with custom dimensions and time ranges

    master

    The useEpg hook accepts several configuration options to control the viewport and time window of the EPG.

    • width: The width of the EPG container.
    • height: The height of the EPG container.
    • startDate: The beginning of the visible time range (supports YYYY-MM-DD or ISO strings).
    • endDate: The end of the visible time range.

    Note: When providing width and height in the hook, you do not necessarily need to wrap the components in a sized div for the logic to work, though the container will still occupy space.

    // Example with custom width and height
    const {
      getEpgProps,
      getLayoutProps,
      ...
    } = useEpg({
      epg,
      channels,
      startDate: '2022/02/02', // or 2022-02-02T00:00:00
      width: 1200,
      height: 600
    });
    
    // Example with specific time range
    const {
      getEpgProps,
      getLayoutProps,
      ...
    } = useEpg({
      epg,
      channels,
      startDate: '2022-02-02T10:00:00',
      endDate: '2022-02-02T20:00:00',
      width: 1200,
      height: 600
    });
  8. Customize Layout rendering

    master

    You can override the default rendering of components within the Layout component using render props.

    Layout Render Props

    • renderProgram: function({ program: { data: object, position: object } }) - Custom rendering for programs. data contains program properties, and position contains position styles.
    • renderChannel: function({ channel: { ..., position: object } }) - Custom rendering for channels. channel contains channel properties, and position contains position styles.
    • renderTimeline: function({ sidebarWidth: number }) - Custom rendering for the timeline. Receives the sidebarWidth.
    • renderLine: function({ styles: object }) - Custom rendering for the live tracking line (Sponsors feature).
    • renderCurrentTime: function({ styles: object, isRTL: boolean, isBaseTimeFormat: boolean, time: string }) - Custom rendering for the current time indicator (Sponsors feature).
  9. Use the useEpg hook

    master

    The useEpg hook is the primary way to manage Electronic Program Guide (EPG) data and layout configuration in Planby. It accepts a configuration object and returns an instance object containing scroll controls and current scroll positions.

    Required Options

    • channels: An array of channel data objects.
    • epg: An array of EPG program data objects.

    Dimensions

    If you do not declare width and height in the options, the component will automatically take the dimensions of its parent element.

    Instance Properties

    The hook returns an object with the following properties to control or monitor the EPG state:

    • scrollY: Current vertical scroll position.
    • scrollX: Current horizontal scroll position.
    • onScrollLeft(value: number): Function to scroll left (default step: 300).
    • onScrollRight(value: number): Function to scroll right (default step: 300).
    • onScrollTop(value: number): Function to scroll to the top (default step: 300).
    • onScrollToNow(): Function to scroll to the current time or live programs.
  10. Define Channel and EPG data schemas

    master

    When providing data to useEpg, ensure your objects follow these schemas:

    Channel Schema

    • logo: string (required) - URL or path to the channel logo.
    • uuid: string (required) - Unique identifier for the channel.

    EPG Schema

    • channelUuid: string (required) - The uuid of the channel this program belongs to.
    • id: string (required) - Unique identifier for the program.
    • image: string (required) - URL or path to the program image.
    • since: string (required) - Start time.
    • till: string (required) - End time.
    • title: string (required) - Program title.
    • fixedVisibility: boolean (optional) - If true, the element remains visible during scroll events (e.g., for Sponsors).
  11. Configure useEpg options

    master

    The useEpg hook supports a wide range of configuration options. Note that some features are marked as PRO and require a commercial license.

    Core Configuration

    • channels: array (required) - Array with channels data.
    • epg: array (required) - Array with EPG data.
    • itemHeight: number (optional) - Height of channels and programs. Default is 80.
    • dayWidth: number (optional) - Width of a full day. Default is 7200. To calculate: 24h * (your custom hour width) = dayWidth.
    • startDate / endDate: string (optional) - Date formats: 2022/02/02 or 2022-02-02T00:00:00. Must be within the same 24-hour period.
    • isBaseTimeFormat: boolean (optional) - If true, converts time to 12-hour format (e.g., 2:00am). Default is false.
    • isSidebar: boolean (optional) - Show/hide sidebar.
    • isTimeline: boolean (optional) - Show/hide timeline.
    • isLine: boolean (optional) - Show/hide the live tracking line.

    PRO Features

    • timelineHeight: Height of the timeline.
    • endDate: Allows scrolling through multiple days.
    • hoursInDays: Set start/end times for each day in multiple-day mode.
    • initialScrollPositions: { top: number, left: number } to set initial position.
    • liveRefreshTime: Refresh interval for events (default 120 sec).
    • isCurrentTime: Show current time in Timeline.
    • isInitialScrollToNow: Automatically scroll to the current live element.
    • isVerticalMode: Show Timeline in vertical view.
    • isResize: Enable element resizing.
    • isRTL: Change direction to Right-to-Left.
    • timezone: Convert and display data from UTC to a specific timezone.
    • mode: { mode: 'day' | 'week' | 'month', style: 'default' | 'modern' }.
    • overlap: { mode: 'stack' | 'layer', layerOverlapLevel: number }.
    • drag and drop: { mode: 'row' | 'multi-rows' }.
    • grid layout: { modeHoverHighlight: boolean, onGridItemClick: function }.
    • channelMapKey / programChannelMapKey: Map custom data properties to uuid or channelUuid.
    • globalStyles: Inject custom CSS/fonts.
    • areas: Add field ranges to the Timeline layout.