Code Monkey home page Code Monkey logo

planby's Introduction

Description

Planby 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.

Codesandbox example

Live example - Codesandbox

Live example - Typescript Codesandbox

Live example - website with control panel

Testimonials

๐Ÿš€ Become a Sponsor! ๐Ÿš€

Become a sponsor, support, and help us in continuing our development. -> Opencollective

Getting Started

Installation

  • yarn
yarn add planby
  • npm
npm install planby

Usage

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/02', // or 2022-02-02T00:00:00
});

return (
  <div>
    <div style={{ height: '600px', width: '1200px' }}>
      <Epg {...getEpgProps()}>
        <Layout
          {...getLayoutProps()}
        />
      </Epg>
    </div>
  </div>
);

or

Custom width and height

const {
  getEpgProps,
  getLayoutProps,
  ...
} = useEpg({
  epg,
  channels,
 startDate: '2022/02/02', // or 2022-02-02T00:00:00
  width: 1200,
  height: 600
});

return (
  <div>
     <Epg {...getEpgProps()}>
        <Layout
          {...getLayoutProps()}
        />
      </Epg>
  </div>

or

Time range

const {
  getEpgProps,
  getLayoutProps,
  ...
} = useEpg({
  epg,
  channels,
  startDate: '2022-02-02T10:00:00',
  endDate: '2022-02-02T20:00:00',
  width: 1200,
  height: 600
});

return (
  <div>
     <Epg {...getEpgProps()}>
        <Layout
          {...getLayoutProps()}
        />
      </Epg>
  </div>

API

useEpg

Options

Available options in useEpg

Property Type Status Description Access
channels array required Array with channels data
epg array required Array with EPG data
width number optional EPG width
height number optional EPG height
sidebarWidth number optional Width of the sidebar with channels
timelineHeight number optional Height of the timeline PRO
itemHeight number optional Height of channels and programs in the EPG. Default value is 80
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 -> dayWidth
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
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
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
initialScrollPositions object optional Set initial scroll position in Layout, e.g., initialScrollPositions: { top: 500, left: 800 } PRO
liveRefreshTime number optional Live refresh time of the events. Default value is 120 sec. PRO
isBaseTimeFormat boolean optional Convert to 12-hour format, e.g., 2:00am, 4:00pm, etc. Default value is false.
isCurrentTime boolean optional Show current time in Timeline. Default value is false. PRO
isInitialScrollToNow boolean optional Scroll to the current live element. PRO
isVerticalMode boolean optional Show Timeline in vertical view. Default value is false. PRO
isResize boolean optional Possibility to resize the element. PRO
isSidebar boolean optional Show/hide sidebar
isTimeline boolean optional Show/hide timeline
isLine boolean optional Show/hide line
isRTL boolean optional Change direction to RTL or LTR. Default value is false. PRO
theme object optional Object with theme schema
timezone object optional Convert and display data from UTC format to your own time zone PRO
areas array optional Area gives possibilities to add field ranges to the Timeline layout. PRO
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
overlap object optional Enable the element overlaps in the layout. Mode values: stack/layer, layerOverlapLevel: number PRO
drag and drop object optional Drag and move the element in the layout. Mode values: row/multi-rows PRO
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
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
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
globalStyles string optional Inject custom global styles and font. Font weight: 400,500,600. Default font is "Inter" PRO

Note about width and height props

Without declaring the width and length properties, the component takes the dimensions of the parent element.

globalStyles

Inject own custom font and other global styles.

const globalStyles = `
  @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap");

/* Available in PRO plan */
 .planby {
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";

  /* Layout */
  .planby-layout {}

  /* Line */
  .planby-line {}

  /* Current time */
  .planby-current-time {}
  .planby-current-content {}

  /* Channels */
  .planby-channels {}

  /* Channel */
  .planby-channel {}

  /* Program */
  .planby-program {}
  .planby-program-content {}
  .planby-program-flex {}
  .planby-program-stack {}
  .planby-program-title {}
  .planby-program-text {}

  /* Timeline */
  .planby-timeline-wrapper {}
  .planby-timeline-box {}
  .planby-timeline-time {}
  .planby-timeline-dividers {}
  .planby-timeline-wrapper {}
}
  
`;

Instance Properties

Properties returned from useEpg

Property Type Description
scrollY number Current scroll y value
scrollX number Current scroll x value
onScrollLeft function(value: number) Default value is 300
onScrollRight function(value: number) Default value is 300
onScrollToNow function() Scroll to current time/live programs
onScrollTop function(value: number) Default value is 300

Channel schema

Property Type Status
logo string required
uuid string required

Epg schema

Property Type Status Description Access
channelUuid string required
id string required
image string required
since string required
till string required
title string required
fixedVisibility boolean optional The element is always visible in the layout during the scroll events Sponsors

Epg

Base props

Available props in Epg

Property Type Description Status
isLoading boolean Loader state optional
loader Component Loader custom component optional

Layout

Base props

Available props in Layout.

Property Type Description Status Access
renderProgram function({ program: { data: object, position: object}) data object contains all properties related to the program, position object includes all position styles optional
renderChannel function({ channel: { ..., position: object}) channel object contains all properties related to the channel, position object includes all position styles optional
renderTimeline function({sidebarWidth: number}) sidebarWidth value of the channel's sidebar width optional
renderLine function({styles: object}) basic styles and position values for the custom live tracking Line optional Sponsors
renderCurrentTime function({styles: object, isRTL: boolean, isBaseTimeFormat: boolean, time: string}) basic styles values for the custom current time optional Sponsors

Render functions

You 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.

renderProgram

Below is an example that allows you to render your custom Program component using Plaby's style components.

import {
  useEpg,
  Epg,
  Layout,
  ProgramBox,
  ProgramContent,
  ProgramFlex,
  ProgramStack,
  ProgramTitle,
  ProgramText,
  ProgramImage,
  useProgram,
  Program,
  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', // or 2022-02-02T00:00:00
});

return (
  <div>
    <div style={{ height: '600px', width: '1200px' }}>
      <Epg {...getEpgProps()}>
        <Layout
            {...getLayoutProps()}
            renderProgram={({ program,...rest }) => (
              <Item key={program.data.id} program={program} {...rest} />
            )}
          />
      </Epg>
    </div>
  </div>
);
}

export default App;

renderProgram - 12 hours time format

Below is an example that allows you to render your custom Program component with 12 hours time format using Plaby's style components.

...
const Item = ({ program, ...rest }: ProgramItem) => {
  const {
    styles,
    formatTime,
    set12HoursTimeFormat,
    isLive,
    isMinWidth,
  } = useProgram({
    program,
    ...rest
  });

  const { data } = program;
  const { image, title, since, till } = data;

  const sinceTime = formatTime(since, set12HoursTimeFormat()).toLowerCase();
  const tillTime = formatTime(till, set12HoursTimeFormat()).toLowerCase();

  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,
  isBaseTimeFormat: true,
  startDate: '2022/02/02', // or 2022-02-02T00:00:00
});

...
}

