tailwindCss를 통한 UI 수정

 

지금까지 만들어진 해커뉴스의 디자인적인 부분은 tailwindCss를 가지고 작업을 할것이다. 그렇게 하기 전에 기존에 있는 해커뉴스의 코드는 template을 가지고 구조적인 부분을 수정했지만 아직도 문제가 있다.

 

template의 <ul>, <li> 태그들은 아직도 반복문을 따로 사용해서 작업하는 부분이나 template의 동적인 데이터를 추가해야 하는 부분은 데이터의 변경이 있을때마다 replace함수를 써 줘야하기 때문에 여러가지 기능들이 추가되면 replace 함수를 그만큼 추가로 사용해야 하는 문제점이 있다. 따라서 템플릿엔진(ejs, pug, nunjucks, handlebars 등)을 사용할 것이다.

 

그 전에 먼저 UI 작업을 먼저 한다.

 

https://fontawesome.com/

 

Font Awesome

The world’s most popular and easiest to use icon set just got an upgrade. More icons. More styles. More Options.

fontawesome.com

폰트와 아이콘을 가볍게 사용할 수 있다. (대부분 아이콘을 사용)

 

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"  integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA==" crossorigin="anonymous" referrerpolicy="no-referrer" />

마찬가지로 cdn.js 홈페이지에서 cdn으로 가져온다.

 

const container = document.querySelector('#root');
const ajax = new XMLHttpRequest();
const NEWS_URL = 'https://api.hnpwa.com/v0/news/1.json'
const CONTENT_URL = 'https://api.hnpwa.com/v0/item/@id.json';
const store = {
    currentPage: 1,
}

function getData(url){    
   ...
}

function newsFeed(){
    const newsFeed = getData(NEWS_URL);
    const newsTotalPage = newsFeed.length / 10;
    const newsList = [];
    let template = `
    <div class="bg-gray-600 min-h-screen">
      <div class="bg-white text-xl">
        <div class="mx-auto px-4">
          <div class="flex justify-between items-center py-6">
            <div class="flex justify-start">
              <h1 class="font-extrabold">Hacker News</h1>
            </div>
            <div class="items-center justify-end">
              <a href="#/page/{{__prev_page__}}" class="text-gray-500">
                Previous
              </a>
              <a href="#/page/{{__next_page__}}" class="text-gray-500 ml-4">
                Next
              </a>
            </div>
          </div> 
        </div>
      </div>
      <div class="p-4 text-2xl text-gray-700">
        {{__news_feed__}}        
      </div>
    </div>
    `;
    
    for(let i=(store.currentPage - 1) * 10; i<store.currentPage * 10; i++){
        newsList.push(`
            <div class="p-6 ${newsFeed[i].read ? 'bg-red-500' : 'bg-white'} mt-6 rounded-lg shadow-md transition-colors duration-500 hover:bg-green-100">
                <div class="flex">
                    <div class="flex-auto">
                        <a href="#/show/${newsFeed[i].id}">${newsFeed[i].title}</a>  
                    </div>
                    <div class="text-center text-sm">
                        <div class="w-10 text-white bg-green-300 rounded-lg px-0 py-2">${newsFeed[i].comments_count}</div>
                    </div>
                </div>
                <div class="flex mt-3">
                    <div class="grid grid-cols-3 text-sm text-gray-500">
                        <div><i class="fas fa-user mr-1"></i>${newsFeed[i].user}</div>
                        <div><i class="fas fa-heart mr-1"></i>${newsFeed[i].points}</div>
                        <div><i class="far fa-clock mr-1"></i>${newsFeed[i].time_ago}</div>
                    </div>  
                </div>
            </div>
        `);
    }

    template = template.replace('{{__news_feed__}}', newsList.join(''));
    template = template.replace('{{__prev_page__}}', `${store.currentPage > 1 ? store.currentPage - 1 : 1}" ${store.currentPage === 1 ? 'style="pointer-events: none;"' : " "}`);
    template = template.replace('{{__next_page__}}', `${store.currentPage + 1}" ${store.currentPage === newsTotalPage ? 'style="pointer-events: none;"' : " "}`);    

    container.innerHTML = template;
}

function newsDetail(){
    const id = location.hash.substring(7);

    const newsContent = getData(CONTENT_URL.replace('@id', id));
    let template = `
        <div class="bg-gray-600 min-h-screen pb-8">
            <div class="bg-white text-xl">
                <div class="mx-auto px-4">
                    <div class="flex justify-between items-center py-6">
                        <div class="flex justify-start">
                            <h1 class="font-extrabold">Hacker News</h1>
                        </div>
                        <div class="items-center justify-end">
                            <a href="#/page/${store.currentPage}" class="text-gray-500">
                                <i class="fa fa-times"></i>
                            </a>
                        </div>
                    </div>
                </div>
            </div>

            <div class="border rounded-xl bg-white m-6 p-4 ">
                <h2>${newsContent.title}</h2>
                <div class="text-gray-400 h-20">
                    ${newsContent.content}
                </div>
                {{__comments__}}
            </div>
        </div>
    `;

    function makeComment(comments, called = 0){
        const commentString = [];
                
        for(let i=0; i<comments.length; i++){
            commentString.push(`
                <div style="padding-left: ${called * 40}px;" class="mt-4">
                    <div class="text-gray-400">
                        <i class="fa fa-sort-up mr-2"></i>
                        <strong>${comments[i].user}</strong> ${comments[i].time_ago}
                    </div>
                    <p class="text-gray-700">${comments[i].content}</p>
                </div>
            `);

            if(comments[i].comments.length > 0){
                commentString.push(makeComment(comments[i].comments, called + 1)); // 재귀 호출
            }
        }

        return commentString.join('');
    }

    container.innerHTML = template.replace('{{__comments__}}', makeComment(newsContent.comments));
}

function router(){
    ...
}

window.addEventListener('hashchange', router);

router();

(확연히 기존 template 변수에 사용된 html 태그보다 스타일링을 통해 내용이 길어짐)

 

각 목록 화면과 내용 화면에 UI 부분을 tailwindCss를 사용해서 디자인을 수정했다. html 태그의 클래스를 보게되면 css의 속성(display: flex -> flex, justify-content: space-between -> justify-between 등)을 tailwindCss만의 방식으로 클래스명을 사용하여 스타일링한 것을 알 수 있다.

 

해커뉴스의 내용엔 comment 데이터가 있는데 comment안에 comment가 있는 형식으로 단계가 정해져 있지 않은 구조이다. comment 부분은 makeComment() 함수를 통해 배열 안의 배열을 재귀 호출을 통해서 조회한다. comment배열 안의 comment가 있는지 조건문으로 처리하고 comment안의 배열이 없을 때 해당하는 값을 return 한다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

+ Recent posts