Haml calendar
While I was looking through the Haml docs today, I found the ability to print out the date. My gears started spinning. Why not create a calendar?
See the Pen Haml Calendar by Katy DeCorah (@katydecorah) on CodePen
It took a lot of research, but I made a functioning Haml Calendar. I say functioning, because it will display the correct date and tomorrow it will automatically display tomorrow’s date. You may also change the month, year, and day variables to display a specific date.
I realize this is not a practical calendar solution, but it was fun to figure out.
I used these shots from Dribbble for layout and color inspiration.
Starting out
The first step: print out today’s date. Once I got that, I created variables for month, year, and day that default to today’s date unless otherwise specified. I also created an array @days
to hold the days of the week in the order I prefer.
I looped through @days
to create the headers for the calendar, but I decided to only display the first letter of each day. I used a list because I find that they are easier to style and they help keep my code organized.
- @days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
%ul.weekdays
- @days.each do |i|
%li.weekday
= i[0]
Next I created a new list for the ordinal days of the calendar using a new loop:
%ul.week
- (1...32).each do |i|
%li.day
= i
I started by printing 31 days (with the start of the month at Sunday for now). I styled the list items so that only 7 can fit in each row. The list items naturally fell into calendar order.
At this point I had a calendar, but it wasn’t correct. August begins on Thursday, not Sunday. I found that if I adjusted the starting value of my loop, I could get the first of the month to start on Thursday - (-3...32).each do |i|
. That works, except now Sunday reads as -3 and so forth. I added a few constraints:
%ul.week
- (-3...32).each do |i|
%li.day - if i > 0
= i
The items that are i <= 0
still exist, but they don’t print a number. Instead they create blank space allowing August to begin on Thursday.
The calendar works, but it’s not dynamic.
Making it Dynamic
I wrote a new variable called monthStart
. Using the date function along with my variables for month and year, I could get the day each month starts on. I wrote another variable to find the position of the first of the month in my @days
array. So in @days
Thursday’s position is 4, but my loop needs to start at -3 for the month to start on that day. I wrote down every day, its position in the array, and what number the loop needs to start on for the month to start on that day. From these findings, I created a formula. I take the negative of the hash and add 1.
- monthStart = Date.new(year, month, 1).strftime("%a")
- @days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
- hashDays = Hash[@days.map.with_index.to_a]
- monthStartNum = hashDays[monthStart]
- adjustMonthStartNum = -monthStartNum + 1
So I updated my loop:
%ul.week
- (adjustMonthStartNum...32).each do |i|
%li.day - if i > 0
= i
To make sure my loop worked, I changed my month
variable to 9 to display September. It worked!
But, September only has 30 days and I’m still printing out 31.
I wrote another variable called monthEnd
. This new variable was slightly easier than monthStart
as I automatically receive an integer.
- monthEnd = Integer(Date.new(year, month, -1).strftime("%d"))
I updated my loop once more (Here I add 1 to monthEnd
to make sure it gets the last day and not up until the last day of the month):
%ul.week
- (adjustMonthStartNum...monthEnd + 1).each do |i|
%li.day - if i > 0
= i
Yay! Dynamic!
Finishing Up
I added a few more constraints when printing out the days to highlight today and to mute the days before today. I think I can write this more efficiently, but I’m ok with my progress so far.
If you edit in CodePen, try writing in a custom date. I commented out the space for you to give it a try.
I really enjoyed figuring this out. I’m new to Ruby, but I think I will do more experimenting!
p.s. I’m not sure about editing the timezone, so it might be a day ahead.