export default App;

renderProgram - RTL direction

Below is an example that allows you to render your custom Program component with RTL direction using Plaby's style components.

...
const Item = ({ program, ...rest }: ProgramItem) => {
  const {
    isRTL,
    isLive,
    isMinWidth,
    formatTime,
    styles,
    set12HoursTimeFormat,
    getRTLSinceTime,
    getRTLTillTime,
  } = useProgram({
    program,
    ...rest
  });

  const { data } = program;
  const { image, title, since, till } = data;

  const sinceTime = formatTime(
    getRTLSinceTime(since),
    set12HoursTimeFormat()
  ).toLowerCase();
  const tillTime = formatTime(
    getRTLTillTime(till),
    set12HoursTimeFormat()
  ).toLowerCase();

  return (
    <ProgramBox width={styles.width} style={styles.position}>
      <ProgramContent width={styles.width} isLive={isLive}>
        <ProgramFlex>
          {isLive && isMinWidth && <ProgramImage src={image} alt="Preview" />}
          <ProgramStack isRTL={isRTL}>
            <ProgramTitle>{title}</ProgramTitle>
            <ProgramText>
              {sinceTime} - {tillTime}
            </ProgramText>
          </ProgramStack>
        </ProgramFlex>
      </ProgramContent>
    </ProgramBox>
  );
};

function App() {

  ...

 const {
  getEpgProps,
  getLayoutProps,
} = useEpg({
  epg,
  channels,
  isBaseTimeFormat: true,
  startDate: '2022/02/02', // or 2022-02-02T00:00:00
});

...
}

