원형 회전 날씨 카드 배너 만들기 - API 찾기 , 카드배너 디자인하기

ChoiYongHyeun·2024년 1월 18일
0

망가뜨린 장난감들

목록 보기
8/19
post-thumbnail

어제 원형으로 돌아가는 카드배너의 틀은 만들어두었다.

이제 저 카드 배너에 어떤 내용을 넣을 것인가 고민하던 찰나

최근 배운 비동기 처리를 이용해 날씨 카드 배너를 만들자고 생각하였다.


사용할 API 둘러보기

기상청 단기예보 ((구)_동네예보) 조회서비스

공공 데이터 포털에서 기상청 단기예보 조회 서비스를 이용하기로 하였다.

단기 예보는 현재 날짜로부터 3일 뒤 날씨 까지 시간 별 날씨 정보를 담고 있다.

API 신청을 해주고 제공하는 데이터가 무엇들을 포함하고 있는지 확인해보자

API 업데이트 주기

그럼 API의 정보들은 언제 언제 업데이트 될까 ?

갸아악 초단기 같은 경우엔 거의 1시간에 한 번 꼴로 업데이트 되던데 단기 예보는 3시간 단위로 업데이트 된다.

그래도 업데이트 되는게 어디냐 룰루루

요청 메시지와 응답 메시지 확인

요청 변수를 살펴보면 nx , ny (지역 좌표)와 base_date , base_time 을 이용하여 GET 요청을 보내면 될 것 같다.

nx , ny를 구하기 위해선 행정구역-행정동 형태의 주소를 위도 경도로 바꾸고 , 기상청 격자 포맷으로 바꿔줘야 한다.

위도, 경도로 바꾸기 위해 GEOCODING API 를 사용하기로 하고 받은 위도 경도는 이미 깃허브에서 많은 사람들이 코드로 남겨두었더라

기상청 홈페이지 내부 파일에 있던 것을 찾아 깃허브에 누가 공유해두었다.
시간이 나면 해당 Gist 에서 확인해보자

그래서 나중에 시간이 나면 해당 코드를 해석해봐야지

제공하는 데이터 (예보값)

이 중에서 내가 쓸만한 데이터는 최고 기온, 최저 기온, 하늘 상태, 강수 형태 , 강수 확률 , 1시간 기온 정도가 될 것 같다 .


카드 배너 디자인 레퍼런스 찾기

머리속으로 대충 상상되는 디자인은 있으나

더 나은 디자인을 위해서 핀터레스트를 뒤져보기로 했다.

와우 너무 찾아보길 잘했다. 나의 디자인적 감각이 얼마나 절망적인지 알 수 있었다. 하지만 다행스럽게도 디자인 감각이 뛰어난 능력자들이 많은 세상에 살고 있음을 알 수 있었다.

디자인 출처 : www.dribbble.com

해당 느낌으로 카드배너를 디자인 해봐야겠다.

카드 배너는 올해부턴 CSS 다르게 짬 ㅅㄱ (2022년 CSS 채신기술) 에서 발견한 @container 쿼리를 이용해서 해봐야지

가보자 가보자 ㅋㅋ


기존 카드배너 너비 수정하기

위의 느낌으로 디자인 하기 위해서 이전에 디자인했던 카드배너의 높이를 수정하기로 했다.

height : 300px => 400px 로 변경해주었다.

길쭉길쭉 더 카드배너 같은 느낌

원래는 현재 사용하고 있는 핸드폰의 비율대로 하려고 했드니
내가 핸드폰 비율이란걸 인지해서 그런지 몰라도 카드들이 회전하는게 아니라
진짜 핸드폰들이 회전하는 것 같아서 안했다.


카드배너에 사용할 이미지 찾기

https://www.vecteezy.com/

해당 홈페이지에서 free 인 쌈뽕한 이미지들을 찾아왔다.

요런 느낌들 ..

쌈뽕하다 쌈뽕해

카드 배너 디자인 하기

뚝딱뚝딱 html ,css 를 이용해 카드 배너 디자인을 만들어봤다.

      <div class="card">
        <div class="weather-wrapper">
          <div class="main-weather">
            <div class="header-weather">🌍Seoul</div>
            <div class="body-weather">
              <img class="weather-img" src="images/shiny.png" />
              <div class="weather-text">
                <div class="temperature-text">-2℃</div>
                <div class="state-text">Shiny</div>
                <div class="date-text">
                  <span class="hour">3</span>
                  <span span="meridie">pm</span>,Friday,19, january
                </div>
              </div>
              <hr class = 'cross-line' / >
              <div class="weather-sub">
                <div class="sub-wrapper">
                  <div class="weather-icon">💨</div>
                  <div class="datail-number">11 km/h</div>
                  <div class="datail-text">wind</div>
                </div>
                <div class="sub-wrapper">
                  <div class="weather-icon">💧</div>
                  <div class="datail-number">24%</div>
                  <div class="datail-text">Humidity</div>
                </div>
                <div class="sub-wrapper">
                  <div class="weather-icon">☂️</div>
                  <div class="datail-number">10%</div>
                  <div class="datail-text">chance of <br />rain</div>
                </div>
              </div>
            </div>
            <div class="tail-weather"></div>
          </div>
          <div class="sub-weather">
            <div class="sub-main">
              <div class="weather-by-time">
                <div class="item-wrapper"></div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
