3

Intro

I am creating a weather application with nextJS and TailwindCSS. I had almost created the whole application but stuck at the end with this UI issue. web

What do I want?

I want to change the backgroundImage dynamically depending upon the weather description ( ex: clear sky, haze, rain, snow).

Problem

For that I had written a function changeBackground("rain") but it is not working. I had defined all the image paths in the tailwind.config.js file. After debugging, I found that the function is giving the correct answer (printed answer in console) but my className="bg-${changeBackground("rain")}" not working. Below is the code for this

tailwind.config.js

module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      backgroundImage: {
        'day_sun' : "url('../public/back_big.jpg')",
        'day_rain' : "url('../public/dayrain.jpg')",
        'day_cloud' : "url('../public/daycloud2.jpg')",
        'day_snow' : "url('../public/daysnow.jpg')",
        'night_sun' : "url('../public/nightsunny.jpg')",
        'night_snow' : "url('../public/nightsnow.jpg')",
        'night_thunder' : "url('../public/nightthunder.jpg')",
      }
    },
  },
  plugins: [],
}

index.js

import Head from "next/head";
import { useEffect } from "react";
import Image from "next/image";
import { useState } from "react";
import Today_highlight from "./components/Today_highlight";
import Weather_Today from "./components/Weather_Today";
import Weather_week from "./components/Weather_week";
import searchimageurl from "../public/search.gif";
import Typed from "react-typed";


const Home = () => {
  //console.log("res1 = ", results1);
  //const router = useRouter();
  const [city, setCity] = useState("");
  const [data, setData] = useState({ day: {}, week: {} });

  


  //for the first time
  useEffect(() => {
    (async () => {
      const url = `https://api.openweathermap.org/data/2.5/weather?q=Delhi&appid=${process.env.NEXT_PUBLIC_API_KEY_1}`;
      const res1 = await fetch(url);
      const response1 = await res1.json();
      //console.log("res1 = ",response1);

      //api-2
      const url1 = `https://api.openweathermap.org/data/2.5/forecast/daily?q=Delhi&appid=${process.env.NEXT_PUBLIC_API_KEY_1}`;
      const res2 = await fetch(url1);
      const response2 = await res2.json();
      //console.log("res2 = ",response2);

      setData({ day: response1, week: response2 });
    })();
  }, []);


  const handleChange = (e) => {
    setCity(e.target.value);
    //console.log(city)
  };

  const handleSubmit = async (e) => {
    //console.log("%c ClickSubmit","font-size:12px; color:green; padding:10px;")
    //console.log("city = ", city);
    //router.push(`/?term=${city}`);

    const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.NEXT_PUBLIC_API_KEY_1}`;
    const res = await fetch(url);
    const data1 = await res.json();
    //console.log(data1);

    //api-2
    const url1 = `https://api.openweathermap.org/data/2.5/forecast/daily?q=${city}&appid=${process.env.NEXT_PUBLIC_API_KEY_1}`;
    const res1 = await fetch(url1);
    const data2 = await res1.json();
    //console.log(data2);
    setData({ day: data1, week: data2 });
  };

  //console.log(data);
  const weather = data?.day?.weather;
  
  //console.log("we - ",weather[0]?.description)
  //fn to determine the bg
  function changebackground(des) {
    //console.log("des =",des)

    if (des === "sky is clear" || des === "clear sky") return 'day_sun';
    else if (des === "few clouds") return 'day_cloud';
    else if (des === "scattered clouds") return 'day_cloud';
    else if (des === "broken clouds" || des === "overcast clouds")
      return 'day_cloud';
    else if (
      des === "shower rain" ||
      des === "light rain" ||
      des === "drizzle" ||
      des === "moderate rain"
    )
      return 'day_rain';
    else if (
      des === "rain" ||
      des === "very heavy rain" ||
      des === "heavy intensity rain" ||
      des === "extreme rain" ||
      des === "heavy intensity shower rain"
    )
      return 'day_rain';
    else if (
      des === "thunderstorm" ||
      des === "light thunderstorm" ||
      des === "heavy thunderstorm" ||
      des === "ragged thunderstorm" ||
      des === "thunderstorm with rain"
    )
      return 'night_thunder';
    else if (des === "snow" || des === "light snow" || des === "heavy snow")
      return 'day_snow';
    else if (
      des === "light rain and snow" ||
      des === "rain and snow" ||
      des === "light shower snow"
    )
      return 'night_snow';
    else if (
      des === "mist" ||
      des === "fog" ||
      des === "smoke" ||
      des === "haze"
    )
      return 'day_rain';
    else return 'day_sun';
  }

  console.log(changebackground("snow"),"-> picture")

  return (
    <>
      <Head>
        <title>Weather-Lytics</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <div  className={`lg:bg-${changebackground("snow")} bg-no-repeat`} >
        {/* input */}
        <div className="p-3 xl:p-5 flex flex-row justify-center items-center space-x-2 xl:space-x-5 ">
          <div className=" border-2 border-stone-700 rounded-full ">
            <Typed
              strings={[
                "Search for Delhi",
                "Search for Tokyo",
                "Search for California",
                "Search for Ulaanbaatar",
              ]}
              typeSpeed={30}
              backSpeed={50}
              attr="placeholder"
              loop
            >
              <input
                className="w-full rounded-full p-2 xl:p-4 pl-5 xl:pl-10 text-base xl:text-3xl text-blue-800 font-bold active:rounded-full "
                value={city}
                type="text"
                onChange={handleChange}
              />
            </Typed>
          </div>
          <div>
            <button
              className="p-1 m-auto p-auto"
              onClick={() => handleSubmit()}
            >
              <div className="w-14 h-14 xl:w-16 xl:h-16 p-2 rounded-full bg-pink-400 border-2 hover:bg-pink-600 border-white">
                <Image
                  src={searchimageurl}
                  layout="responsive"
                  alt="Search_icon"
                  className=" rounded-full p-3 bg-blue-900 "
                />
              </div>
            </button>
          </div>
        </div>

        <div className="min-h-full  flex flex-col lg:flex-row justify-evenly ">
          <div className="bg-white/50 xl:bg-white/70  w-full h-full lg:w-1/4 lg:h-full xl:m-4 rounded-lg xl:rounded-3xl">
            <Weather_Today results={data.day} />
          </div>
          <div className=" lg:h-full">
            <div className="min-h-full flex flex-col">
              <div className="bg-white/50 xl:bg-white/70 xl:m-4 xl:rounded-3xl">
                <Today_highlight results={data.day} />
              </div>
              <div className="bg-white/50 xl:bg-white/70 xl:m-4 xl:rounded-3xl">
                <Weather_week results1={data.week} />
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};


