DEV Community

Cover image for Implemented a Feature where the Theme on my Portfolio changes based on the Holiday (Because it's fun) 💫
👾 FrancisTRᴅᴇᴠ 👾
👾 FrancisTRᴅᴇᴠ 👾

Posted on

Implemented a Feature where the Theme on my Portfolio changes based on the Holiday (Because it's fun) 💫

Yesterday, I had this great idea for my portfolio. I want to implement a feature where if it reaches Valentine day (since it is coming up), it changes the theme of my portfolio. For example, right now I have blue for my text. Instead, it would be pink!

Of course, hard coding it would be a pain since you have to manually change it on each holiday, so I made it automatically using the new Date(). The holidays I added are:

  • Valentine Day
  • St. Patrick's Day
  • Halloween
  • Christmas Day

Here are the features I added to the portfolio! If you would love to see it, visit: https://francistr.github.io/


Spark Effect on Mouse Click!

I found this effect from Prahalad on this post "Click anywhere to see Spark Effect(fireworks) using CSS and JS". The only problem is translating it to my Portfolio since I used Next.js for my Portfolio. To achieved the functionality, here is what I did:

In CSS (Similar to Prahalad implementation):

/* Each spark segment */
.click-burst li {
  padding: 0;
  width: 0;
  height: 0;
  position: absolute;
  left: auto;
  right: auto;
}

/* Top (vertical) */
.click-burst li:first-child {
  left: 50%;
  top: -22px;
  width: 1px;
  border-left: 2px solid var(--click-color-1);
  animation: vert 0.25s linear;
}

/* Bottom (vertical) */
.click-burst li:nth-child(2) {
  left: 50%;
  bottom: -22px;
  width: 1px;
  border-left: 2px solid var(--click-color-1);
  animation: vert 0.25s linear;
}

/* Left (horizontal) */
.click-burst li:nth-child(3) {
  left: -6px;
  top: 11px;
  height: 1px;
  border-bottom: 2px solid var(--click-color-1);
  animation: horiz 0.25s linear;
}

/* Right (horizontal) */
.click-burst li:nth-child(4) {
  right: -6px;
  top: 11px;
  height: 1px;
  border-bottom: 2px solid var(--click-color-1);
  animation: horiz 0.25s linear;
}

/* Diagonals */
.click-burst li:nth-child(5) {
  left: 0px;
  top: -11px;
  rotate: 45deg;
  height: 1px;
  border-bottom: 2px solid var(--click-color-2);
  animation: horiz 0.25s linear;
}
.click-burst li:nth-child(6) {
  right: 0px;
  top: -11px;
  rotate: -45deg;
  height: 1px;
  border-bottom: 2px solid var(--click-color-2);
  animation: horiz 0.25s linear;
}
.click-burst li:nth-child(7) {
  left: 0px;
  bottom: -11px;
  rotate: -45deg;
  height: 1px;
  border-bottom: 2px solid var(--click-color-2);
  animation: horiz 0.25s linear;
}
.click-burst li:nth-child(8) {
  right: 0px;
  bottom: -11px;
  rotate: 45deg;
  height: 1px;
  border-bottom: 2px solid var(--click-color-2);
  animation: horiz 0.25s linear;
}

/* Keyframes for mouse click */
@keyframes vert {
  from { height: 22px; }
  to   { height: 0px; }
}
@keyframes horiz {
  from { width: 22px; }
  to   { width: 0px; }
}
Enter fullscreen mode Exit fullscreen mode

On the ClickBurst.tsx, I add this code:

/**
 * Click anywhere on the page to spawn a temporary <ul> with 8 <li> "sparks"
 * positioned and animated by CSS. Removed after 250ms.
 */
export default function ClickBurst() {
  useEffect(() => {
    const onClick = (event: MouseEvent) => {
      let ul = document.createElement("ul");
      ul.className = "click-burst";

      // Absolutely position at the mouse and center the UL on that point
      ul.style.position = "absolute";
      ul.style.left = `${event.pageX}px`;
      ul.style.top = `${event.pageY}px`;
      ul.style.transform = "translate(-50%, -50%)";

      // Size of the effect area (tweak as you like)
      ul.style.width = "3em";
      ul.style.height = "1.5em";

      // Housekeeping
      ul.style.listStyle = "none";
      ul.style.padding = "0";
      ul.style.margin = "0";           // no margin hacks needed
      ul.style.pointerEvents = "none"; // don't block clicks
      ul.style.zIndex = "9999";        // on top of everything


      // 8 radial “spark” lines (li elements)
      for (let i = 1; i <= 8; i++) {
        let li = document.createElement("li");
        ul.appendChild(li);
      }

      document.body.appendChild(ul);

      // Remove after 250ms (matches animation duration)
      setTimeout(() => {
        ul.remove();
      }, 250);
    };

    document.body.addEventListener("click", onClick);
    return () => document.body.removeEventListener("click", onClick);
  }, []);

  return null; // no visible UI; this just wires up the effect
}
Enter fullscreen mode Exit fullscreen mode

Note that I had the help of Copilot to translate the code from the post onto my portfolio. Tweaks were made after translation.

Annnnndddddddd Done! Those are the main parts. Here is what it looks like:

Clicking Effect

Hovering Effect!

When you hover over my title "Full-Stack AI Engineer", your mouse change to a different .ico image. For some reason, it did not like .png .jpg, etc. So, I made my disired images all .ico. This is what I added.

For CSS, I added a variable and add that variable to our class:

/* Inside of the Root */
--custom-cursor: url('/cursorImg/IceCream.ico') 16 16, auto

/* Outside of the Root */
.custom-cursor {
  cursor: var(--custom-cursor);
}
Enter fullscreen mode Exit fullscreen mode

Then I added the <span> tag that only works if you hover over this text

<h2 className="text-2xl lg:text-start shiny">
   <span className="custom-cursor">Full-Stack AI Engineer</span>
</h2>
Enter fullscreen mode Exit fullscreen mode

That's pretty much it. Here is what it looks like when you visit my site!

Hovering

Rest of page change colors!

To achieve this, this is the steps I took to make this dynamic.

For CSS, I create the variables in the root and use it throughout the CSS file:

:root {
  /* Titles */
  --shiny-color: #00ccff;
  --shiny-color-light: #cef5ff;

  /* sub-titles */
  --primary-main-color: 193 100% 50%;

  /* Card itself */
  --card-main-bg: 222.2 50% 10%;

  /* Skills card */
  --skills-card-bg: #0C1426;

  /* Click colors */
  --click-color-1: rgb(255, 255, 255);
  --click-color-2: rgb(255, 255, 255);

  --custom-cursor: url('/cursorImg/IceCream.ico') 16 16, auto
}
Enter fullscreen mode Exit fullscreen mode

I then added a .tsx file called "ThemeScheduler". where it's purpose is if the assign date has started, change the variable values to a different color.

For example, for Christmas, we assign the colors and its date of change:

{ // Christmas (December 25th)
  // Year, Month, day, hours, minutes, seconds, milliseconds
  start: new Date(new Date().getFullYear(), 11, 25, 0, 0, 0, 0),
  end: new Date(new Date().getFullYear(), 11, 26, 0, 0, 0, 0),
  vars: {
    "--shiny-color": "hsl(120, 79%, 40%)",
    "--shiny-color-light": "#ff7a7a",

    "--primary-main-color": "120, 79%, 40%",

    "--card-main-bg": "0, 49%, 10%",
    "--skills-card-bg": "hsl(0, 49%, 10%)",

    "--click-color-1": "rgb(21, 183, 21)",
    "--click-color-2": "rgb(255, 122, 122)",

    "--custom-cursor": "url('/cursorImg/ChristmasTree.ico') 16 16, auto"
  },
},
Enter fullscreen mode Exit fullscreen mode

That is the gist of it. Here is what it looks like for each holiday in full:

Valentine Day

Valentine Day

St. Patrick's Day

St. Patrick's Day

Halloween

Halloween

Christmas Day

Christmas Day


Thanks for reading! Note that the Portfolio is still in the works. If you would love to review and provide feedback, I would love to hear from you! Will make a Portfolio review request in the future!

Discussion

  • What other themes should I add?
  • What is your favorite theme?
  • Feedback would be nice! Note that this is still in development, but would love to receive feedback if possible!

Top comments (23)

Collapse
 
konark_13 profile image
Konark Sharma

Loved the Idea of adding different themes based on the days. Sounds so cool and interesting, thanks for sharing the code. A thing you could add is loading animation based on the days. Valentines: love theme loading animation, Halloween: scary theme loading animation and so on. Seems like I need to add this feature in my portfolio. Thanks for inspiring me.

Collapse
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

No problem Konark! I'm glad this gave you some ideas and inspiration for your portfolio! Can't wait to see yours! (Unless you have it up already or shared it?). Regardless, thanks again!

Collapse
 
konark_13 profile image
Konark Sharma

It is already up but yeah kept it simple and still need to implement the ideas you gave.
Incase, you are curious: Portfolio. Would love to hear your feedback on it.
Keep inspiring me and many other like me.

Thread Thread
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Looks Awesome! Love the color scheme and how it's not too much information and is organized! Couple of things:

  • For your skills, I recommend labeling your technologies (React under the React Icon for example). It's is an accessibility thing and sometimes people have a hard time seeing what the icon is and having to search it up.
  • Whenever I make any website, the final boss for responsiveness is seeing if it fits on a Galaxy Fold. I notice white spaces when I went into that Resolution size as seen below.

That's pretty much it! Everything else seems fine. Do account for accessibility and have this in mind. "Less clicks equals to better experience".

Thread Thread
 
konark_13 profile image
Konark Sharma

Thank you so much @francistrdev for taking your time and reviewing. I know what is causing the glitch will fix it in version 2.0. I'll keep your points in mind for version 2.0 and also add the inspiration you gave. I really appreciate your time and review. Means a lot.

Thread Thread
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

For sure! Let me know if I can be any of assistance and will look forward for your updates :D

Collapse
 
cgcm070 profile image
Cesar Castillo

What a great idea! Adding some SVGs of Christmas trees or pumpkins, depending on the time of year, could also look fantastic 🤩

Collapse
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Great Idea! Though my current issue is that I do not want it to distract the user of decorations. Any suggestions on where to put them specifically?

Collapse
 
cgcm070 profile image
Cesar Castillo

Understood. How about an initial pop-up ( tooltip) description as a visual reference? It could guide users to hover over the title to see more icons when the page loads.

Thread Thread
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Sounds like an interesting idea. Will take a consideration for the future! Thanks!

Collapse
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Thanks Richard! I appreciate your thoughts! Let me know if you have any suggestions as well and look forward for my finished portfolio!

Collapse
 
bhavin-allinonetools profile image
Bhavin Sheth

This is such a fun idea — it adds personality without hurting usability 👍

I really like how you handled it with CSS variables + dates instead of hardcoding styles. That makes it playful and maintainable. The click burst + cursor change are nice touches too.

Curious: have you thought about adding a subtle toggle to preview themes manually, or do you prefer keeping it “surprise-only” based on the date?

Collapse
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Hey Bhavin! Thanks for your reply! Appreciate the comments!

For your curious thought, I am thinking of keeping a surprise-only for now since my purpose is keeping it an "Easter egg" and not distracting from the whole site. @cgcm070 did mentioned about using the tool tip, so maybe that can go along with the idea of having the ability to preview it manually probably.

Thanks again! Hope that make sense!

Collapse
 
alfatechknowledge profile image
Alfatech

Love this idea – seasonal theming done the smart way, not the “I’ll remember to change it next year… maybe” way 😄. Using new Date() instead of hard-coding is exactly the kind of lazy that’s actually professional.
The spark effect is a nice touch – playful but not gimmicky, and props for wrestling it into Next.js instead of copy-pasting magic. Also the custom cursor on hover? Riskowny ruch, a wyszło zaskakująco clean.
A few thoughts:
Maybe add a tiny debug panel showing which theme is active? Could help users notice the feature outside holiday windows.
Consider time zones – someone in Tokyo might get Christmas before you 😉
Easter theme could be fun (pastels + egg cursor?).
April Fools mode that subtly messes with UI would be legendary.
Favorite so far: Halloween – those colors just hit.
Cool project, widać serce i pomysł, nie tylko kolejny klon portfolio. Keep breaking things creatively

Collapse
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Thanks Alfatech! I appreciate your generous comment!

To clarify about "props for wrestling it into Next.js instead of copy-pasting magic.", this was built off a template that uses Next.js (Added credits to the README on GitHub) but made modifications that makes it at least unique to me and fix other bugs such as responsiveness and other stuff. Also, not sure if "Note that I had the help of Copilot to translate the code from the post onto my portfolio. Tweaks were made after translation." counts as "copy/paste", but up to you. Making this transparent and hope that's ok with you!

For your feedback,

  • "Maybe add a tiny debug panel showing which theme is active? Could help users notice the feature outside holiday windows.". Makes sense!
  • "Consider time zones – someone in Tokyo might get Christmas before you 😉". Need some time to think about since I thought about Lunar New Year, but the problem is that the date changes each year. Will need to think more about how to implement that. Great idea though!
  • "Easter theme could be fun (pastels + egg cursor?).". Forgot about Easter! Will put that on my TODO in the future! Thanks!
  • "April Fools mode that subtly messes with UI would be legendary.". Lmao! Hopefully a recruiter won't see this for the first time on April 1." Great idea!
  • "Favorite so far: Halloween – those colors just hit.". Reminds me of "Fall" themed. Great choice!

Thanks for your feedback and support. Stay tuned in the future!

Collapse
 
mulishagraves_7969 profile image
Mulisha Graves

Love this 💗. I get so bored looking at white and black and I love crazy colors in everything.

Collapse
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Thanks Mulisha! Glad you enjoyed it!

Collapse
 
shalinibhavi525sudo profile image
shambhavi525-sudo

This is such a fun way to inject personality into a portfolio! Most sites are static 'set-and-forget' projects, but the ThemeScheduler makes yours feel alive.

Feedback & Ideas:

The 'Spark' Logic: My favorite feature. Since you're using Next.js, consider checking for prefers-reduced-motion in your useEffect so you don't trigger the animation for users with motion sensitivity.

Performance: If users spam-click, document.createElement can get heavy. For a 'Senior' touch, you could try a small Canvas layer or an element pool to keep it buttery smooth.

Theme Idea: Add a 'Matrix/Hacker' theme for International Developer Day (Sept 13th) with a terminal-green cursor!

Collapse
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Thanks Sham for your comment! It's is really important for your site to be unique to you and not in a generic way.

For your ideas and feedback,

  • The 'Spark' Logic: My favorite feature. Since you're using Next.js, consider checking for prefers-reduced-motion in your useEffect so you don't trigger the animation for users with motion sensitivity.

Will take that into consideration!

  • Performance: If users spam-click, document.createElement can get heavy. For a 'Senior' touch, you could try a small Canvas layer or an element pool to keep it buttery smooth.

I did try to spam click it and the performance seems ok for me at least. Will try to test it on low ended computers to see otherwise. Regardless, good idea though!

  • Theme Idea: Add a 'Matrix/Hacker' theme for International Developer Day (Sept 13th) with a terminal-green cursor!

Great idea! Will take that to my TODO list in the future!

Thanks you for your feedback! Stayed tuned and hope you are well!

Collapse
 
marina_eremina profile image
Marina Eremina

Loved your portfolio, simple but definitely not boring! The skills section animation is super fun, just spent a couple of minutes playing with it 😄

Collapse
 
francistrdev profile image
👾 FrancisTRᴅᴇᴠ 👾

Hey Marina! Glad you like it and had fun with my portfolio site!