CalenBear
If you had a blog in the early years of blogging, your theme most certainly had a sidebar. A place for recent posts, a blogroll, a short "about me" note, and possibly a calendar.
You rarely see two or three column blogs these days, and blog calendars are almost extinct. CalenBear brings them back in a modern one-column format.1
It shows your full posting history as a year-by-year calendar, with every day you published clickable. There's also an option to show a few fun stats about your blogging.
Preview
My own blog, from the first post until today:
- Believe in yourself
- Knowember, get to know your blogger
- One more time
- Bear Halloween upvote button
- Stay spooky
- Hope
- Not knowing tomorrow
- My latest Bear theme: Kodiak
- Unusual You
- Precious pauses
- The most precious gift
- The lovely lussebulle
- Stand up for hemorrhoids
- Mental ice age
- Let's make /photo pages
- Happy tears
- No place like home
- Who I blog for
- An open invitation to creation
- Dare to be a weirdo
- The joy of just doing
- All my posts are perfect
- Understandable enough
- Bursting our bubbles
- The secret
- A lagom life
- Opposites attract
- Do your worst
- Successful mistakes
- Birming bulletin #7
- Rain, finally
- World's best dad
- 7,282 visits later
- No autosave for miracles
- Don’t make my blogging mistake
- Write like no one's reading
- Your voice is here
- How do you know that?
- Emptiness
- Evil endless edits
- Pour your words out
- Look how far you’ve come
- What should you blog about?
- What's stopping you?
- Hedgehog Week
- Bad communication
- Your blog is loved
- Share your stories
- Building trust
- Birming bulletin #6
- Day by day discipline
- A flexible mind
- The weight of waiting
- Still here
- The tool trap
- 3 new Bear photo gallery add-ons
- My blogging journey
- Every day has a story
- No harm done
- What digital can’t quite reach
- I guess I’m trash
- Trying to actually be here
- A taste of blogging
- Birming bulletin #5
- Re: Who would ever read this?
- What do you think?
- Paralyzed by possibilities
- The need to win
- Re: Re: Blank blogging counts too
- Let it go
- Bear building in the open
- The backseat blogger
- Lagom
- Blank blogging counts too
- Re: At last, satisfaction
- Restless rating syndrome
- Cats I wish were mine
- From cranky to cappuccino
- Keep blogging, don't worry
- Summer state of mind
- JulyReply Q&A
- Re: Wanting to Write More
- Junited 2026 in numbers
- I feel proud today
- You're a blogger, and that's pretty damn awesome
- App fatigue
- Your blog won't explode
- The simple joy of giving
- A universe of ideas
- Junited blogger? Please let me know
- Swedish archipelago in pictures
- A short pause
- My blogger archetype
- Swedish midsummer in pictures
- Knowledge without understanding
- My blog mess
- Just human
- Why blogging daily feels easier
- Don't wait for flow
- Bad blog posts
- Where do blogs go when they die?
- Celebrating the blogosphere
- Blogging in the dark
- Pick your style in style
- Can't blog? Blog.
- Blogging without pressure
- The luxury of normal
- Technology still feels magical
- Blogging, it's been a minute
- Unpopular posts on Bear blog
- Prettier palettes with previews
- Shifting focus
- Don't let the old man in
- Your blog needs more photos
- Exemplary humanship
- Full of life
- Projects that never ends
- The broken doorbell
- Everything is content
- Trust the process
- Let others know you blog
- The proud painter
- Say yes more often
- This is who I am?
- Why me? Why not?
- Forget about the numbers
- Birming bulletin #4
- First post love
- The complaining kind
- Start writing
- Breathe in, breathe out
- Stay magical
- Just start writing
- Every post is perfect
- Don't fear the upvote button
- Your world, your blog
- A blog is a true friend
- 57 channels
- Don't reject yourself
- How to kill a blog
- It is what it isn't
- Little lies
- From making to creating
- Blog because you want to
- Birming bulletin #3
- Keep walking
- Wear a Bear
- But I care
- A success story
- Don’t practice writing
- Blog without clog
- Keep showing up
- Finding the flow and keeping it
- Bear + Micro.blog = True
- How I use Bear posts and pages
- Writing more in less time
- A little bit of magic
- Be a blog donor
- Posting regularly
- Blogs are alive
- The blog gardener
- Birming bulletin #2
- Stories hiding in plain sight
- Our blogging struggles
- Serious mistakes
- Bloggers inspiring bloggers
- Hit publish
- High five
- Richest blogger in the cemetery
- Nowhere to go
- Birming bulletin #1
- Interesting or interested?
- Coffee, code, and guilt
- What’s your Bear age?
- Reasons to not quit blogging
- Rather ruined than rabies
- It’s okay to quit blogging
- Creativity loves boundaries
- Blogging or thinking about blogging?
- BearRoll, a Bear blogroll
- The cost of not caring
- Entering the blogging spotlight
- The blogging itch
- Getting my blog shit together
- The time tyrant
- Don’t quit blogging for the wrong reasons
- Escape from freedom
- Learning to walk again
- Guestbooks are back
- Writing with doubt
- I found Bear’s home in Thailand
- Just blog
- My travel gear
- Bear upvote button setting
- The real problem
- Not what I’d feared
- Changing negative narratives
- My blogging workflow
- The gift of blogging
- Bearming bulletin no. 2
- Trying not to hit delete
- Too many impressions
- Even monks do it
- Choosing not to choose
- Meditation makes me boring
- Writing while the usual self is asleep
- The idiot behind the wheel
- No electricity, no problem
- Our blogging history
- I found a Bear sticker in Thailand
- True artists stay true
- 443 posts later, still doubting myself
- Being happy is hard
- I give up
- When life cracks open
- Still there, still happy
- I’m not judging, but…
- Ok or no way?
- Ready for takeoff
- The creative breath
- Bloggers unite
- Happy New Year
- Obsession or passion?
- Bear discovery filter idea
- Thank you!
- Mix blogging
- Bear blog or Micro.blog, or both?
- The Swedish semla has arrived
- Bearming bulletin no. 1
- Santa meets modern tech
- A professional answer
- Meeting people
- What’s a winner?
- Sharing the space
- Swedish Tuesday tradition
- How winners get lucky
- When to ship, when to wait
- The invisible audience
- Try more, think less
- No problem problems
- When writing writes itself
- Ten percent feels right
- Swedish Thursday ritual
- New old blog posts
- Quiet quality
- Never blog like me
- Mass mess
- No more phone calls
- Creating without clinging
- Don’t do a bear service
- The richness of blogging
- When play turns into work
- Prisoners of possibilities
- Blinking fuel lights
- Heads-up, I might break your reader
- Your blog, your home
- Enough said
- Getting out of your way
- The beauty of a simple hello
- Writing is a true friend
- A bear-sized dilemma
- What’s a successful blog post?
- Why so serious?
- Getting it out of my head
- Learning to blog with doubt
- A curious heart has no age
- The upside of downtime
- Creativity can't be forced
- The magic around the corner
- Taking things for granted
- The feeling of not having
- Blogging keeps it real
- They call us bloggers
- Go easy on yourself
- Space for the impossible
- Hobbies on the go
- The inner critic
- Write whatever whenever
- Seeing things differently
- Haunted by the to-do list
- Balancing two blogs
- Just be yourself
- Happy cinnamon bun day
- Haunted by ambitions
- The world’s worst blogger
- The guru on the wall
- From rookie to master
- No shortcuts to wonder
- Stay curious
- Life without labels
- The mysterious stranger
- From grumbling to growth
- Publish, don’t polish
- Blogging builds bridges
- Choosing writing
- Making promises
- From problem to perk
- The mess we hide
- Where do thoughts go?
- Catching creativity
- The free ride
- The silent applause
- Not good in group
- Guided by the sandman
- Too many balls in the air
- Why write for an audience?
- The courage to trust ourselves
- The real problem isn’t the problem
- The "just one more" trap
- Passion doesn’t shout
- The kindness of early warnings
- The mysterious people
- My lucky seven
- When worry grows like mould
- The boredom antidote
- Right here, right hiraeth
- Routine beats word counts
- Blogging is beyond age
- Where inspiration lives
- Doing the work
- Most people care
- Writing within limits
- Beauty in the chaos
- The unseen victories
- Finding your own way
- Am I the new asshole?
- Writing it off
- Your blog, your rules
- Our kryptonite
- You have me
- Finding your voice, and keeping it
- Many men called Otto
- My blogging inspiration
- Cookies and blogs
- A suitcase full of dreams
- The balance of just enough
- The bored blogger
- The cost of not listening
- Less time, more blog
- Fungus and flow
- Turning resistance into reward
- Passion as the recipe for success
- Text or talk?
- Can't please them all
- What keeps us going
- It’s not wrong, it’s life
- I want a blog restart
- Beginner's mind
- Finding flavor in life
- Overthinkers non-anonymous
- Blog identity crisis — again
- The lost art of listening
- Re: Starting without a plan
- Dancing with ghosts
- The present
- A lifetime of lessons
- Clarity over chaos
- Setbacks with a purpose
- A place that feels like elsewhere
- The perfection myth
- Learning to live with uncertainty
- Blogs have birthdays too
- I’d rather be a fake millionaire
- Re: IndieWeb is Punk
- JulyReply 2025 is here
- The illusion of overnight success
- The Zen of CSS
- Cherish what you have
- Blogging balance
- True success is daring to fail
- High on low expectations
- A life in motion
- Blog recycling
- Swedish Midsummer: family, frogs & flowers
- Finding my genuine English voice
- The overthinking blogger
- One step at a time
- Never forget to remember
- We all need a hobby
- The simple perfection
- The uplifting burdon of living
- Your Swedish local guide
- Everyone's a genius behind the wheel
- When saying no is the right answer
- Curiosity as a compass
- Celebrating Sweden’s National Day
- Why I remember you
- You have time
- When nothing is everything
- Let's get curious
- The uninvited guest
- You gotta start somewhere
- Finding your own path
- The value of a firm "No"
- Just keep writing
- Balancing our wings
- When sorrow unites
- When blogging feels fake
- The first impression
- The waste of waiting
- The meaning of life
- Is 'then' really better than 'now'?
- The crack in writing
- The gift of absence
- Great Swedish Music
- A love letter to feelings
- The joy of an empty calendar
- Trusting your gut
- Beyond bragging
- When the world is your teacher
- Doing what feels right
- Stop searching, start living
- The recipe for a job you'll love
- Mental mud
- The writer's engine
- The digital hermit
- Jekyll & Hyde: My two blogging worlds
- My most useful skill
- Never stop dreaming
- Writing without a filter
- Nostalgia vs. Reality
- Behind my blog I can be myself
- Feeling non-adult
- Non-stop talkers
- The best blog post ever
- Take care
- Choosing the right blogging platform
- What's an expert?
- Imperfect blogging is perfectly fine
- The rarity of friendliness
- When the words ran out
- Hit the blog button
- The freedom of less
- The hidden treasure of blogging
- The yoga of writing
- Contrast
- Last day in Chiang Mai
- Don’t hold back
- Tiny greatness
- The power of the toothpick
- Stealth blogging
- Lost and found
- Bear blog question challenge
- Time and transformation
- Finding the melody of life
- Here we are
- The fresh start fallacy
- Honesty is the best gift
- Feeling inadequate
- Listen up
- Awakening dreams
- The tyranny of thoughts
- Don't buy me a coffee... yet
- Why blog?
- Just another nothing new to write post
- Nothing new to write
- Guided by tears
- Now and then
- From setback to success
- Truly quiet
- Mini-vacation, maxi-happiness
- Learning from everyone
- Share your shit
- The upsides of English blogging
- My world of confusion
- Free from freedom
- Attentive blogging
- The paradox of desire
- Breaking the cycle of easy choices
- No guarantees
- The silver lining
- Change or accept
- The importance of practical experience
- Growth through challenge
- Collecting comfort
- Breaking free from routine
- Life's on the wire
- Don't say you're too busy to blog
- The trap of quick fixes
- From fear to freedom
- Silent cut
- What are you thinking about?
- Seeing the bigger picture
- The satisfying grind
- Inspired by everyday
- Diverse delights
- Making writing a natural part of our day
- Blogging tattoo
- Blog like a painter
- Blog your way forward
- Writing as meditation
- The all-or-nothing trap
- A taste of Sweden: Celebrating the cinnamon bun
- Where's the fire?
- Creative currents
- A pair of paragraphs
- Snapshot blogging
- You're not me
- Conquering the dread
- Finding strength in sharing
- The right way to be wrong
- From hell to healing
- Comfort zone challenges
- Finding your own path
- The recipe for success
- Prioritized writing
- When to start blogging?
- Blogging without breaking a sweat
- Blog post ideas galore
- The sound of silence
- Make the call
- The curiosity cure
- Rudeness reflections
- To write or not to write?
- Tears of joy
- The freedom of limitations
- Short legs success
- Letting go
- Clever marketing isn't always clever
- The unforeseen
- Purposeful living
- The power of tiny steps
- Our precious time
- Oops, I did it again
- Dear Dad
- From mom with love
- SeptemBest: A quality blog challenge
- Living authentically
- Overcoming self-doubt
- Ditching the desk for dreams
- There's no secret
- Bad luck? Good luck?
- Quit or stay?
- Write your way
- Dare to dial
- The art of seeing
- Succession is the way to success
- The importance of interests
- Social hangover
- Collecting moments
- Re: Finding my blogging voice
- Embracing the unexpected
- Lost in the everyday
- My brother thinks my blog is broken (he might be right)
- Share your blogging timeline
- The importance of community
- Don't let anyone dim your light
- The end of JulyReply — and the rebirth of this blog
- Writing workout
- Saved by a stranger
- We have a blogline
- The wisdom of pain
- Highs and Lows
- Sometimes you gotta let it go
- VIP of problems
- Do you unmustify?
- I wish I was more dedicated
- Success is not an on-demand commodity
- Creativity 2.0
- The real progress
- Unedited thoughts
- Don't f*ck with fika!
- Keep going
- Re: Embracing the Pain
- Don't think too much
- Bad vibes
- Creative greatness
- Six simple truths
- Writing yourself into existence
- Your trash might be someone else’s treasure
- The joy of not knowing
- Why so serious?
- False identities
- Re: Not everything has to be for sale
- Re: Get Bored!
- Re: Re: Equally different
- We Blog 24/7
- What really matters
- No time to write...really?
- Go your own way
- Why we blog
- The beauty of blogging
- Equally different
- Awesome aging
- Don't think
- No blog yet? You might need 3.
- Swedish Midsummer
- The stupid act of being rude
- How are you doing?
- The changes in life
- Kinder than necessary
- The temptation of negativity
- Why I chose Bear for blogging
- We live and we learn
- Inviting inspiration
- Keep the creative fire burning
- Mental rain clouds
- Bogus Operandi
- Boring text
- Your phone's built-in markdown editor
- Bear blog got a search feature?
- No holding back
- A good writer
- Make yourself a good day
- I have nothing to write
- Give to live
- Writing is unfiltered speech
- Back on Bear Blog - for life
- Release your creativity
- Creating yourself
- Junited: a blog love letter
- Creative environments
- Blogging is back
- Weighing words
- Swenglish language experiment
- Dare to be a fool
- Blogging doubts
- Without judgment
- Blogging anonymously or not?
- Blogging is blooming
- The right blogging tool
- The simple life
- What's the rush?
- Why whine?
- How dare you?
- Why write?
- To write or to "skriva"
- There is no news
- Just another blog
- Creative craziness
- The joy of blogging in English
- Ship more
- Walk into what is
- Write every day
- A winning mindset
- Internet ruined everything
- No matter what
- Not ready for blogging?
- The bubbling writing nerve
- Natural talent
- Perspective
- Development is everywhere
- F**k paradise
- Friend or foe?
- Teacher in disguise
- You're are an expert
- Constant change
- The limitless you
- Prisoner of possibilities
- Remembering fragility
- The lost key
- Just write
- The power of hurrying slowly
- Real inspiration
- The "not creative" trap
- This or that
- The gift of limitations
- Writing without waiting for inspiration
- Cutting concepts
- A win-win kind of blogging
- It's alive!
Since {{ first_post }}, I have published {{ total_posts }} over {{ years_blogging }}, an average of {{ average_posts }} per month. My most active month was {{ most_active_month }}.
How to use
Add the markup below wherever you want the calendar to appear, then add the script and styles to your theme. The posts embed on the first line gives the script your posts to work with, and the list is hidden once the calendar is built.
The summary is optional. Leave out the cb-summary div if you don't want it, or write your own sentence using any of these placeholders:
{{ first_post }}– linked title and date of your first post.{{ last_post }}– linked title and date of your most recent post.{{ total_posts }}– total number of posts.{{ years_blogging }}– time since your first post, like "3 years, 2 months, and 5 days".{{ average_posts }}– average posts per month since your first post.{{ most_active_month }}– the month with the most posts.
Markup
{{ posts }}
<div id="cb-summary">
Since {{ first_post }}, I have published {{ total_posts }} over {{ years_blogging }}, an average of {{ average_posts }} per month. My most active month was {{ most_active_month }}.
</div>
<div id="cb-wrap">
<div class="cb-nav">
<button id="cb-prev" type="button" aria-label="Previous year">←</button>
<span id="cb-year"></span>
<button id="cb-next" type="button" aria-label="Next year">→</button>
</div>
<div id="cb-grid"></div>
</div>
Script
<script>
/* CalenBear | robertbirming.com */
(function () {
"use strict";
function formatDate(date) {
return date.toLocaleDateString("en-GB", {
day: "numeric",
month: "long",
year: "numeric",
timeZone: "UTC"
});
}
function blogAge(from, to) {
const fromY = from.getUTCFullYear();
const fromM = from.getUTCMonth();
const fromD = from.getUTCDate();
const toY = to.getUTCFullYear();
const toM = to.getUTCMonth();
const toD = to.getUTCDate();
let years = toY - fromY;
let months = toM - fromM;
let days = toD - fromD;
if (days < 0) {
months--;
days += new Date(Date.UTC(toY, toM, 0)).getUTCDate();
}
if (months < 0) {
years--;
months += 12;
}
const segments = [];
if (years > 0) segments.push(years + (years === 1 ? " year" : " years"));
if (months > 0) segments.push(months + (months === 1 ? " month" : " months"));
if (days > 0 || segments.length === 0) segments.push(days + (days === 1 ? " day" : " days"));
if (segments.length === 1) return segments[0];
if (segments.length === 2) return segments[0] + " and " + segments[1];
return segments[0] + ", " + segments[1] + ", and " + segments[2];
}
function safeLink(url, title) {
const a = document.createElement("a");
a.textContent = title;
try {
const parsed = new URL(url);
a.href = (parsed.protocol === "https:" || parsed.protocol === "http:")
? parsed.href
: "#";
} catch {
a.href = "#";
}
a.rel = "noopener noreferrer";
return a;
}
function replacePlaceholder(container, placeholder, buildFn) {
container.childNodes.forEach(function (node) {
if (node.nodeType !== Node.TEXT_NODE) return;
const marker = "{{ " + placeholder + " }}";
const idx = node.textContent.indexOf(marker);
if (idx === -1) return;
const before = document.createTextNode(node.textContent.slice(0, idx));
const after = document.createTextNode(node.textContent.slice(idx + marker.length));
const insert = buildFn();
node.parentNode.insertBefore(before, node);
if (Array.isArray(insert)) {
insert.forEach(function (n) { node.parentNode.insertBefore(n, node); });
} else {
node.parentNode.insertBefore(insert, node);
}
node.parentNode.insertBefore(after, node);
node.parentNode.removeChild(node);
});
}
function init() {
const sourceList =
document.querySelector("ul.embedded.blog-posts") ||
document.querySelector("ul.blog-posts");
if (!sourceList) return;
const items = Array.from(sourceList.querySelectorAll("li"));
if (!items.length) return;
const posts = {};
let totalPosts = 0;
const monthCounts = {};
items.forEach(function (li) {
const time = li.querySelector("time[datetime]");
const link = li.querySelector("a");
if (!time || !link) return;
const dt = time.getAttribute("datetime");
const match = /^(\d{4})-(\d{2})-(\d{2})/.exec(dt);
if (!match) return;
const key = match[1] + "-" + match[2] + "-" + match[3];
totalPosts++;
const mo = key.slice(0, 7);
monthCounts[mo] = (monthCounts[mo] || 0) + 1;
posts[key] = { title: link.textContent.trim(), url: link.href };
});
const keys = Object.keys(posts).sort();
if (!keys.length) return;
sourceList.hidden = true;
const postYears = keys.map(function (k) { return parseInt(k.slice(0, 4), 10); });
const minYear = Math.min(...postYears);
const maxYear = Math.max(...postYears);
let currentYear = maxYear;
const firstKey = keys[0];
const lastKey = keys[keys.length - 1];
const firstPost = posts[firstKey];
const lastPost = posts[lastKey];
const firstDate = new Date(firstKey + "T00:00:00Z");
const lastDate = new Date(lastKey + "T00:00:00Z");
const now = new Date();
const monthsSinceFirst =
(now.getUTCFullYear() - firstDate.getUTCFullYear()) * 12 +
(now.getUTCMonth() - firstDate.getUTCMonth()) + 1;
const avgPosts = (totalPosts / monthsSinceFirst).toFixed(1);
const mostActiveMonth = Object.keys(monthCounts).reduce(function (a, b) {
return monthCounts[a] >= monthCounts[b] ? a : b;
});
const mostActiveDate = new Date(mostActiveMonth + "-01T00:00:00Z");
const mostActiveLabel = mostActiveDate.toLocaleDateString("en-GB", {
month: "long", year: "numeric", timeZone: "UTC"
});
const summary = document.getElementById("cb-summary");
if (summary) {
replacePlaceholder(summary, "first_post", function () {
const link = safeLink(firstPost.url, firstPost.title);
return [link, document.createTextNode(" on " + formatDate(firstDate))];
});
replacePlaceholder(summary, "last_post", function () {
const link = safeLink(lastPost.url, lastPost.title);
return [link, document.createTextNode(" on " + formatDate(lastDate))];
});
replacePlaceholder(summary, "total_posts", function () {
return document.createTextNode(totalPosts + (totalPosts === 1 ? " post" : " posts"));
});
replacePlaceholder(summary, "years_blogging", function () {
return document.createTextNode(blogAge(firstDate, now));
});
replacePlaceholder(summary, "average_posts", function () {
return document.createTextNode(avgPosts);
});
replacePlaceholder(summary, "most_active_month", function () {
return document.createTextNode(mostActiveLabel);
});
}
const monthNames = [
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"
];
const dayNames = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
const yearEl = document.getElementById("cb-year");
const grid = document.getElementById("cb-grid");
const prevBtn = document.getElementById("cb-prev");
const nextBtn = document.getElementById("cb-next");
function render() {
yearEl.textContent = currentYear;
prevBtn.disabled = currentYear <= minYear;
nextBtn.disabled = currentYear >= maxYear;
grid.replaceChildren();
for (let mo = 0; mo < 12; mo++) {
const cell = document.createElement("div");
cell.className = "cb-month";
const heading = document.createElement("div");
heading.className = "cb-month-name";
heading.textContent = monthNames[mo];
cell.appendChild(heading);
const dayGrid = document.createElement("div");
dayGrid.className = "cb-days";
dayNames.forEach(function (d) {
const lbl = document.createElement("span");
lbl.className = "cb-day-label";
lbl.textContent = d;
dayGrid.appendChild(lbl);
});
const firstDay = new Date(currentYear, mo, 1).getDay();
const offset = (firstDay + 6) % 7;
const daysInMonth = new Date(currentYear, mo + 1, 0).getDate();
for (let i = 0; i < offset; i++) {
const empty = document.createElement("span");
empty.className = "cb-day cb-day-empty";
dayGrid.appendChild(empty);
}
for (let dy = 1; dy <= daysInMonth; dy++) {
const moStr = String(mo + 1).padStart(2, "0");
const dyStr = String(dy).padStart(2, "0");
const key = currentYear + "-" + moStr + "-" + dyStr;
if (posts[key]) {
const dayEl = document.createElement("a");
dayEl.className = "cb-day cb-day-post";
dayEl.textContent = dy;
dayEl.href = posts[key].url;
dayEl.title = posts[key].title;
dayGrid.appendChild(dayEl);
} else {
const dayEl = document.createElement("span");
dayEl.className = "cb-day";
dayEl.textContent = dy;
dayGrid.appendChild(dayEl);
}
}
cell.appendChild(dayGrid);
grid.appendChild(cell);
}
}
prevBtn.addEventListener("click", function () {
if (currentYear > minYear) { currentYear--; render(); }
});
nextBtn.addEventListener("click", function () {
if (currentYear < maxYear) { currentYear++; render(); }
});
render();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init, { once: true });
} else {
init();
}
})();
</script>
Styles
/* CalenBear | robertbirming.com */
#cb-wrap {
margin-block: 1.5rem;
}
.cb-nav {
display: flex;
align-items: center;
gap: 1rem;
margin-block-end: 1.5rem;
}
.cb-nav button {
font: inherit;
background: none;
border: none;
padding: 0;
cursor: pointer;
font-size: 1rem;
color: color-mix(in srgb, var(--text-color), transparent 40%);
line-height: 1;
}
@media (hover: hover) {
.cb-nav button:not([disabled]):hover {
color: var(--text-color);
}
}
.cb-nav button[disabled] {
opacity: 0.3;
cursor: default;
}
#cb-year {
font-size: 1rem;
color: var(--text-color);
}
#cb-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
gap: 1rem;
}
.cb-month {
background: var(--code-background-color);
border-radius: 6px;
padding: 0.75rem;
}
.cb-month-name {
font-size: calc(var(--font-scale) * 0.85);
color: color-mix(in srgb, var(--text-color), transparent 40%);
margin-block-end: 0.5rem;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.cb-days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 1px;
text-align: center;
}
.cb-day-label {
font-size: 0.65rem;
color: color-mix(in srgb, var(--text-color), transparent 40%);
padding-block: 2px;
}
.cb-day {
font-size: 0.7rem;
padding-block: 3px;
padding-inline: 1px;
border-radius: 3px;
color: color-mix(in srgb, var(--text-color), transparent 40%);
line-height: 1.4;
}
.cb-day-empty {
visibility: hidden;
}
.cb-day-post {
background: color-mix(in srgb, var(--link-color) 12%, transparent);
color: var(--link-color);
font-weight: 500;
cursor: pointer;
text-decoration: none;
}
@media (hover: hover) {
.cb-day-post:hover {
background: var(--link-color);
color: var(--background-color);
}
}
Happy blogging, day by day.
Want more? Check out the full Bear Blog library.
Requires JavaScript, available on Bear Blog's premium plan.↩