<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Obada</title>
    <description>The latest articles on DEV Community by Obada (@ubbaobada).</description>
    <link>https://dev.to/ubbaobada</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1070964%2F2565633b-8560-4c7b-b47a-ad879ae976ab.png</url>
      <title>DEV Community: Obada</title>
      <link>https://dev.to/ubbaobada</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ubbaobada"/>
    <language>en</language>
    <item>
      <title>Building Smarter Delivery Robots: A Journey ThroughAlgorithm Optimization</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Tue, 13 Jan 2026 20:40:29 +0000</pubDate>
      <link>https://dev.to/ubbaobada/building-smarter-delivery-robots-a-journey-throughalgorithm-optimization-n58</link>
      <guid>https://dev.to/ubbaobada/building-smarter-delivery-robots-a-journey-throughalgorithm-optimization-n58</guid>
      <description>&lt;h2&gt;
  
  
  Exploring algorithm optimization through Eloquent JavaScript's package delivery robot challenge.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
Chapter 7 of Eloquent JavaScript presents an interesting challenge: building a robot that deliverspackages around a virtual village. What makes this exercise compelling isn't just implementing thesolution—it's exploring how different optimization strategies perform in practice. This article walksthrough building increasingly efficient robots, measuring their performance, and discovering whichapproaches actually deliver results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem: Package Delivery in a Virtual Village&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine a robot that needs to deliver packages around a small village. The village has variouslocations connected by roads, and packages need to be picked up from one location and delivered toanother.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Village Structure&lt;/strong&gt;&lt;br&gt;
The village is represented as a graph:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var roads = [
  "Alice's House-Bob's House",
  "Alice's House-Cabin",
  "Alice's House-Post Office",
  "Bob's House-Town Hall",
  // ... more roads
];

