{"id":13406178,"url":"https://github.com/karolkozer/planby","last_synced_at":"2025-03-14T10:32:39.011Z","repository":{"id":38341791,"uuid":"454734679","full_name":"karolkozer/planby","owner":"karolkozer","description":null,"archived":false,"fork":false,"pushed_at":"2023-12-25T14:08:49.000Z","size":9205,"stargazers_count":1326,"open_issues_count":4,"forks_count":90,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-05-01T18:39:12.936Z","etag":null,"topics":["app","component","eletronic","epg","events","guide","harmonogram","hooks","music","online","program","react","schedule","television","tv","vod","web","website"],"latest_commit_sha":null,"homepage":"https://planby.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/karolkozer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":["karolkozer"],"open_collective":"planby"}},"created_at":"2022-02-02T10:44:19.000Z","updated_at":"2024-05-01T03:52:50.000Z","dependencies_parsed_at":"2023-11-07T17:12:14.440Z","dependency_job_id":"83bbc490-9753-43b5-b791-395e65086193","html_url":"https://github.com/karolkozer/planby","commit_stats":{"total_commits":75,"total_committers":4,"mean_commits":18.75,"dds":"0.22666666666666668","last_synced_commit":"885ce92818ae1a83f5be048823d3f43c9f25dbcf"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karolkozer%2Fplanby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karolkozer%2Fplanby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karolkozer%2Fplanby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karolkozer%2Fplanby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/karolkozer","download_url":"https://codeload.github.com/karolkozer/planby/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221126783,"owners_count":16760892,"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","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":["app","component","eletronic","epg","events","guide","harmonogram","hooks","music","online","program","react","schedule","television","tv","vod","web","website"],"created_at":"2024-07-30T19:02:23.309Z","updated_at":"2024-10-25T20:32:02.792Z","avatar_url":"https://github.com/karolkozer.png","language":"TypeScript","readme":"\u003cdiv align=\"center\" style=\"margin-bottom: 10px\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/planby\"\u003e\n    \u003cimg src=\"https://i.postimg.cc/J0XMPHNQ/planby-logo.png\" alt=\"Planby logo\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\" style=\"margin-bottom: 20px\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/planby\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/planby\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://npmjs.org/package/planby\"\u003e\n    \u003cimg alt=\"downloads\" src=\"https://badgen.net/npm/dm/planby\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://npmjs.org/package/planby\"\u003e\n    \u003cimg alt=\"downloads\" src=\"https://img.shields.io/npm/dt/planby?color=%2327ae60\u0026label=recent%20downloads\" /\u003e\n  \u003c/a\u003e \n \u003ca href=\"https://opencollective.com/planby#sponsor\"  target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n## Description\n\nPlanby is a React based component for a quick implementation of Epg, schedules, live streaming, music events, timelines and many more ideas. It uses a custom virtual view which allows you to operate on a really big number of data. The component has a simple API that you can easily integrate with other third party UI libraries. The component theme is customised to the needs of the application design.\n\n\u003cdiv align=\"center\" style=\"margin-bottom: 10px\"\u003e\n  \u003ca href=\"https://planby.netlify.app/\"\u003e\n    \u003cimg src=\"https://i.postimg.cc/6p2GDGMX/tv-preview-custom.png\" alt=\"Planby preview\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\" style=\"margin-bottom: 10px\"\u003e\n  \u003ca href=\"https://planby.netlify.app/\"\u003e\n    \u003cimg src=\"https://i.postimg.cc/s2Pn9jGZ/planby-conf-event.png\" alt=\"Planby preview\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\" style=\"margin-bottom: 10px\"\u003e\n  \u003ca href=\"https://planby.netlify.app/\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/karolkozer/planby-demo-resources/master/planby-planner-week.png\" alt=\"Planby preview\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\" style=\"margin-bottom: 10px\"\u003e\n  \u003ca href=\"https://planby.netlify.app/\"\u003e\n    \u003cimg src=\"https://i.postimg.cc/50qZ05ST/planby-music-festival-event.png\" alt=\"Planby preview\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n## Codesandbox example\n\n[Live example - Codesandbox](https://codesandbox.io/s/5o3tsy)\n\n[Live example - Typescript Codesandbox](https://codesandbox.io/s/planby-epg-demo-ts-lp66v5)\n\n[Live example - website with control panel](https://planby.netlify.app/)\n\n## Testimonials\n\n\u003cdiv align=\"center\" \u003e\n  \u003ca href=\"https://planby.netlify.app/#testimonials\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/karolkozer/planby-demo-resources/master/they-use-planby.png\" alt=\"Planby preview\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\" style=\"margin-bottom: 10px\"\u003e\n  \u003ca href=\"https://planby.netlify.app/#testimonials\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/karolkozer/planby-demo-resources/master/testimonials.png\" alt=\"Planby preview\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n## 🚀 [Become a Sponsor!](https://opencollective.com/planby) 🚀\n\nBecome a sponsor, support, and help us in continuing our development. -\u003e [Opencollective](https://opencollective.com/planby)\n\n## Getting Started\n\n### Installation\n\n- yarn\n\n```sh\nyarn add planby\n```\n\n- npm\n\n```sh\nnpm install planby\n```\n\n## Usage\n\n```tsx\nimport { useEpg, Epg, Layout } from 'planby';\n\nconst channels = React.useMemo(\n  () =\u003e [\n    {\n      logo: 'https://via.placeholder.com',\n      uuid: '10339a4b-7c48-40ab-abad-f3bcaf95d9fa',\n      ...\n    },\n  ],\n  []\n);\n\nconst epg = React.useMemo(\n  () =\u003e [\n    {\n      channelUuid: '30f5ff1c-1346-480a-8047-a999dd908c1e',\n      description:\n        'Ut anim nisi consequat minim deserunt...',\n      id: 'b67ccaa3-3dd2-4121-8256-33dbddc7f0e6',\n      image: 'https://via.placeholder.com',\n      since: \"2022-02-02T23:50:00\",\n      till: \"2022-02-02T00:55:00\",\n      title: 'Title',\n      ...\n    },\n  ],\n  []\n);\n\nconst {\n  getEpgProps,\n  getLayoutProps,\n  onScrollToNow,\n  onScrollLeft,\n  onScrollRight,\n} = useEpg({\n  epg,\n  channels,\n  startDate: '2022/02/02', // or 2022-02-02T00:00:00\n});\n\nreturn (\n  \u003cdiv\u003e\n    \u003cdiv style={{ height: '600px', width: '1200px' }}\u003e\n      \u003cEpg {...getEpgProps()}\u003e\n        \u003cLayout\n          {...getLayoutProps()}\n        /\u003e\n      \u003c/Epg\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n);\n```\n\nor\n\n#### Custom width and height\n\n```tsx\nconst {\n  getEpgProps,\n  getLayoutProps,\n  ...\n} = useEpg({\n  epg,\n  channels,\n startDate: '2022/02/02', // or 2022-02-02T00:00:00\n  width: 1200,\n  height: 600\n});\n\nreturn (\n  \u003cdiv\u003e\n     \u003cEpg {...getEpgProps()}\u003e\n        \u003cLayout\n          {...getLayoutProps()}\n        /\u003e\n      \u003c/Epg\u003e\n  \u003c/div\u003e\n\n```\n\nor\n\n#### Time range\n\n```tsx\nconst {\n  getEpgProps,\n  getLayoutProps,\n  ...\n} = useEpg({\n  epg,\n  channels,\n  startDate: '2022-02-02T10:00:00',\n  endDate: '2022-02-02T20:00:00',\n  width: 1200,\n  height: 600\n});\n\nreturn (\n  \u003cdiv\u003e\n     \u003cEpg {...getEpgProps()}\u003e\n        \u003cLayout\n          {...getLayoutProps()}\n        /\u003e\n      \u003c/Epg\u003e\n  \u003c/div\u003e\n\n```\n\n## API\n\n### useEpg\n\n#### Options\n\nAvailable options in useEpg\n\n| Property                 | Type      | Status   | Description                                                                                                                                                                                                                    | Access |\n| ------------------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ |\n| `channels`               | `array`   | required | Array with channels data                                                                                                                                                                                                       |        |\n| `epg`                    | `array`   | required | Array with EPG data                                                                                                                                                                                                            |        |\n| `width`                  | `number`  | optional | EPG width                                                                                                                                                                                                                      |        |\n| `height`                 | `number`  | optional | EPG height                                                                                                                                                                                                                     |        |\n| `sidebarWidth`           | `number`  | optional | Width of the sidebar with channels                                                                                                                                                                                             |        |\n| `timelineHeight`         | `number`  | optional | Height of the timeline                                                                                                                                                                                                         | `PRO`  |\n| `itemHeight`             | `number`  | optional | Height of channels and programs in the EPG. Default value is 80                                                                                                                                                                |        |\n| `dayWidth`               | `number`  | optional | Width of the day. Default value is 7200. Calculation to set up day width with own hour width value e.g., 24h \\* 300px (your custom hour width) = 7200px -\u003e `dayWidth`                                                          |        |\n| `startDate`              | `string`  | optional | Date format `2022/02/02` or `2022-02-02T00:00:00`. You can set your own start time, e.g., `2022-02-02T10:00:00`, `2022-02-02T14:00:00`, etc. Full clock hours only                                                             |        |\n| `endDate`                | `string`  | optional | Date format `2022-02-02T00:00:00`, `2022-02-02T20:00:00`, etc. Must be within the same 24-hour period as `startDate`. Full clock hours only. Scroll through `multiple days` and timeline mode is available only in `PRO` plan. | `PRO`  |\n| `hoursInDays`            | `array`   | optional | Set start time and end time of each day in `multiple days` feature if your data for each day has some time spaces between items in the day.                                                                                    | `PRO`  |\n| `initialScrollPositions` | `object`  | optional | Set initial scroll position in Layout, e.g., `initialScrollPositions: { top: 500, left: 800 }`                                                                                                                                 | `PRO`  |\n| `liveRefreshTime`        | `number`  | optional | Live refresh time of the events. Default value is 120 sec.                                                                                                                                                                     | `PRO`  |\n| `isBaseTimeFormat`       | `boolean` | optional | Convert to 12-hour format, e.g., `2:00am`, `4:00pm`, etc. Default value is false.                                                                                                                                              |        |\n| `isCurrentTime`          | `boolean` | optional | Show current time in Timeline. Default value is false.                                                                                                                                                                         | `PRO`  |\n| `isInitialScrollToNow`   | `boolean` | optional | Scroll to the current live element.                                                                                                                                                                                            | `PRO`  |\n| `isVerticalMode`         | `boolean` | optional | Show Timeline in vertical view. Default value is false.                                                                                                                                                                        | `PRO`  |\n| `isResize`               | `boolean` | optional | Possibility to resize the element.                                                                                                                                                                                             | `PRO`  |\n| `isSidebar`              | `boolean` | optional | Show/hide sidebar                                                                                                                                                                                                              |        |\n| `isTimeline`             | `boolean` | optional | Show/hide timeline                                                                                                                                                                                                             |        |\n| `isLine`                 | `boolean` | optional | Show/hide line                                                                                                                                                                                                                 |        |\n| `isRTL`                  | `boolean` | optional | Change direction to RTL or LTR. Default value is false.                                                                                                                                                                        | `PRO`  |\n| `theme`                  | `object`  | optional | Object with theme schema                                                                                                                                                                                                       |        |\n| `timezone`               | `object`  | optional | Convert and display data from UTC format to your own time zone                                                                                                                                                                 | `PRO`  |\n| `areas`                  | `array`   | optional | Area gives possibilities to add field ranges to the Timeline layout.                                                                                                                                                           | `PRO`  |\n| `mode`                   | `object`  | optional | Type values: `day/week/month`. Style values: `default/modern` Define the mode and style of the timeline. Default mode is `day` and style is `default`                                                                          | `PRO`  |\n| `overlap`                | `object`  | optional | Enable the element overlaps in the layout. Mode values: `stack/layer`, layerOverlapLevel: `number`                                                                                                                             | `PRO`  |\n| `drag and drop`          | `object`  | optional | Drag and move the element in the layout. Mode values: `row/multi-rows`                                                                                                                                                         | `PRO`  |\n| `grid layout`            | `object`  | optional | Background grid on the layout. Mode hoverHighlight values: `true/false`, onGridItemClick: function with all the properties on clicked item grid                                                                                | `PRO`  |\n| `channelMapKey`          | `string`  | optional | The Channel `uuid` attribute can be controlled by prop. Key map gives a possibilities to use specific prop from own data instead of needing to map to uuid in own data                                                         | `PRO`  |\n| `programChannelMapKey`   | `string`  | optional | The Programs `channelUuid` attributes can be controlled by prop. Key map gives a possibilities to use a specific prop from own data instead of needing to map to channelUuid in your data                                      | `PRO`  |\n| `globalStyles`           | `string`  | optional | Inject custom global styles and font. Font weight: 400,500,600. Default font is \"Inter\"                                                                                                                                        | `PRO`  |\n\n#### Note about width and height props\n\nWithout declaring the `width` and `length` properties, the component takes the dimensions of the parent element.\n\n#### globalStyles\n\nInject own custom font and other global styles.\n\n```tsx\nconst globalStyles = `\n  @import url(\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600\u0026display=swap\");\n\n/* Available in PRO plan */\n .planby {\n  font-family: \"Inter\", system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica,\n    Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\";\n\n  /* Layout */\n  .planby-layout {}\n\n  /* Line */\n  .planby-line {}\n\n  /* Current time */\n  .planby-current-time {}\n  .planby-current-content {}\n\n  /* Channels */\n  .planby-channels {}\n\n  /* Channel */\n  .planby-channel {}\n\n  /* Program */\n  .planby-program {}\n  .planby-program-content {}\n  .planby-program-flex {}\n  .planby-program-stack {}\n  .planby-program-title {}\n  .planby-program-text {}\n\n  /* Timeline */\n  .planby-timeline-wrapper {}\n  .planby-timeline-box {}\n  .planby-timeline-time {}\n  .planby-timeline-dividers {}\n  .planby-timeline-wrapper {}\n}\n  \n`;\n```\n\n#### Instance Properties\n\nProperties returned from useEpg\n\n| Property        | Type                      | Description                          |\n| --------------- | ------------------------- | ------------------------------------ |\n| `scrollY`       | `number`                  | Current scroll y value               |\n| `scrollX`       | `number`                  | Current scroll x value               |\n| `onScrollLeft`  | `function(value: number)` | Default value is 300                 |\n| `onScrollRight` | `function(value: number)` | Default value is 300                 |\n| `onScrollToNow` | `function()`              | Scroll to current time/live programs |\n| `onScrollTop`   | `function(value: number)` | Default value is 300                 |\n\n### Channel schema\n\n| Property | Type     | Status   |\n| -------- | -------- | -------- |\n| `logo`   | `string` | required |\n| `uuid`   | `string` | required |\n\n### Epg schema\n\n| Property          | Type      | Status   | Description                                                          | Access   |\n| ----------------- | --------- | -------- | -------------------------------------------------------------------- | -------- |\n| `channelUuid`     | `string`  | required |\n| `id`              | `string`  | required |\n| `image`           | `string`  | required |\n| `since`           | `string`  | required |\n| `till`            | `string`  | required |\n| `title`           | `string`  | required |\n| `fixedVisibility` | `boolean` | optional | The element is always visible in the layout during the scroll events | Sponsors |\n\n### Epg\n\n#### Base props\n\nAvailable props in Epg\n\n| Property    | Type        | Description             | Status   |\n| ----------- | ----------- | ----------------------- | -------- |\n| `isLoading` | `boolean`   | Loader state            | optional |\n| `loader`    | `Component` | Loader custom component | optional |\n\n### Layout\n\n#### Base props\n\nAvailable props in Layout.\n\n| Property            | Type                                                                                  | Description                                                                                                     | Status   | Access     |\n| ------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -------- | ---------- |\n| `renderProgram`     | `function({ program: { data: object, position: object})`                              | `data` object contains all properties related to the program, `position` object includes all position styles    | optional |\n| `renderChannel`     | `function({ channel: { ..., position: object})`                                       | `channel` object contains all properties related to the channel, `position` object includes all position styles | optional |\n| `renderTimeline`    | `function({sidebarWidth: number})`                                                    | `sidebarWidth` value of the channel's sidebar width                                                             | optional |\n| `renderLine`        | `function({styles: object})`                                                          | basic `styles` and `position` values for the custom live tracking Line                                          | optional | `Sponsors` |\n| `renderCurrentTime` | `function({styles: object, isRTL: boolean, isBaseTimeFormat: boolean, time: string})` | basic `styles` values for the custom current time                                                               | optional | `Sponsors` |\n\n# Render functions\n\nYou can use Plaby's style components to develop main features. Moreover, you can integrate with third party UI library eg. Chakra UI, Material UI etc or make custom styles.\n\n## renderProgram\n\nBelow is an example that allows you to render your custom Program component using Plaby's style components.\n\n```tsx\nimport {\n  useEpg,\n  Epg,\n  Layout,\n  ProgramBox,\n  ProgramContent,\n  ProgramFlex,\n  ProgramStack,\n  ProgramTitle,\n  ProgramText,\n  ProgramImage,\n  useProgram,\n  Program,\n  ProgramItem\n} from \"planby\";\n\n\nconst Item = ({ program,...rest }: ProgramItem) =\u003e {\n  const { styles, formatTime, isLive, isMinWidth } = useProgram({ program,...rest });\n\n  const { data } = program;\n  const { image, title, since, till } = data;\n\n  const sinceTime = formatTime(since);\n  const tillTime = formatTime(till);\n\n  return (\n    \u003cProgramBox width={styles.width} style={styles.position}\u003e\n      \u003cProgramContent\n        width={styles.width}\n        isLive={isLive}\n      \u003e\n        \u003cProgramFlex\u003e\n          {isLive \u0026\u0026 isMinWidth \u0026\u0026 \u003cProgramImage src={image} alt=\"Preview\" /\u003e}\n          \u003cProgramStack\u003e\n            \u003cProgramTitle\u003e{title}\u003c/ProgramTitle\u003e\n            \u003cProgramText\u003e\n              {sinceTime} - {tillTime}\n            \u003c/ProgramText\u003e\n          \u003c/ProgramStack\u003e\n        \u003c/ProgramFlex\u003e\n      \u003c/ProgramContent\u003e\n    \u003c/ProgramBox\u003e\n  );\n};\n\nfunction App() {\n\n  ...\n\n const {\n  getEpgProps,\n  getLayoutProps,\n} = useEpg({\n  epg,\n  channels,\n  startDate: '2022/02/02', // or 2022-02-02T00:00:00\n});\n\nreturn (\n  \u003cdiv\u003e\n    \u003cdiv style={{ height: '600px', width: '1200px' }}\u003e\n      \u003cEpg {...getEpgProps()}\u003e\n        \u003cLayout\n            {...getLayoutProps()}\n            renderProgram={({ program,...rest }) =\u003e (\n              \u003cItem key={program.data.id} program={program} {...rest} /\u003e\n            )}\n          /\u003e\n      \u003c/Epg\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n);\n}\n\nexport default App;\n```\n\n## renderProgram - 12 hours time format\n\nBelow is an example that allows you to render your custom Program component with 12 hours time format using Plaby's style components.\n\n```tsx\n...\nconst Item = ({ program, ...rest }: ProgramItem) =\u003e {\n  const {\n    styles,\n    formatTime,\n    set12HoursTimeFormat,\n    isLive,\n    isMinWidth,\n  } = useProgram({\n    program,\n    ...rest\n  });\n\n  const { data } = program;\n  const { image, title, since, till } = data;\n\n  const sinceTime = formatTime(since, set12HoursTimeFormat()).toLowerCase();\n  const tillTime = formatTime(till, set12HoursTimeFormat()).toLowerCase();\n\n  return (\n    \u003cProgramBox width={styles.width} style={styles.position}\u003e\n      \u003cProgramContent\n        width={styles.width}\n        isLive={isLive}\n      \u003e\n        \u003cProgramFlex\u003e\n          {isLive \u0026\u0026 isMinWidth \u0026\u0026 \u003cProgramImage src={image} alt=\"Preview\" /\u003e}\n          \u003cProgramStack\u003e\n            \u003cProgramTitle\u003e{title}\u003c/ProgramTitle\u003e\n            \u003cProgramText\u003e\n              {sinceTime} - {tillTime}\n            \u003c/ProgramText\u003e\n          \u003c/ProgramStack\u003e\n        \u003c/ProgramFlex\u003e\n      \u003c/ProgramContent\u003e\n    \u003c/ProgramBox\u003e\n  );\n};\n\nfunction App() {\n\n  ...\n\n const {\n  getEpgProps,\n  getLayoutProps,\n} = useEpg({\n  epg,\n  channels,\n  isBaseTimeFormat: true,\n  startDate: '2022/02/02', // or 2022-02-02T00:00:00\n});\n\n...\n}\n\nexport default App;\n```\n\n## renderProgram - RTL direction\n\nBelow is an example that allows you to render your custom Program component with RTL direction using Plaby's style components.\n\n```tsx\n...\nconst Item = ({ program, ...rest }: ProgramItem) =\u003e {\n  const {\n    isRTL,\n    isLive,\n    isMinWidth,\n    formatTime,\n    styles,\n    set12HoursTimeFormat,\n    getRTLSinceTime,\n    getRTLTillTime,\n  } = useProgram({\n    program,\n    ...rest\n  });\n\n  const { data } = program;\n  const { image, title, since, till } = data;\n\n  const sinceTime = formatTime(\n    getRTLSinceTime(since),\n    set12HoursTimeFormat()\n  ).toLowerCase();\n  const tillTime = formatTime(\n    getRTLTillTime(till),\n    set12HoursTimeFormat()\n  ).toLowerCase();\n\n  return (\n    \u003cProgramBox width={styles.width} style={styles.position}\u003e\n      \u003cProgramContent width={styles.width} isLive={isLive}\u003e\n        \u003cProgramFlex\u003e\n          {isLive \u0026\u0026 isMinWidth \u0026\u0026 \u003cProgramImage src={image} alt=\"Preview\" /\u003e}\n          \u003cProgramStack isRTL={isRTL}\u003e\n            \u003cProgramTitle\u003e{title}\u003c/ProgramTitle\u003e\n            \u003cProgramText\u003e\n              {sinceTime} - {tillTime}\n            \u003c/ProgramText\u003e\n          \u003c/ProgramStack\u003e\n        \u003c/ProgramFlex\u003e\n      \u003c/ProgramContent\u003e\n    \u003c/ProgramBox\u003e\n  );\n};\n\nfunction App() {\n\n  ...\n\n const {\n  getEpgProps,\n  getLayoutProps,\n} = useEpg({\n  epg,\n  channels,\n  isBaseTimeFormat: true,\n  startDate: '2022/02/02', // or 2022-02-02T00:00:00\n});\n\n...\n}\n\nexport default App;\n```\n\n## renderChannel\n\nBelow is an example that allows you to render your custom Channel component using Plaby's style components.\n\n```tsx\nimport { useEpg, Epg, Layout, ChannelBox, ChannelLogo, Channel } from 'planby';\n\ninterface ChannelItemProps {\n  channel: Channel;\n}\n\nconst ChannelItem = ({ channel }: ChannelItemProps) =\u003e {\n  const { position, logo } = channel;\n  return (\n    \u003cChannelBox {...position}\u003e\n      \u003cChannelLogo\n        onClick={() =\u003e console.log('channel', channel)}\n        src={logo}\n        alt=\"Logo\"\n      /\u003e\n    \u003c/ChannelBox\u003e\n  );\n};\n\n\nfunction App() {\n\n  ...\n\n  const {\n    getEpgProps,\n    getLayoutProps,\n  } = useEpg({\n    epg,\n    channels,\n    startDate: '2022/02/02', // or 2022-02-02T00:00:00\n  });\n\n  return (\n    \u003cdiv\u003e\n      \u003cdiv style={{ height: '600px', width: '1200px' }}\u003e\n        \u003cEpg {...getEpgProps()}\u003e\n          \u003cLayout\n              {...getLayoutProps()}\n              renderChannel={({ channel }) =\u003e (\n              \u003cChannelItem key={channel.uuid} channel={channel} /\u003e\n            )}\n            /\u003e\n        \u003c/Epg\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n\n```\n\n## renderTimeline\n\nBelow is an example that allows you to render your custom Timeline component using Plaby's style components.\n\n```tsx\nimport {\n  TimelineWrapper,\n  TimelineBox,\n  TimelineTime,\n  TimelineDivider,\n  TimelineDividers,\n  useTimeline,\n} from 'planby';\n\ninterface TimelineProps {\n  isBaseTimeFormat: boolean;\n  isSidebar: boolean;\n  dayWidth: number;\n  hourWidth: number;\n  numberOfHoursInDay: number;\n  offsetStartHoursRange: number;\n  sidebarWidth: number;\n}\n\nexport function Timeline({\n  isBaseTimeFormat,\n  isSidebar,\n  dayWidth,\n  hourWidth,\n  numberOfHoursInDay,\n  offsetStartHoursRange,\n  sidebarWidth,\n}: TimelineProps) {\n  const { time, dividers, formatTime } = useTimeline(\n    numberOfHoursInDay,\n    isBaseTimeFormat\n  );\n\n  const renderTime = (index: number) =\u003e (\n    \u003cTimelineBox key={index} width={hourWidth}\u003e\n      \u003cTimelineTime\u003e\n        {formatTime(index + offsetStartHoursRange).toLowerCase()}\n      \u003c/TimelineTime\u003e\n      \u003cTimelineDividers\u003e{renderDividers()}\u003c/TimelineDividers\u003e\n    \u003c/TimelineBox\u003e\n  );\n\n  const renderDividers = () =\u003e\n    dividers.map((_, index) =\u003e (\n      \u003cTimelineDivider key={index} width={hourWidth} /\u003e\n    ));\n\n  return (\n    \u003cTimelineWrapper\n      dayWidth={dayWidth}\n      sidebarWidth={sidebarWidth}\n      isSidebar={isSidebar}\n    \u003e\n      {time.map((_, index) =\u003e renderTime(index))}\n    \u003c/TimelineWrapper\u003e\n  );\n}\n\nfunction App() {\n\n  ...\n\n  const {\n    getEpgProps,\n    getLayoutProps,\n  } = useEpg({\n    epg,\n    channels,\n    startDate: '2022/02/02', // or 2022-02-02T00:00:00\n  });\n\n  return (\n    \u003cdiv\u003e\n      \u003cdiv style={{ height: '600px', width: '1200px' }}\u003e\n        \u003cEpg {...getEpgProps()}\u003e\n          \u003cLayout\n              {...getLayoutProps()}\n              renderTimeline={(props) =\u003e \u003cTimeline {...props} /\u003e}\n            /\u003e\n        \u003c/Epg\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n\nexport default App;\n```\n\n## renderTimeline - RTL direction\n\nBelow is an example that allows you to render your custom Timeline component using Plaby's style components.\n\n```tsx\nimport {\n  TimelineWrapper,\n  TimelineBox,\n  TimelineTime,\n  TimelineDivider,\n  TimelineDividers,\n  useTimeline,\n} from 'planby';\n\ninterface TimelineProps {\n  isRTL: boolean;\n  isBaseTimeFormat: boolean;\n  isSidebar: boolean;\n  dayWidth: number;\n  hourWidth: number;\n  numberOfHoursInDay: number;\n  offsetStartHoursRange: number;\n  sidebarWidth: number;\n}\n\nexport function Timeline({\n  isRTL,\n  isBaseTimeFormat,\n  isSidebar,\n  dayWidth,\n  hourWidth,\n  numberOfHoursInDay,\n  offsetStartHoursRange,\n  sidebarWidth,\n}: TimelineProps) {\n  const { time, dividers, formatTime } = useTimeline(\n    numberOfHoursInDay,\n    isBaseTimeFormat\n  );\n\n  const renderTime = (index: number) =\u003e (\n    \u003cTimelineBox key={index} width={hourWidth}\u003e\n      \u003cTimelineTime isBaseTimeFormat={isBaseTimeFormat} isRTL={isRTL}\u003e\n        {formatTime(index + offsetStartHoursRange).toLowerCase()}\n      \u003c/TimelineTime\u003e\n      \u003cTimelineDividers\u003e{renderDividers()}\u003c/TimelineDividers\u003e\n    \u003c/TimelineBox\u003e\n  );\n\n ...\n}\n\n```\n\n## Theme\n\n### Schema\n\nMake your theme custom. Below is theme schema that you can pass as one of the options to `useEpg` hook.\n\n```jsx\nconst theme = {\n  primary: {\n    600: '#1a202c',\n    900: '#171923',\n  },\n  grey: { 300: '#d1d1d1' },\n  white: '#fff',\n  green: {\n    300: '#2C7A7B',\n  },\n  loader: {\n    teal: '#5DDADB',\n    purple: '#3437A2',\n    pink: '#F78EB6',\n    bg: '#171923db',\n  },\n  scrollbar: {\n    border: '#ffffff',\n    thumb: {\n      bg: '#e1e1e1',\n    },\n  },\n  gradient: {\n    blue: {\n      300: '#002eb3',\n      600: '#002360',\n      900: '#051937',\n    },\n  },\n  text: {\n    grey: {\n      300: '#a0aec0',\n      500: '#718096',\n    },\n  },\n  timeline: {\n    divider: {\n      bg: '#718096',\n    },\n  },\n};\n```\n\n## All import options\n\n```tsx\nimport {\n  Epg,\n  Layout,\n  ChannelBox,\n  ChannelLogo,\n  ProgramBox,\n  ProgramContent,\n  ProgramFlex,\n  ProgramStack,\n  ProgramTitle,\n  ProgramText,\n  ProgramImage,\n  TimelineWrapper,\n  TimelineBox,\n  TimelineTime,\n  TimelineDividers,\n  useEpg,\n  useProgram,\n  useTimeline,\n  Program, // Interface\n  Channel, // Interface\n  ProgramItem, // Interface for program render\n  Theme, // Interface\n} from 'planby';\n```\n\n## License\n\nCustom License - All Rights Reserved. [See `LICENSE` for more information](https://planby.app/docs/planby-license.pdf).\n\n## Contact\n\nKarol Kozer - [@kozerkarol_twitter](https://twitter.com/kozerkarol)\n\nProject Link: [https://github.com/karolkozer/planby](https://github.com/karolkozer/planby)\n","funding_links":["https://github.com/sponsors/karolkozer","https://opencollective.com/planby"],"categories":["TypeScript","Projects using `@faker-js/faker`"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarolkozer%2Fplanby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkarolkozer%2Fplanby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarolkozer%2Fplanby/lists"}