export default App;

renderChannel

Below is an example that allows you to render your custom Channel component using Plaby's style components.

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', // or 2022-02-02T00:00:00
  });

  return (
    <div>
      <div style={{ height: '600px', width: '1200px' }}>
        <Epg {...getEpgProps()}>
          <Layout
              {...getLayoutProps()}
              renderChannel={({ channel }) => (
              <ChannelItem key={channel.uuid} channel={channel} />
            )}
            />
        </Epg>
      </div>
    </div>
  );
}

renderTimeline

Below is an example that allows you to render your custom Timeline component using Plaby's style 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;
}

export function Timeline({
  isBaseTimeFormat,
  isSidebar,
  dayWidth,
  hourWidth,
  numberOfHoursInDay,
  offsetStartHoursRange,
  sidebarWidth,
}: TimelineProps) {
  const { time, dividers, formatTime } = useTimeline(
    numberOfHoursInDay,
    isBaseTimeFormat
  );

  const renderTime = (index: number) => (
    <TimelineBox key={index} width={hourWidth}>
      <TimelineTime>
        {formatTime(index + offsetStartHoursRange).toLowerCase()}
      </TimelineTime>
      <TimelineDividers>{renderDividers()}</TimelineDividers>
    </TimelineBox>
  );

  const renderDividers = () =>
    dividers.map((_, index) => (
      <TimelineDivider key={index} width={hourWidth} />
    ));

  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', // or 2022-02-02T00:00:00
  });

  return (
    <div>
      <div style={{ height: '600px', width: '1200px' }}>
        <Epg {...getEpgProps()}>
          <Layout
              {...getLayoutProps()}
              renderTimeline={(props) => <Timeline {...props} />}
            />
        </Epg>
      </div>
    </div>
  );
}

export default App;

renderTimeline - RTL direction

Below is an example that allows you to render your custom Timeline component using Plaby's style components.

import {
  TimelineWrapper,
  TimelineBox,
  TimelineTime,
  TimelineDivider,
  TimelineDividers,
  useTimeline,
} from 'planby';

interface TimelineProps {
  isRTL: boolean;
  isBaseTimeFormat: boolean;
  isSidebar: boolean;
  dayWidth: number;
  hourWidth: number;
  numberOfHoursInDay: number;
  offsetStartHoursRange: number;
  sidebarWidth: number;
}

export function Timeline({
  isRTL,
  isBaseTimeFormat,
  isSidebar,
  dayWidth,
  hourWidth,
  numberOfHoursInDay,
  offsetStartHoursRange,
  sidebarWidth,
}: 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>{renderDividers()}</TimelineDividers>
    </TimelineBox>
  );

 ...
}

Theme

Schema

Make your theme custom. Below is theme schema that you can pass as one of the options to useEpg hook.

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',
    },
  },
};

All import options

import {
  Epg,
  Layout,
  ChannelBox,
  ChannelLogo,
  ProgramBox,
  ProgramContent,
  ProgramFlex,
  ProgramStack,
  ProgramTitle,
  ProgramText,
  ProgramImage,
  TimelineWrapper,
  TimelineBox,
  TimelineTime,
  TimelineDividers,
  useEpg,
  useProgram,
  useTimeline,
  Program, // Interface
  Channel, // Interface
  ProgramItem, // Interface for program render
  Theme, // Interface
} from 'planby';

License

Custom License - All Rights Reserved. See LICENSE for more information.

Contact

Karol Kozer - @kozerkarol_twitter

Project Link: https://github.com/karolkozer/planby

planby's People

Contributors

christiaanscheermeijer avatar karolkozer avatar theritikchoure avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

planby's Issues

Error in Next.js

When I try example from this codesandbox in my Next.js appliation it throws an error:

next-dev.js?878b:20 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Check the render method of EPG.

Can we use it for react-native?

Hi, @karolkozer! The project is really good, Stated using it for the web and it is working fine, But for me, I need to use it in a react-native application is there any way to use the same library or is there any alternative library for the react-native application?

Thanks in advance!

Should not inject global styles

Thanks for making this library! I noticed that it will always inject global styles including a web font when rendered. This makes the component look nicer but it affects other parts of the application.

It would be great to scope some of the styles to the component itself, and let the user to add the global styles and fonts by themselves.