function buildGraph(edges) {
  let graph = Object.create(null);
  function addEdge(from, to) {
    if (graph[from] == null) {
      graph[from] = [to];
    } else {
      graph[from].push(to);
    }
  }
  for (let [from, to] of edges.map((r) =&amp;gt; r.split("-"))) {
    addEdge(from, to);  // Add edge in both directions
    addEdge(to, from);  // This makes roads bidirectional
  }
  return graph;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;why bidirectional? Each &lt;em&gt;addEdge&lt;/em&gt; call is made twice with swapped parameters so the robot can travel in both directions on any road.&lt;/p&gt;

&lt;h2&gt;
  
  
  key Concept: Immutable State
&lt;/h2&gt;

&lt;p&gt;The simulation uses an immutable data structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class VillageState {
  constructor(place, parcels) {
    this.place = place;
    this.parcels = parcels;
  }

  move(destination) {
    if (!roadGraph[this.place].includes(destination)) {
      return this; // Invalid move, return unchanged state
    }

    let parcels = this.parcels
      .map(p =&amp;gt; {
        if (p.place != this.place) return p;
        return { place: destination, address: p.address };
      })
      .f****ilter(p =&amp;gt; p.place != p.address);

    return new VillageState(destination, parcels);
  }
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The _move _ method doesn't modify the existing state—it creates a new one. This immutability makesdebugging easier and prevents unexpected bugs from state mutations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exercise 1: Measuring Robot Performance&lt;/strong&gt;&lt;br&gt;
Optimization without measurement is guesswork. The book provides three robot strategies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;randomRobot: Picks random directions&lt;/li&gt;
&lt;li&gt;routeRobot: Follows a fixed route visiting all locations&lt;/li&gt;
&lt;li&gt;goalOrientedRobot: Uses pathfinding to go directly to targets&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Building a Comparison Function&lt;/strong&gt;&lt;br&gt;
Fair comparison requires running each robot multiple times on identical scenarios and averaging theresults:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function compareRobots(robot1, memory1, robot2, memory2) {
  let robot1Total = 0;
  let robot2Total = 0;

  for (let i = 0; i &amp;lt; 100; i++) {
    let task = VillageState.random(); // Same task for both

    robot1Total += countTurns(task, robot1, memory1);
    robot2Total += countTurns(task, robot2, memory2);
  }

  console.log(`Robot 1 average: ${robot1Total / 100}`);
  console.log(`Robot 2 average: ${robot2Total / 100}`);
}

function countTurns(state, robot, memory) {
  for (let turn = 0; ; turn++) {
    if (state.parcels.length == 0) {
      return turn; // Return count instead of logging
    }
    let action = robot(state, memory);
    state = state.move(action.direction);
    memory = action.memory;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initial Results&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;randomRobot:        ~70 turns
routeRobot:         ~16 turns
goalOrientedRobot:  ~15 turns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal-oriented approach performs best, but there's room for improvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exercise 2: Building a Smarter Robot&lt;/strong&gt;&lt;br&gt;
Understanding goalOrientedRobot's Weakness.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function goalOrientedRobot({ place, parcels }, route) {
  if (route.length == 0) {
    let parcel = parcels[0];  // Always picks first parcel!
    if (parcel.place != place) {
      route = findRoute(roadGraph, place, parcel.place);
    } else {
      route = findRoute(roadGraph, place, parcel.address);
    }
  }
  return { direction: route[0], memory: route.slice(1) }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue: It blindly chooses parcels[0] without considering distance.&lt;/p&gt;

&lt;p&gt;Scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Robot at Post Office&lt;/li&gt;
&lt;li&gt;Parcel 1: At Alice's House (2 steps away)&lt;/li&gt;
&lt;li&gt;Parcel 2: At Marketplace (1 step away)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It heads to Alice's House simply because that parcel is first in the array.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 1: Choose the Closest Parcel&lt;/strong&gt;&lt;br&gt;
Strategy: Calculate distance to each parcel and pick the nearest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function parcelDistance(place, parcel) {
  if (parcel.place != place) {
    return findRoute(roadGraph, place, parcel.place).length;
  } else {
    return findRoute(roadGraph, place, parcel.address).length;
  }
}

function findClosestParcel(place, parcels) {
  let bestParcel = null;
  let shortDistance = Infinity;

  for (let parcel of parcels) {
    let distance = parcelDistance(place, parcel);
    if (distance &amp;lt; shortDistance) {
      shortDistance = distance;
      bestParcel = parcel;
    }
  }
  return bestParcel;
}

function cleverRobot({ place, parcels }, route) {
  if (route.length == 0) {
    let parcel = findClosestParcel(place, parcels);
    if (parcel.place != place) {
      route = findRoute(roadGraph, place, parcel.place);
    } else {
      route = findRoute(roadGraph, place, parcel.address);
    }
  }
  return { direction: route[0], memory: route.slice(1) };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;goalOrientedRobot: turnsgoalOrientedRobot: 15.21 turns
cleverRobot: 12.57 turns (17% improvement)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Attempt 2: Consider Total Distance (Pickup + Delivery)&lt;/strong&gt;&lt;br&gt;
New insight: We should consider the complete journey, not just the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modified distance calculation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function parcelDistance(place, parcel) {
  if (parcel.place != place) {
    // Distance to pickup + distance from pickup to delivery
    return findRoute(roadGraph, place, parcel.place).length +
           findRoute(roadGraph, parcel.place, parcel.address).length;
  } else {
    return findRoute(roadGraph, place, parcel.address).length;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;goalOrientedRobot: 15.82 turns
cleverRobot:       15.28 turns (minimal improvement)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analysis:&lt;br&gt;
This approach sometimes ignores parcels at the current location. A parcel at our currentposition should almost always be picked up immediately (0-step pickup cost), but the total distancecalculation doesn't prioritize this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 3: Prioritize Local Parcels&lt;/strong&gt;&lt;br&gt;
Strategy:&lt;br&gt;
Always grab parcels at our current location first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function findClosestParcel(place, parcels) {
  let bestParcel = null;
  let shortDistance = Infinity;

  // First pass: look for parcels at current location
  for (let parcel of parcels) {
    if (parcel.place == place) {
      let distance = findRoute(roadGraph, place, parcel.address).length;
      if (distance &amp;lt; shortDistance) {
        shortDistance = distance;
        bestParcel = parcel;
      }
    }
  }

  if (bestParcel != null) return bestParcel; // Found one here!

  // Second pass: find best parcel elsewhere
  for (let parcel of parcels) {
    let distance = parcelDistance(place, parcel);
    if (distance &amp;lt; shortDistance) {
      shortDistance = distance;
      bestParcel = parcel;
    }
  }

  return bestParcel;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;goalOrientedRobot: 15.88 turns
cleverRobot:       16.07 turns (regression)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analysis:&lt;br&gt;
Always prioritizing local parcels creates a greedy algorithm that can commit to inefficientlong-distance deliveries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Breakthrough: Multi-Parcel Thinking&lt;/strong&gt;&lt;br&gt;
different approach emerges from observing real delivery services. Delivery drivers don't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick up one package&lt;/li&gt;
&lt;li&gt;Deliver it&lt;/li&gt;
&lt;li&gt;Return for the next one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick up multiple packages along their route&lt;/li&gt;
&lt;li&gt;Deliver them opportunistically as they pass by destinations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This requires a different question: instead of "which parcel should I complete next?", ask "what's thenearest useful destination?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Efficient Robot Algorithm&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function categorizeParcels(place, parcels) {
  let toPickup = [];
  let toDeliver = [];

  for (let parcel of parcels) {
    if (parcel.place != place) {
      toPickup.push(parcel);
    } else {
      toDeliver.push(parcel);
    }
  }

  return { toPickup, toDeliver };
}

function getAllDestinations(place, parcels) {
  let { toPickup, toDeliver } = categorizeParcels(place, parcels);
  let destinations = [];

  // Add all pickup locations
  for (let parcel of toPickup) {
    if (!destinations.includes(parcel.place)) {
      destinations.push(parcel.place);
    }
  }

  // Add all delivery addresses
  for (let parcel of toDeliver) {
    if (!destinations.includes(parcel.address)) {
      destinations.push(parcel.address);
    }
  }

  return destinations;
}

function findClosestDestination(place, destinations) {
  let bestDestination = null;
  let shortestDistance = Infinity;

  for (let dest of destinations) {
    let route = findRoute(roadGraph, place, dest);
    if (route.length &amp;lt; shortestDistance) {
      shortestDistance = route.length;
      bestDestination = dest;
    }
  }

  return bestDestination;
}

function efficientRobot({ place, parcels }, route) {
  if (route.length &amp;gt; 0) {
    return { direction: route[0], memory: route.slice(1) };
  }

  let destinations = getAllDestinations(place, parcels);
  let target = findClosestDestination(place, destinations);
  let newRoute = findRoute(roadGraph, place, target);

  return { direction: newRoute[0], memory: newRoute.slice(1) };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify all useful destinations (places with parcels to pick up or deliver)&lt;/li&gt;
&lt;li&gt;Find the closest destination&lt;/li&gt;
&lt;li&gt;Move toward it&lt;/li&gt;
&lt;li&gt;As the robot moves, VillageState.move() automatically handles pickups and deliveries&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Final Results&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;goalOrientedRobot: 15.37 turns
cleverRobot:       15.40 turns
efficientRobot:    12.15 turns (20% improvement)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1.Greedy Algorithms Can Be Deceiving&lt;br&gt;
Optimizing for the immediate next step (closest parcel) worked better than trying to plan too far ahead(total distance). Sometimes simpler heuristics win.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Over-optimization Can Backfire&lt;br&gt;
The "prioritize local parcels" strategy seemed logical but decreased performance. Measurement revealstruth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Problem Framing Matters&lt;br&gt;
The breakthrough came from reframing the question:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;❌ "Which parcel should I complete next?"&lt;/li&gt;
&lt;li&gt;✅ "What's the nearest useful thing I can do?"&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Reframing Drives Innovation&lt;br&gt;
The most effective solution came from changing the fundamental question being asked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Incremental Improvement Through Testing&lt;br&gt;
Each iteration taught us something:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Attempt 1: Proximity matters (17% improvement)&lt;/li&gt;
&lt;li&gt;Attempt 2: Too much planning hurts (regression)&lt;/li&gt;
&lt;li&gt;Attempt 3: Greedy local priority fails (regression)&lt;/li&gt;
&lt;li&gt;Final: Dynamic re-evaluation wins (20% improvement)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Further Optimizations&lt;/strong&gt;&lt;br&gt;
The efficient robot could be improved further with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traveling Salesman Problem algorithms for optimal multi-stop routes&lt;/li&gt;
&lt;li&gt;Lookahead planning (considering 2-3 moves ahead)&lt;/li&gt;
&lt;li&gt;Clustering nearby parcels for batch pickups/deliveries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But these add significant complexity for diminishing returns in a small village.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Algorithm optimization is rarely straightforward. Logical improvements can decrease performance, andbreakthrough solutions often require reframing the problem entirely.&lt;/p&gt;

&lt;p&gt;The path from 15.37 turns to 12.15 turns demonstrates that understanding comes from building,measuring, and iterating. Sometimes the best insights emerge not from theory, but from observing whatactually works.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Explored different approaches to this problem? Found other optimizations? The discussion is open in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>What is React Framer Motion?</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Sun, 28 Sep 2025 07:04:08 +0000</pubDate>
      <link>https://dev.to/ubbaobada/what-is-react-framer-motion-e4l</link>
      <guid>https://dev.to/ubbaobada/what-is-react-framer-motion-e4l</guid>
      <description>&lt;p&gt;&lt;strong&gt;React Framer Motion&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Framer Motion&lt;/em&gt; is an open-source motion library for React, Created by Framer. Framer Motion is production-ready and offers a wide of features, it was created to help developers create smooth and interactive animations with ease. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Framer Motion&lt;/em&gt; provides a variety of features to enhance your animation, including: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Spring: Create natural and realistic animations using spring control.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keyframes: Define animations using keyframes for more control.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Layout animation: Animate layout changes seamlessly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shared layout animations: Coordinate animations across multiple components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gestures: Add drag, tap, and hover interactions to your animation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scroll animations: Animate elements based on scroll position.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SVG paths: Animate SVG elements and paths.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exit animations: Define animations for elements when they are removed from the DOM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server-side rendering: Support for server-side rendering to improve performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hardware-accelerated animations: Utilize hardware acceleration for smoother animations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Orchestrate animations across components: Coordinate complex animations across multiple components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS variables: Use CSS variables to control animations dynamically.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Getting Started&lt;/strong&gt;&lt;br&gt;
To get started with &lt;em&gt;Framer Motion&lt;/em&gt;, you need to install it via your package manager. You can use npm to install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install framer-motion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { motion } from "framer-motion";

export const MyComponent = ({ isVisible }) =&amp;gt; (
  &amp;lt;motion.div animate={{ opacity: isVisible ? 1 : 0 }}/&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Practical Example&lt;/strong&gt;&lt;br&gt;
Here is a practical example of how to use &lt;em&gt;Framer Motion&lt;/em&gt; to create a simple animation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
import { motion } from "framer-motion";
const App = () =&amp;gt; {
 const [isVisible, setIsVisible] = useState(true);
 return (
   &amp;lt;div&amp;gt;
     &amp;lt;button onClick={() =&amp;gt; setIsVisible(!isVisible)}&amp;gt;Toggle&amp;lt;/button&amp;gt;
     &amp;lt;motion.div
       animate={{ opacity: isVisible ? 1 : 0 }}
       transition={{ duration: 0.5 }}
     &amp;gt;
       Hello, Framer Motion!
     &amp;lt;/motion.div&amp;gt;
   &amp;lt;/div&amp;gt;
 );
};
export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, clicking the button toggles the visiblity of the "Hello, Framer Motion" with a smooth fade-in and fade-out animation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Framer Motion is a powerful and versatile animation library for React that offers a wide range of features to create smooth and interactive animations. It is easy to get started with and provides extensive documentation and examples to help you create stunning animations for your projects.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>react</category>
      <category>framermotion</category>
    </item>
    <item>
      <title>Promises in JavaScript</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Fri, 25 Jul 2025 09:35:46 +0000</pubDate>
      <link>https://dev.to/ubbaobada/promises-in-javascript-2l7b</link>
      <guid>https://dev.to/ubbaobada/promises-in-javascript-2l7b</guid>
      <description>&lt;h2&gt;
  
  
  What is a Promise?
&lt;/h2&gt;

&lt;p&gt;A promise is an &lt;em&gt;object&lt;/em&gt; that represents the eventual completion (or failure) of an asynchronous operation and its resulting value.&lt;br&gt;
Think of it like a &lt;em&gt;placeholder&lt;/em&gt; for a value that will arrive in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  States of a Promise
&lt;/h2&gt;

&lt;p&gt;A promise can be in one of three states: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pending - initial state, not fulfilled or rejected.&lt;/li&gt;
&lt;li&gt;Fulfilled - operation completed successfully.&lt;/li&gt;
&lt;li&gt;Rejected - operation failed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Basic Syntax
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
const promise = new Promise((resolve, reject) =&amp;gt; {&lt;br&gt;
  // async operation here&lt;br&gt;
  if (/* everything good */) {&lt;br&gt;
    resolve("Success!");&lt;br&gt;
  } else {&lt;br&gt;
    reject("Something went wrong.");&lt;br&gt;
  }&lt;br&gt;
});&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Consuming a Promise
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
promise&lt;br&gt;
  .then((result) =&amp;gt; {&lt;br&gt;
    console.log(result); // "Success!"&lt;br&gt;
  })&lt;br&gt;
  .catch((error) =&amp;gt; {&lt;br&gt;
    console.error(error); // "Something went wrong."&lt;br&gt;
  })&lt;br&gt;
  .finally(() =&amp;gt; {&lt;br&gt;
    console.log("Done");&lt;br&gt;
  });&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;.then()&lt;/em&gt; is called when the promise is fulfilled.&lt;br&gt;
&lt;em&gt;.catch()&lt;/em&gt; is called when the promise is rejected.&lt;br&gt;
&lt;em&gt;.finally()&lt;/em&gt; runs regardless of success or failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Example: Using &lt;em&gt;fetch&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
fetch('https://api.example.com/data')&lt;br&gt;
  .then((response) =&amp;gt; response.json())&lt;br&gt;
  .then((data) =&amp;gt; console.log(data))&lt;br&gt;
  .catch((error) =&amp;gt; console.error('Error:', error));&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Promise?
&lt;/h2&gt;

&lt;p&gt;Before promises, we used &lt;em&gt;callbacks&lt;/em&gt;, which could lead to "callback hell", deeply nested functions that are hard to read and maintain.&lt;/p&gt;

&lt;p&gt;Promises solve that by: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Making code more readable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Making error handling easier&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chaining operations&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Promises in JavaScript&lt;/strong&gt; - a very important topic for writing clean, modern asynchronous code.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is Bootstrap 5?</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Tue, 24 Jun 2025 18:31:43 +0000</pubDate>
      <link>https://dev.to/ubbaobada/what-is-bootstrap-5-1h6f</link>
      <guid>https://dev.to/ubbaobada/what-is-bootstrap-5-1h6f</guid>
      <description>&lt;h2&gt;
  
  
  What is &lt;strong&gt;Bootstrap&lt;/strong&gt;?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Bootstrap is a free front-end framework for faster and easier web development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bootstrap includes HTML and CSS based design templates for typography, forms, buttons, tables, navigation, modals, image carousels and many other, as well as optional JavaScript plugins.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bootstrap also gives you the ability to easily create responsive designs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bootstrap Versions&lt;/strong&gt;&lt;br&gt;
Bootstrap 5 (released 2021) is the newest version of Bootstrap (released 2013); with new components, faster stylesheet and more responsiveness.&lt;/p&gt;

&lt;p&gt;Bootstrap 5 supports the latest, stable releases of all major browsers and platforms. However, Internet Explorer 11 and down is not supported.&lt;/p&gt;

&lt;p&gt;The main differences between Bootstrap 5 and Bootstrap 3 &amp;amp; 4, is that Bootstrap 5 has switched to vanilla JavaScript instead of jQuery.&lt;/p&gt;

&lt;p&gt;Before using any tool or framework, we should ask ourselves an important question: WHY?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use &lt;strong&gt;Bootstrap&lt;/strong&gt;?
&lt;/h2&gt;

&lt;p&gt;Advantages of Bootstrap: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Easy to use: Anybody with just basic knowledge of HTML and CSS can start using Bootstrap.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responsive features: Bootstrap's responsive CSS adjusts to phones, tablets, and desktops.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mobile-first approach: In Bootstrap, mobile-first styles are part of the core framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Browser compatibility: Bootstrap 5 is compatible with all modern browsers (Chrome, Firefox, Edge, Safari, and Opera). Note that if you need support for IE11 and down, you must use either BS4 or BS3.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where to get &lt;strong&gt;Bootstrap&lt;/strong&gt;5?
&lt;/h2&gt;

&lt;p&gt;There are two ways to start using Bootstrap 5 on your own web site.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Include Bootstrap 5 from a CDN&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Download Bootstrap 5 from getbootstrap.com&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bootstrap&lt;/strong&gt; is the most popular HTML, CSS, and JavaScript framework for creating responsive, mobile-first websites.&lt;/p&gt;

&lt;p&gt;Bootstrap 5 is completely free to download and use!&lt;br&gt;
It's very important to know how to work with it and use it with your projects.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Intersection Observer API</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Sat, 07 Jun 2025 12:38:09 +0000</pubDate>
      <link>https://dev.to/ubbaobada/intersection-observer-api-380o</link>
      <guid>https://dev.to/ubbaobada/intersection-observer-api-380o</guid>
      <description>&lt;p&gt;The Intersection Observer API allows you to configure a callback that is called when either of these circumstances occur: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A traget element intersects either the device's viewport or a specified element. That specified element is called the &lt;strong&gt;root element&lt;/strong&gt; or &lt;strong&gt;root&lt;/strong&gt; for the purposes of the Intersection Observer API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The first time the observer is initially asked to watch a target element.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typically, you'll want to watch for intersection changes with regard to the target element's closest scrollable ancestor, or, if the target element is not a descendant of a scrollable element, the device's viewport.&lt;/p&gt;

&lt;p&gt;The API works the same way, in all cases, whether you're using the viewport or some other element as the root.&lt;/p&gt;

&lt;p&gt;The degree of intersection between the target element and its root is the intersection ratio. This is a representation of the percentage of the target element which is visible as a value between 0.0 and 1.0 .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating an Intersection Observer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;create the intersection observer by calling its constructor and passing it a callback function to be run whenever a threshold is crossed in one direction or the other:&lt;/p&gt;

&lt;p&gt;`&lt;br&gt;
const options = {&lt;br&gt;
root: document.querySelector('#scrollArea'),&lt;br&gt;
rootMargin: '0px',&lt;br&gt;
threshold: 1.0,&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;const observer = new IntersectionObserver(callback, options);&lt;br&gt;
`&lt;br&gt;
A threshold of 1.0 means that when 100% of the target is visible within the element specified by the &lt;strong&gt;root&lt;/strong&gt; option, the callback is invoked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intersection Observer options
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;option&lt;/strong&gt; object passed into the IntersectionObserver() constructor let you control the circumstances under which the observer's callback is invoked. it has the following fields:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;root&lt;/strong&gt;&lt;br&gt;
the element that is used as the viewport for checking visibility of the target. MUST be the ancestor of the target. Defaults to the browser viewport if not specified or if &lt;strong&gt;null&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;rootMargin&lt;/strong&gt;&lt;br&gt;
Margin around the root. A string of one to four values similar to the CSS margin property, e.g., "5px 10px 15px 25px" (top, right, bottom, left). The values can ONLY be percentages or absolute lengths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Threshold&lt;/strong&gt;&lt;br&gt;
Either a single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed. If you only want to detect when visibility passes the 50% mark, you can use a value of 0.5 . If you want the callback to run every time visibility passes another 25%, you would specify the array [0, 0.25, 0.5, 0.75, 1]. The default is 0 (meaning as soon as even on pixel is visible, the callbach will be run). A value of 1.0 means that the treshold isn't considered passed until every pixel is visible.&lt;/p&gt;

&lt;p&gt;Be aware that your callback is executed on the main thread. It should operate as quickly as possible; if anything time-consuming needs to be done, use &lt;strong&gt;Window.requestIdleCallback()&lt;/strong&gt; . &lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Related Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;💡 Simple Demo Project – A basic implementation of the Intersection Observer API &lt;br&gt;
Live Demo (&lt;a href="https://obada-barakat.github.io/intersection-observer-demos/Simple-demo/" rel="noopener noreferrer"&gt;https://obada-barakat.github.io/intersection-observer-demos/Simple-demo/&lt;/a&gt;) &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⚙️ Advanced Demo (Coming Soon) – A more interactive use case with lazy loading and multiple observed elements&lt;br&gt;
Stay tuned!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Intersection Observer API is a powerful tool that can help you build performance-friendly, scroll-based features without constantly polling the DOM. Whether you're implementing lazy loading, triggering animations, or building infinite scroll, this API gives you a clean and efficient way to track element visibility.&lt;/p&gt;

&lt;p&gt;I've created a couple of hands-on demos to help you understand how it works in real projects. If you're curious to dive deeper, check out the code linked above — and feel free to leave feedback or ask questions!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Can You Build This? Shift + Click Checkbox Selector – No Libraries!</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Fri, 30 May 2025 09:30:22 +0000</pubDate>
      <link>https://dev.to/ubbaobada/can-you-build-this-shift-click-checkbox-selector-no-libraries-488p</link>
      <guid>https://dev.to/ubbaobada/can-you-build-this-shift-click-checkbox-selector-no-libraries-488p</guid>
      <description>&lt;p&gt;Hey developers! 👋&lt;/p&gt;

&lt;p&gt;I'm currently going through #JavaScript30 — a fantastic 30-day vanilla JavaScript challenge, and today I hit Day 10.&lt;/p&gt;

&lt;p&gt;The task?&lt;br&gt;
Recreate that handy Shift + Click checkbox feature you’ve probably used in Gmail, where you can select a range of checkboxes at once.&lt;/p&gt;

&lt;p&gt;🎯 The Goal&lt;/p&gt;

&lt;p&gt;Let users:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Click a checkbox&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hold down Shift&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click another checkbox&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Automatically select all checkboxes between them&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧠 What You’ll Practice&lt;/p&gt;

&lt;p&gt;This mini-challenge is great for improving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Handling multiple checkbox events&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using the event.shiftKey property&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tracking user selections between clicks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Looping through elements conditionally&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 Your Challenge&lt;br&gt;
Try building this without any libraries or frameworks — just HTML, CSS (optional), and JavaScript.&lt;br&gt;
Here’s what you need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A list of checkboxes (10+ makes it fun!)&lt;/li&gt;
&lt;li&gt;An event listener on each checkbox&lt;/li&gt;
&lt;li&gt;A way to remember the last checked box&lt;/li&gt;
&lt;li&gt;Logic to check all boxes between the last and current if Shift is pressed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🧪 Starter Hint&lt;/p&gt;

&lt;p&gt;You’ll likely need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store the last checked checkbox in a variable&lt;/li&gt;
&lt;li&gt;Loop through all checkboxes to find the range using forEach.&lt;/li&gt;
&lt;li&gt;Use a flag (e.g. inBetween) to mark when to check/uncheck boxes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💬 Want Help?&lt;br&gt;
If you're stuck or want to compare your solution later, drop a comment! I’ll be sharing my approach in a follow-up post soon.&lt;/p&gt;

&lt;p&gt;🔗 Bonus: Try It Live&lt;br&gt;
I’ve also made a live version of this if you want to test it directly:&lt;br&gt;
👉 &lt;a href="https://obada-barakat.github.io/30-days-of-javascript/day10-JavaScript-Hold-shift-and-select" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🕹️ When you finish it publish with the #challengewithubba hashtag, so everyone would be able to see you solution!&lt;/p&gt;

&lt;p&gt;🎉 ENJOY!!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🛠 DevTools &amp; Console</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Thu, 29 May 2025 10:34:21 +0000</pubDate>
      <link>https://dev.to/ubbaobada/devtools-console-3gb3</link>
      <guid>https://dev.to/ubbaobada/devtools-console-3gb3</guid>
      <description>&lt;p&gt;DevTools and the console might feel light exercises or less important, but they're actually super important for debugging and real-world development.&lt;/p&gt;

&lt;p&gt;🛠 DevTools &amp;amp; Console Highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;console.log(), console.warn(), console.error(), console.info for messaging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;console.table() — super helpful for visualizing arrays/objects&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;console.group() and console.groupCollapsed() — useful for organizing logs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;console.time() / console.timeEnd() for performance checks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;console.assert() — throws only when a condition is false&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;console.clear — clears the console&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These little tools can save you hours of debugging when you're working on bigger projects.&lt;/p&gt;

&lt;p&gt;messaging:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
console.log('hello');&lt;br&gt;
console.warn("OH NOO!");&lt;br&gt;
console.error('shot!');&lt;br&gt;
console.info('We are born with only 2 natural fears: the fear of falling and the fear of loud sounds');&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Visualizing array/objects:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
        const dogs = [&lt;br&gt;
            { name: "Snickers", age: 2 },&lt;br&gt;
            { name: "Hugo", age: 8 },&lt;br&gt;
            { name: "Butchi", age: 4 },&lt;br&gt;
        ];&lt;br&gt;
console.table(dogs)&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Organizing logs:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
        const dogs = [&lt;br&gt;
            { name: "Snickers", age: 2 },&lt;br&gt;
            { name: "Hugo", age: 8 },&lt;br&gt;
            { name: "Butchi", age: 4 },&lt;br&gt;
        ];&lt;br&gt;
        dogs.forEach(dog =&amp;gt; {&lt;br&gt;
            console.group(&lt;/code&gt;${dog.name}&lt;code&gt;)&lt;br&gt;
                console.log(&lt;/code&gt;This is ${dog.name}&lt;code&gt;)&lt;br&gt;
                console.log(&lt;/code&gt;${dog.name} is ${dog.age} years old&lt;code&gt;)&lt;br&gt;
            console.groupEnd(&lt;/code&gt;${dog.name}&lt;code&gt;)&lt;br&gt;
        });&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Time: &lt;br&gt;
&lt;code&gt;&lt;br&gt;
        console.time('fetching data');&lt;br&gt;
        fetch('https://api.github.com/users/obada-barakat')&lt;br&gt;
        .then(data =&amp;gt; data.json())&lt;br&gt;
        .then(data =&amp;gt; {&lt;br&gt;
            console.timeEnd('fetching data');&lt;br&gt;
            console.log(data)&lt;br&gt;
        })&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
.assert: &lt;br&gt;
&lt;code&gt;&lt;br&gt;
console.assert(1 === 2, 'That is wrong!');&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;clear the console: &lt;br&gt;
&lt;code&gt;console.clear()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can check out all of these examples in my GitHub: &lt;a href="https://obada-barakat.github.io/30-days-of-javascript/day9-JavaScript-dev-tools" rel="noopener noreferrer"&gt;Ubba's repo&lt;/a&gt; for more info.&lt;/p&gt;

&lt;p&gt;These tools are super important and helpful, there are absolutely more tools, a quick search in MDN or any other platform would give more information.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>JavaScript Challenge: Chessboard</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Wed, 28 May 2025 13:26:00 +0000</pubDate>
      <link>https://dev.to/ubbaobada/javascript-challenge-chessboard-1li8</link>
      <guid>https://dev.to/ubbaobada/javascript-challenge-chessboard-1li8</guid>
      <description>&lt;p&gt;What is the task: &lt;br&gt;
         Write a program that creates a string that represents an 8X8 grid, &lt;br&gt;
         using new line characters to separate lines. At each position of &lt;br&gt;
         the grid there is either a space or a # character. The characters &lt;br&gt;
         should form a &lt;strong&gt;chessboard&lt;/strong&gt;. &lt;br&gt;
         passing this string to console.log should show something like &lt;br&gt;
         this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4x3j6p347veu7b09m5ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4x3j6p347veu7b09m5ss.png" alt=" " width="125" height="156"&gt;&lt;/a&gt;&lt;br&gt;
When you have a program that generates this pattern, define a binding&lt;br&gt;&lt;br&gt;
   &lt;em&gt;size&lt;/em&gt; = 8 and change the program so that it works for any size, outputing  a grid of the given size.&lt;br&gt;
When you solve it, share on social media platforms with #challengewithubba&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building an Interactive JavaScript Image Gallery with Flexbox — Day 5 of My 30-Day Challenge</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Sun, 25 May 2025 14:14:12 +0000</pubDate>
      <link>https://dev.to/ubbaobada/building-an-interactive-javascript-image-gallery-with-flexbox-day-5-of-my-30-day-challenge-4fg</link>
      <guid>https://dev.to/ubbaobada/building-an-interactive-javascript-image-gallery-with-flexbox-day-5-of-my-30-day-challenge-4fg</guid>
      <description>&lt;p&gt;Hi everyone!&lt;/p&gt;

&lt;p&gt;I just completed Day 5 of my #JavaScript30 challenge where I built a responsive and interactive image gallery using JavaScript and CSS Flexbox. The gallery displays five wildlife images, and clicking on any image smoothly expands it for a closer look.&lt;/p&gt;

&lt;p&gt;This project helped me improve:&lt;/p&gt;

&lt;p&gt;DOM manipulation&lt;br&gt;
Responsive layouts with Flexbox&lt;br&gt;
Handling click events for interactive UI&lt;/p&gt;

&lt;p&gt;Here’s a quick demo of the gallery:&lt;br&gt;
(&lt;a href="https://obada-barakat.github.io/30-days-of-javascript/day5-JavaScript%20Flex%20Gallery/" rel="noopener noreferrer"&gt;https://obada-barakat.github.io/30-days-of-javascript/day5-JavaScript%20Flex%20Gallery/&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I’m excited to continue learning and building! &lt;br&gt;
If you have any feedback or suggestions, I’d love to hear from you.&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>100daysofcode</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>7-Day Website Challenge</title>
      <dc:creator>Obada</dc:creator>
      <pubDate>Sat, 24 May 2025 11:31:07 +0000</pubDate>
      <link>https://dev.to/ubbaobada/7-day-website-challenge-4k87</link>
      <guid>https://dev.to/ubbaobada/7-day-website-challenge-4k87</guid>
      <description>&lt;p&gt;🚀 I just launched my first challenge!&lt;br&gt;
Are you ready to build your own website from scratch — even if you're a beginner?&lt;/p&gt;

&lt;p&gt;Join me for the 7-Day Website Challenge where I’ll guide you step-by-step to create a complete, responsive website using just HTML, CSS, and JavaScript.&lt;/p&gt;

&lt;p&gt;✅ No experience needed&lt;br&gt;
✅ 100% beginner-friendly&lt;br&gt;
✅ Daily tasks, live events, and real support&lt;br&gt;
✅ Build and launch your own personal website in 1 week&lt;/p&gt;

&lt;p&gt;🎯 Whether you're curious about coding or want to finally start learning web development, this is your chance.&lt;/p&gt;

&lt;p&gt;💥 We start now — it's free to join!&lt;/p&gt;

&lt;p&gt;🔗 Join the challenge here: &lt;a href="https://nas.io/frontend-mastery-with-ubba/challenges/7day-website-challenge" rel="noopener noreferrer"&gt;https://nas.io/frontend-mastery-with-ubba/challenges/7day-website-challenge&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcyk7ba6no4m7h6r3ih6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcyk7ba6no4m7h6r3ih6.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
💬 Tag a friend who needs this!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