@import url('https://fonts.googleapis.com/css2?family=Hahmlet:wght@300&display=swap');

* {
  font-family: 'Hahmlet', serif;
  font-weight: 900;
  user-select: none;
}

body {
  background: linear-gradient(to bottom, #12adfd, #1069f3);
}

.container {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding-top: 200px;
  position: relative;
  margin: 0px auto;
  height: 800px;
}

.card {
  width: 200px;
  height: 400px;
  background-color: rgb(10, 20, 55);
  position: absolute;
  color: white;
  font-size: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 10%;
  transition: transform 1s;
  box-shadow: 0px 0px 30px 5px white;
  transform: translateX(0px) translateY(150px) scale(2);
  padding: 1%;
}

.weather-wrapper {
  width: 100%;
  height: 100%;
  background-color: rgb(10, 20, 55);
  border-radius: 10%;
}

.main-weather {
  width: 100%;
  height: 80%;
  border-radius: 10%;
  background: linear-gradient(to bottom, #12adfd, #1069f3);
}

.sub-weather {
  width: 100%;
  height: 20%;
}

.header-weather {
  text-align: center;
  font-size: 15px;
}

.body-weather {
  position: relative;
  height: 100%;
}

.weather-img {
  width: 80%;
  position: absolute;
  left: 10%;
  display: block;
}

.weather-text {
  width: 100%;
  text-align: center;
  position: absolute;
  top: 130px;
}

.temperature-text {
  font-weight: bold;
}

.state-text {
  font-size: 24px;
}

.date-text {
  font-size: 8px;
}

.cross-line {
  position: absolute;
  bottom: 18%;
  left: 10%;
  width: 80%;
  border: none;
  height: 1px;
  box-shadow: 0 1px 0.1px rgba(255, 255, 255, 0.5);
}

.weather-sub {
  position: absolute;
  bottom: 30px;
  width: 80%;
  left: 10%;
  display: flex;
  justify-content: space-around;
  font-size: 7px;
  text-align: center;
}

.sub-weather {
  background-color: rgb(10, 20, 55);
  border-radius: 10%;
  position: relative;
}

.weather-by-time {
  font-size: 8px;
  display: flex;
  margin-top: 10px;
  justify-content: center;
  transition: transfrom 1s;
  overflow-x: hidden;
  /* border: 1px solid white; */
}

.item-wrapper {
  width: 100%;
  display: flex;
}

.time-wrapper {
  width: 40px;
  margin-right: 10px;
}

.small-weather-img {
  width: 40px;
}

.small-time-text {
  text-align: center;
}

.small-temperature {
  text-align: center;
  font-size: 8px;
}
const $weatherByTime = document.querySelector('.weather-by-time');
const $itemWrapper = document.querySelector('.item-wrapper');
const makeTimeZone = () => {
  for (let hour = 0; hour < 24; hour += 1) {
    const $timeWrapper = document.createElement('div');
    const $smallTemperature = document.createElement('div');
    const $smallWeatherImg = document.createElement('img');
    const $smallTimeText = document.createElement('div');
    const imgPath = 'images/shiny.png';

    $timeWrapper.classList.add('time-wrapper');
    $smallTemperature.classList.add('small-temperature');
    $smallTimeText.classList.add('small-time-text');
    $smallWeatherImg.classList.add('small-weather-img');

    $smallTemperature.textContent = '-1' + '℃';
    $smallTimeText.textContent = hour < 10 ? `0${hour}` : hour;
    $smallWeatherImg.src = imgPath;

    $timeWrapper.appendChild($smallTemperature);
    $timeWrapper.appendChild($smallWeatherImg);
    $timeWrapper.appendChild($smallTimeText);

    $itemWrapper.appendChild($timeWrapper);
  }
  $weatherByTime.appendChild($itemWrapper);
};

makeTimeZone();

$itemWrapper.style.transform = `translateX(${-15 * 50}px)`;

이런식으로 html ,css를 만들어 뒀으니 이제 이를 컴포넌트화 시켜서 API 로 가져온 정보들을 안에다가 넣어주도록 하자

리액트에서는 이런 식으로 재사용 가능한 UI 요소를 컴포넌트라고 부른다고 한다.
나는 아직 리액트를 배우지 않았으니 그냥 뚝딱뚝딱 innerHTML 을 이용하도록 하자 ><

profile
빨리 가는 유일한 방법은 제대로 가는 것이다

0개의 댓글