Better program separation for different channels

I'm implementing a sortable drag and drop on the timeline, using dnd-kit
I want to be able to reorded my timeline items in the channel row (not across channels)

This is how I currently implemented it:

            <DndContext
                sensors={sensors}
                collisionDetection={closestCenter}
                // onDragEnd={recalculateRoutes}
                modifiers={[restrictToHorizontalAxis]}
            >
                <SortableContext items={epg} strategy={horizontalListSortingStrategy}>
                    <Epg {...getEpgProps()} isLoading={loading}>
                        <Layout
                            {...getLayoutProps()}
                            renderProgram={
                                ({ program, ...rest }) => (
                                    <TimelineItem
                                        key={program.data.id}
                                        program={program}
                                        {...rest}/>
                                )
                            }
                        />
                    </Epg>
                </SortableContext>
            </DndContext>

TimelineItem is a simple component that follows the dnd-kit docs, with the useSortable hook

The problem is that I can only create one SortableContext, that includes the entire epg: so when I try to rearrange one item, it jumps the items from the other channels

Here is an image of my timeline, with no interaction:
image

Here is an image when I'm moving an item from the second channel. Note how the items from the first channel jumped to the beginning:
image

Note: all the items have different ids

Basically if I could implement a per-channel wrapper, to which I pass in the TimelineItems as children, I would be able to create one context per channel.
Around the same lines as the other render props on layout, a renderChannelRow:

const renderChannelRow: (({children}: {children: ReactNode}) => ReactNode)

What do you think?

Import XML guide data

I'm trying to understand how I can convert XML data to the EPG array data that is required? Has anyone successfully done this with a code sample?

How do I override the styling of a specific component?

Hi and thanks very much for making this library! I've read through the docs and the examples, but I couldn't quite figure out to do this... hopefully a simple question?

Is there a way to override the styling on a specific component, like the hover color of a <ProgramContent>? I tried editing the theme file, and that let me change the gradient colors -- but that affects both the ProgramContent hover color and the timeline background.

I see that the programs have a class of css-nsqzgd-ProgramContent, but I'm not sure how to target that randomly generated nsqzgd part or what system is generating it.

In our codebase we're using MUI and styled-components, and I was able to wrap <ProgramContent> with a styled component and give it a hover: { background: red !important}, but that just doesn't seem like the right way of doing it.

Is there a built-in way to override CSS rules for a specific component?

Thank you!

How to not complete...

Its not so easy to create exact sample as on your website.

Could you explain how to do the following:

  1. highlight programs that are live now
  2. show the live line
  3. scroll to the live programs

We are using it the for TV Guide data

Grouping/Tree Data for Planner?

I want to be able to group objects under one, or better said make a tree system where one planner is under another.
image
For example, Auditorium D in this scenario has rooms under it. I would appreciate the ability to create something like this where I am able to sort items under another, since in my software, we need to see what employees under an employee are doing, and having this grouping system would be very nice.

Compared to the screenshot, I would actually appreciate it more if there was an option to not add events for Auditorioum D in that instance, and rather only to the items under it, since I don't want to be able to add events to the actual employee, but rather to the employees under that employee.

"Invalid time value" error when startDate to endDate > 1 day and `isBaseTimeFormat` = true

Planby is crashing when the start to end date range exceeds 24 hours and isBaseTimeFormat is true:

image