export default Home;

Please help me to do so???

MagnusEffect
  • 3,363
  • 1
  • 16
  • 41

2 Answers2

3

TailwindCSS doesn't allow you to generate classes dynamically. So when you use the following to generate the class…

`lg:bg-${changebackground("snow")}`

…TailwindCSS will not pick that up as a valid TailwindCSS class and therefore will not produce the necessary CSS.

Instead, you must include the full name of the class in your source code. I'd recommend using an object to quickly get the correct class:

const backgroundClasses = {
  day_snow: 'lg:bg-day_snow',
  day_sun: 'lg:bg-day_sun',
  // ...
}

Then use your function to lookup the correct class from that object.

By doing it this way, the entire string for every class is in your source code, so TailwindCSS will know to generate the applicable CSS.

Read more: https://tailwindcss.com/docs/content-configuration#class-detection-in-depth

Nick
  • 5,108
  • 2
  • 25
  • 58
1

TailwindCss don't allow construct class names dynamically. instead use

 if (des === "sky is clear" || des === "clear sky") return 'bg-day_sun';
    else if (des === "few clouds") return 'bg-day_cloud';
    else if (des === "scattered clouds") return 'bg-day_cloud';
    else if (des === "broken clouds" || des === "overcast clouds")
      return 'bg-day_cloud';
    else if (
      des === "shower rain" ||
      des === "light rain" ||
      des === "drizzle" ||
      des === "moderate rain"
    )
      return 'bg-day_rain';
    else if (
      des === "rain" ||
      des === "very heavy rain" ||
      des === "heavy intensity rain" ||
      des === "extreme rain" ||
      des === "heavy intensity shower rain"
    )
      return 'bg-day_rain';
    else if (
      des === "thunderstorm" ||
      des === "light thunderstorm" ||
      des === "heavy thunderstorm" ||
      des === "ragged thunderstorm" ||
      des === "thunderstorm with rain"
    )
      return 'night_thunder';
    else if (des === "snow" || des === "light snow" || des === "heavy snow")
      return 'bg-day_snow';
    else if (
      des === "light rain and snow" ||
      des === "rain and snow" ||
      des === "light shower snow"
    )
      return 'bg-night_snow';
    else if (
      des === "mist" ||
      des === "fog" ||
      des === "smoke" ||
      des === "haze"
    )
      return 'bg-day_rain';
    else return 'day_sun';
  }

and in your CSR use

<div  className={`lg:${changebackground("snow")} bg-no-repeat`} >
Dave
  • 172
  • 1
  • 3
  • 11