On the screenshot on the homepage https://schedule-x.dev/ the events are touching the left border of the box for the day, but there's a gap between the event and the right border of the box.
Google Calendar does that as well, and I found it quite ugly. I didn't know whether they did it deliberately (maybe I'm the only one who doesn't like it? or maybe there's some functionality associated with that that I haven't worked out?)
So I can't ask the developers of Google Calendar but I can ask you :) Is there a reason for laying out the calendar that way? Or is that just the convention now that Google Calendar does that?
I see you've obviously put thought into the design so I don't think it's an oversight on your part (although it may be on Google Calendar's part).
Took me a while to figure it out, but when I first built the month grid without subtracting a few pixels per event, it got a bit hard to optically make sense of where an event ended and a new one started. This especially since events are also allowed to stretch over multiple days.
Subtracting a few pixels from each event, helps me to quicker grasp that an event ends on a given date, and isn't to be considered "one" with an event in the next day.
Having some white space that pertains to the day, but not to an event, let's you create a new event at the same time of an existing one without having to modify the start hour.
At least that's how I use it.
Have you decided how (or if) you're going to handle recurring events? Because that has huge implications for how otherwise "simple" changes to events behave, both from whatever backend you use as well as the UI.
I intend to implement event recurrence, but this is definitely one of those things which will require changes across most packages of the project code. The details of how it will be implemented is still open :) Will surely look to other open source calendars for inspiration. Do you have any tips on solutions/APIs you like?
While iterative development is the best way, there's something to be said for staring at a whiteboard full of the most common calendaring use cases, and being sure before starting the basics that the data model and code factoring "plan" support foreseeable uses, particularly "must have" ones.
This gets lost sight of in most Agile™ teams, maybe even more so than with solo-dev.
One way to do this in a reasonably light and OSS-friendly way is to pre-write the essential features README for the tool (event recurrence is an essential calendaring feature), then go through and mark them as TODO or blank checkboxes or etc., letting people contribute.
If you've architected the code structure a bit towards those things, the contributions / PRs are easier too, as the third party contributor isn't trying to refactor out from under everyone.
a) I had full control of the back-end, so my solution was ultimately fully custom -- I don't have any APIs to point to, sorry.
b) Look at the iCalendar specification if you haven't already if for no other reason than to see what kinds of crazy corner cases they were expecting to support.
c) Generally speaking, making recurring series of events ('recurrence sets' or 'rsets') is "easy", but altering rsets will make you want to kick a small animal. I'm just going to throw out a couple of examples to indicate how annoying this can be.
Assuming each event is in a rset. 1) I move an event on a week calendar from Tuesday to Thursday. Is there an event in the rset in the preceding week that should now be visible on my calendar? 2) I move an event in a series recurring on T/R from T->R. Is the set now R/Sa or is it still T/Th? 3) Do I permit changes to a single event while still allowing it to be a member of its recurrence set (iCalendar allows this!)? More to the point, do subsequent changes of that rset affect the event that you've now changed? 4) I move event from a T/R rset to a Friday. Does it even exist anymore? It's not on a Thursday or Tuesday after all (not joking!). And there are so many "gotchas" of this variety.
Granted, a lot of this complexity will be the job of the backend, for which you may or may not be responsible. But you still need to affirmatively decide if you're going to ask the user if they want to make a ("this"/"this and following"/"all") type of edit on certain actions and what an action maps to in terms of the API you're using. And if you ever want to implement your own backend, you're locked into that decision and you might hate yourself later.
As for my personal solution (again, I was writing the backend): Most calendar implementations of recurring events (if the iCalendar specification is followed) comprise a "base" event and a recurrence rule from which the other events may be calculated. I personally settled on a much more rudimentary solution where each event was initially calculated via a recurrence rule but was stored a first-class entity in my database. I also prohibited changing the recurrence rule of for a set of events that was already created. This made it so that the recurrence rule actually had no semantic meaning besides at creation. The individual events were linked in a "group" and things like drag and drop operations were done just by computing the time delta and shifting each individual event by that amount. I NEVER regretted making my calendar "dumber" and almost always regretted making it more clever.
A last word of warning -- if you do not know precisely the "specification" you want to achieve in terms of what actions are permitted on rsets, you are 100% going to rewrite it multiple times (ask me how I know :p).
Also I wanted to lean more towards the Material Design 3 specification.
Tweets to Self.
I text or email myself all the time, setup a feed to watch your tweets to yourself with the calendar events - it gets stored on twitter infra, accessible via browser, client, whatever, sharable, screenshotable and can be made private - and you just subscribe the calendar to that feed and replicate the tweet's payload into your offline, personal calendar from the feed.
Tweets are already timestamped - and for self and the following, BlueChecks can be used to ensure that event invites are only from validated people, or whitelist invites from only those you follow...
Others could invite you via tweets, and have "invites" show up in a bucket/panel in your calendar, and you can click to add them to the calendar and autotweet an RSVP/Reject via same.
Our CFO left our company to work at a large investment fund. As usual, I would have removed her from our Gsuite, but the C-levels wanted to keep the email so we could still access her contacts and "impersonate" her in ongoing deals. She created a new password, sent it to us, and stopped using the account.
However, two years passed and some calendar events started to appear. They were from an unknown user but with the old CFO's email, involving random professional meetings with random people. We called her, and she said that she didn't have the account credentials or even the cellphone she previously used.
So we did what most companies do: We ignored it.
Fast forward a few months, our head of marketing was at a startup event with investors when a guy he didn't know introduced himself. He was from another company in the same market as ours and was concerned that he had started negotiating to buy an IP from us but we stopped responding. We had never sold any IP, so my coworker asked with whom he had been talking. Of course, it was with the impersonator. When we checked the email, there weren’t any recent emails sent or received. Weird.
A few days later, we called him to the office, offered him some coffee, and he showed us the conversation. It contained a lot of internal details, a full 9-page PDF with specifications and valuation, pricing, and payment details, with the payment destination being our company's account!
It didn't make any sense. It wasn’t just an error. It wasn’t just a scam. Why would the person direct the money to us?
We tried to investigate, but with many things on our plate, the mystery was again sidelined.
A few weeks later, we had a large sales event inland. By local legislation, all events of a certain size must have a paramedic present. We hired a recent college graduate for this role. She reported some sexual harassment from the construction workers we had hired to build the stage and event structure. As we were investigating this and talking with the authorities, we noticed some calendar events between the medic and the impersonator. Our CEO joined one of these meetings, with me beside him at his desk. Neither party turned on their camera. The impersonator's voice, calm and professional, stated that since our CEO had joined the meeting, he could leave the rest to him and then exited the meeting. We talked to the medic; the impersonator had offered her the equivalent of 20k dollars to not make any public claims about the harassment. We had never discussed any of this during our board meetings.
We started to panic. What else could the impersonator have done? How long had he been posing as us?
We contacted a security company to investigate. They deployed four agents who began to analyze data, track everyone, call people for interrogation, and so on.
In a couple of days, they identified a 23-year-old guy from accounting as the impersonator. We called him into a meeting with all directors. He was visibly nervous but explained his story. A few months before joining the company, he had bought a used cellphone online, on an eBay-like website. This cellphone had belonged to the former CFO, who hadn't wiped it before selling. He began reading the saved emails and documents and got excited about the company's strategy, then applied and got the job. He even shared this story with his recruiter (as in "look at God's will"), but nobody reported it to us, as it seemed irrelevant.
So, he occasionally received emails and acted on them, with the best intentions. He actually had the authority to send and receive money, since he worked in the accounting department. He said that initially, he would ask for advice on what to do, but never received any good suggestions, so he stopped asking. From the first CFO to him, we had two other CFOs. Apparently, during this time, we also had a shadow one. He solved many issues, from workers asking for money to renegotiating payment deadlines. He was actually very good at it.
He showed us all the emails and deals he made, and everything was, in fact, recorded in our system, with invoices sent and everything.
The directors debated whether what he had done was good, bad, illegal, and whether he should receive a reward
, etc.
We voted and then promoted him to a position akin to vice-CFO and gave him a substantial bonus, considering all the legal expenses he saved us.
I left the company a few months after that, but I heard he went on to work at a 'cool' startup, I think Notion or Spotify, something like that.
He was a very intelligent and humble guy, and we met him just because of a series of coincidences with a calendar app.
How were you able to overcome this challenge?
Solving overlapping events was definitely one of the things were a couple of days went into finding a nice and performant solution. My solution is here: https://github.com/schedule-x/schedule-x/blob/main/packages/...
Basically what I do is iterate over a list of events, sorted by start time, and for each: 1) figure out if it has an overlap with its next 2) if no, all good -> do nothing. If yes: 3) recursively check upcoming events until none is found with an overlap. 4) for each event in the recursion, set an integer property for how many previous overlapping events there were 5) Use this integer property for adjusting the position of the event with CSS
I know you're following Google Calendar but I think Hey has some great ideas here :)
It's so weird, I don't know why almost all calendars have this bonkers design. We don't paginate web documents anymore. Why calendars?
Google actually got this right at one point with their Android app (the open source one), but then they broke it again with the newer closed source app!
But when I think about it, it absolutely makes sense. I'll definitely consider if this should be the default behavior of the month grid in v2.
Thanks a lot for your input!
Small suggestion for the date picker:
I appreciate that you can click on the month+year to navigate between years much more quickly than using the previous/next month arrows, but it's a bit non-obvious. There should be a hover effect when the cursor is over the month+year, e.g. a gray rounded rectangle, just like a gray circle appears when you're hovering over the arrows or a date. This would make it clearer that this is clickable.
Yes, as of now, the demo does not utilize the APIs for adding, editing or removing events. But this definitely helps me understand that it might make sense to do so! I'll put this in the project backlog; the APIs exist, the demo just doesn't use them.
And about the gotchas: Yea, I feel ya! This is my third stab at building a regular event calendar. At work I also build scheduling tools. Still, I discover these gotchas anew on a regular basis.
Most important learning so far, which also costed me the most before I knew it, was to always run my CI-pipelines in different time zones.
I find calendars to be interesting projects for some reason. I built one for a personal project recently using Phoenix LiveView and have really enjoyed it a lot.
See Kiko.
Does it integrate into existing calendar to make it more seamless to leverage the web calendar?
Do you mean if any existing calendar can be used a backend? In that case, not out of the box. But I do intend to build a plugin for using Google Calendar as a backend.
Resizing is one of the next tasks in my backlog.
could this someone be rendered as a component in a react app ?
There is a dedicated React component for this: https://schedule-x.dev/docs/calendar/react