I think this might be related to #32 and #5 ? If so, is the solution to:

  • Sponsor the project for multi-day functionality (I'll ask the bosses about that!)
  • Not use 12-hour time, OR keep isBaseTimeFormat set to false but then use custom render methods to show 12-hour time?

It seems like even in that case, though:

  • Multi-day support in the documentation could be reworded, maybe? e.g. for the endDate prop, instead of "Endless scroll through multiple days available only for Sponsors" (which makes it sound like it's related to async endless loading), maybe "Must be within the same 24-hour period as startDate. Support for multiple days is available only to Sponsors"?
  • The conflict with isBaseTimeFormat shouldn't crash the app? I'm not too sure how that prop works (it's just a boolean) but it seems like it's affecting both date input/parsing datestrings in addition to output formatting; the two should be separate concerns, I think?

I'm going to talk to my bosses about possible sponsorship, and then maybe spend some time in the source to see if I can help locate the crash issues.

Thanks again for this library!

Feature Request : Option to set timeline dividers to daily, weekly, monthly

Hey Planby Team(@karolkozer ),

We wanted to take a moment to express our admiration for Planby. It has been an invaluable tool for our team as we use it to visualize due dates set by users in our video planning and editing app. The flexibility and customization options that Planby offers have been incredibly helpful for us and we are grateful for the work you have put into creating such a fantastic product.

As we continue to use Planby, we have identified a feature that we believe would further enhance its capabilities. Currently, the timeline dividers are set to hourly. However, we have identified a need for custom timeline dividers that include daily, weekly, and monthly options as well. We believe that this added feature would make Planby even more versatile and useful for a wider range of users and use cases.

An example would be such:

Pre-production date: Feb 27th, 2023
Production date: March 12th, 2023
Post-production: March 15th, 2023
...

For the above we would visualize the date type as channels and the dates as programs associated with the channels

We would love to know your thoughts on this feature request and would be happy to contribute in any way that we can to help make it a reality. We understand that developing new features takes time and resources, so we want to make sure that this is something that aligns with your vision for Planby before we proceed.

Please let us know your thoughts and if there is anything we can do to assist with this request. Thank you.

Plans to support Vue JS?

I'm a Vue JS developer and it will be great for me to integrate this amazing library to my project.

Dynamic height render is broken

Hi and thanks for this library!

I'm working on an implementation and seems that without a concrete fixed pixel height the channels/programs do not render properly.

Replicated by forking your codepen and just changing Epg container height to "auto":
obraz
https://codesandbox.io/s/planby-epg-demo-forked-001b8r?file=/src/App.js

Only the first channel is rendered, the rest of the channels are missing, space seems to be calculated correctly for them but it's all empty.
obraz

Interestingly, if I modify the code to force a hot reload it renders correctly, so seems like something related to the initial render.

Try out initialScrollPositions feature

Hey karolkozer,

I love Planby and I'm trying to use it for an EPG timeline in a React application on smart TVs. I've got an issue where I'd like to switch pages and come back to the same position in the planby grid as I was before. I noticed that there's an initialScrollPositions property that I might be able to use for this purpose.

Is there any way I can confirm that this would work? If it does, I think I can convince my company to become a sponsor for this project! Let me know.

Time format

Hi Karol,

Iโ€™m currently working on using your EPG component on a project Iโ€™m working on. Iโ€™m running into an issue where when I pass in the time for any of the props you exposed using the useEPG hook I get the following error:

image
image

Transformed Data

Iโ€™m using the following to transform my time value from a number in ms to the format you specified in your docs. However the only time the epg is actually working is when Iโ€™m passing in static time stamps.

image

Code snippet where Iโ€™m formatting the dateTime

Could you shed some light on what I can do to get past this issue?

Capturing the Epg click event to see the detail ?

Hello, everyone!
Thank you for creating such an awesome product.

I'm unsure how to implement the onClick event for an Epg item to display its details, similar to what is demonstrated in the demo page (referencing this picture)
image

I'm not certain if this feature is exclusive to the PRO version, as I couldn't find its implementation in the Codesandbox example

Could you please guide me on how to implement this functionality? Thank you so much!

Bug: isLine is not drawn on day ranges that contain two or more days

scenario:
Define a date range which contain two different dates
startDate: 2022-02-02T12:00:00
endDate: 2022-02-03T12:00:00
isLIne: true

expected behavior:
The line gets drawn when the local time changes from 2022-02-02T23:59:59 to 2022-02-03T00:00:00. Also the view is scrolled to the live edge if the given condition is met.

actual behavior:
The line is NOT getting drawn when the local time changes from 2022-02-02T23:59:59 to 2022-02-03T00:00:00. The view is not longer scrolled to the live edge if the given condition is met.

Thx

When i set time between box less than 30s ProgramItem will disappear

const epg = useMemo(
        () => [
            {
                id: '6f3caa7f-5b11-4edb-998e-80d4baa03372',
                description:
                    "Bounty hunter Boba Fett & mercenary Fennec Shand navigate the underworld when they return to Tatooine to claim Jabba the Hutt's old turf.",
                title: 'Jingle',
                isYesterday: true,
                since: '2022-02-02T00:00:00',
                till: '2022-02-02T00:00:30',
                channelUuid: '16fdfefe-e466-4090-bc1a-57c43937f826',
                image: 'https://www.themoviedb.org/t/p/w1066_and_h600_bestv2/sjx6zjQI2dLGtEL0HGWsnq6UyLU.jpg',
            },
            {
                id: '6f3caa7f-5b11-4edb-998e-80d4baa03373',
                description:
                    "Bounty hunter Boba Fett & mercenary Fennec Shand navigate the underworld when they return to Tatooine to claim Jabba the Hutt's old turf.",
                title: 'Spot',
                isYesterday: true,
                since: '2022-02-02T00:01:00',
                till: '2022-02-02T00:01:29',
                channelUuid: '16fdfefe-e466-4090-bc1a-57c43937f826',
                image: 'https://www.themoviedb.org/t/p/w1066_and_h600_bestv2/sjx6zjQI2dLGtEL0HGWsnq6UyLU.jpg',
            },
        ],
        []
    );
      const [dayWidth, setDatWidth] = useState<number>(270000);
    const { getEpgProps, getLayoutProps, onScrollToNow, onScrollLeft, onScrollRight } = useEpg({
        theme: customTheme,
        epg,
        channels,
        isSidebar: true,
        isTimeline: true,
        dayWidth: dayWidth,
        isLine: true,
        startDate: '2022-02-02T00:00:00',
        height: 300,
    });

Screen Shot 2565-12-08 at 16 59 10

DND overlay changes and card lock

Hi @karolkozer! Wonderful project, I started to work with your library recently. The API looks great, it's easy to understand, and to customize. But I have several questions, about how to get some features:

  • Is it possible to lock a few cards to have the opportunity to drag and drop them all at once?
  • When I move a card to a small gap, the row is getting extended. Is it possible to restrict row extension and just move the card back to the initial position in this case?
  • The same with card resizing, if the user tries to resize a card and does not have enough space - the row extends. It is possible to restrict row extension in this case too?

TimeLine after 24h keep counting 25,26,27...

Hello,
I am using Planby lately and i really appreciate your work but i have some problems with timeline . When the difference of startTime and endTime is larger then 24h (1day) the timeline keep counting 25,26,27... and not starting from 0 again .
Can you suggest me any solution ?
Thank you!
image

Feature Request: Single-channel/track program/event list

I can't believe how much fun this is! I've seen cool stuff added since last time I checked out the demo - thanks so much :)

Have/would you consider a single set of entries listed with associated details? The concept being that a user clicks on (for example) a channel logo, which then presents a more detailed listing of its own?

A mockup would explain this way better than I can elucidate:
Click

Result

Change style of Line & add time to Line

Hello and many thanks for this fantastic library, author! This library has been on my search list for a while :)

I want to customize style of Line component, such its color and width, but I'm not sure how. Would you kindly assist me?

Can we also have an option to display the current time at the top of the Line? Thank you, I truly need this for my project. Like the picture below:

image

Light Theme

Hi,

Are there any place to get an example for a light theme?

Regards

Cannot go past 1 day

I set
startDate: 2023-02-09T11:24:50 and endDate: 2023-02-10T10:24:50
and I get Invalid time value

Do start and end date have to be on the same day? I am not seeing this documented anywhere. Thanks

CRUD scheduling

Question/feature request: Is it possible to add scheduling capabilities or use planby for a scheduling tool? I mean changing the channel of an item via drag and drop / editing the start and end of a program.

Improvements

Hi @karolkozer! Great project, started using it last year, I believe I had asked you to be able to edit the width of the timeline. I love the simplicity and the design of it, and recently forked it to make some changes that were required for my specific use case.

Wanted to use this issue as a checklist to create PRs for the features I added/want to add to the fork:

  • Forward Refs to Content, Scrollbox, Channels, and Timeline
  • Custom Loading Animation
  • Support endless scroll (across multiple days)
  • Demo for integration with DnD-Kit

renderTimeline not working/not implemented

It seems in the latest release 0.2.1 renderTimeline override just doesnt execute. First hint was styled component
as written in the readme section not implemented within "planby" module

Divide timeline into half hour blocks

Divide timeline into half hour blocks, I think it could be nice. Thanks.

I already code some lines to fix for now my need:

export function Timeline({
    isSidebar,
    dayWidth,
    hourWidth,
    sidebarWidth,
    className,
    numberOfHoursInDay
  }) {
    const { time } = useTimeline(numberOfHoursInDay * 2);

    const renderTime = (hour) => {
      return (
        <TimelineBox key={hour} width={hourWidth / 2} className="timelineBox">
          <TimelineTime className={`timelineTime ${className}`}>
            {hour}
          </TimelineTime>
        </TimelineBox>
      )
    };
  
    return (
      <TimelineWrapper
        dayWidth={dayWidth}
        sidebarWidth={sidebarWidth}
        isSidebar={isSidebar}
        className="timelineWrapper"
      >
        {time.map((_, index) => {
          const hour = Math.floor(index / 2);
          const oClockHour = `${hour < 10 ? '0' : ''}${hour}`;
          const time = index % 2 === 0 ? `${oClockHour}:00` : `${oClockHour}:30`;
          return renderTime(time, index);
        })}
      </TimelineWrapper>
    );
  }

Error when programme item spans into next day

Hi

When using isBaseTimeFormat=true the "function formatTime" throws an invalid time exception when a programme item spans into the next day e.g starttime 23:50 -> endtime 03:00. When isBaseTimeFormat=false the timeline formatTime function doesnt throw an exception but continues as 23:00, 24:00, 25:00, 26:00, 27:00: see image below
image

However i have found the issue and can be solved by a small update to the internal formatTime function as follows:

`const formatTime = (index) => {
var date = new Date();
var baseDate = format(date, TIME_FORMAT.DATE);
var time = index < 10 ? "0" + index : index;

        /**** Update Code **/
        if(time>23){                
            var timeString = (time - 24).toString();
            time = timeString.length < 2 ? "0" + timeString : timeString;
        }
        /**** End update **/
    
        if (isBaseTimeFormat) {
          var _date = new Date(baseDate + "T" + time + ":00:00");
    
          var timeFormat = format(_date, TIME_FORMAT.BASE_HOURS_TIME);
          return timeFormat.toLowerCase().replace(/\s/g, "");
        }
    
        return time + ":00";
    };

`

Capturing line click event

Hi, I'm trying to implement adding new program to the timeline by clicking specific place on the line and capture the time on that specific place to set program till property.
Is there any way to achieve this?

onScrollToNow cannot be executed

Hi author, I ran into a strange error

The onScrollToNow event does not execute properly after the button is clicked, I have tried other events such as onScrollTop and it works fine.

The code added to the program is as follows

const { ..., onScrollToNow, ... } = useApp();
...
 <IonButton onClick={() => { onScrollToNow(); }} >
    now
  </IonButton>

Here is a demo of the Codepen environment: https://codesandbox.io/s/optimistic-kate-x8rw1e

Front-end rookie requesting help.

Touch events are supported?

I tried the component in the demo from your site, but i see that the touch events don't work.
I have to implement they by myself or there are already developed into the premium version of the component?

Thanks in advance

Change interval of timeline from 24hr?

Hey there, awesome project! Well documented and easy to use. Was wondering if there was a way to override the 24hr default length of the timeline to a custom length/range (starting at 10:00 and going to 14:00 for example). Related, is there a way to override the 24hr time format to a more tradtional 12hr one (so 10:00am - 2:00pm for example)?

Thanks again!

Typing issues using useEpg hook

Hey, I'm trying to integrate this package in my project (I'm using Typescript, react 18.2 and the latest version of planby).
While doing so, I've found that I can't get the hook working with the provided types:

image

I've found that in the useEpgProps,

epg: Program[]; 

but the one imported from the default export is from dist/Epg/index.d.ts (imported as 'ProgramItem as ProgramItemType') and I think it's conflicting with the default type resolution.

image

the indicator line is not visible when program data is provided for 48 hours and when next js server rendering on page reload the indicator line goes back 5 and a half hours(UTC) before the local time.

the indicator line is not visible when program data is provided for 48 hours and when next js server rendering on page reload the indicator line goes back 5 and a half hours(UTC) before the local time.

Hence, need your help to resolve these issue. Please let me know if you need any additional information from my end.

Scroll to specified time on mount

Normally component would directly scroll to current time, but I wanted it to stay at 00:00
Is there any way to change this behavior this? like props :
startAt: Date.now()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.