728x90

Click! 👉 https://dasolpark.github.io/Dasol_JS_Calculator/

 

Calculator

 

dasolpark.github.io

Github 👉 https://github.com/DasolPark/Dasol_JS_Calculator

 

DasolPark/Dasol_JS_Calculator

Calculator with Vanilla JavaScript. Contribute to DasolPark/Dasol_JS_Calculator development by creating an account on GitHub.

github.com

 Vanilla JavaScript로 개발한 🧮'계산기' 입니다.

eval을 이용하여 효율적으로 개발할 수 있었으며, 여러가지 변수는 고려하지 않고 단순하게 만들어 보았습니다😊

Main 화면
실행 화면
결과 화면

728x90

Click! 👉https://dasolpark.github.io/Dasol_ReactJS_Movie_App/#/

 

Movie App

 

dasolpark.github.io

Github 👉https://github.com/DasolPark/Dasol_ReactJS_Movie_App

 

DasolPark/Dasol_ReactJS_Movie_App

ReactJS with Movie App. Contribute to DasolPark/Dasol_ReactJS_Movie_App development by creating an account on GitHub.

github.com

🎞 가장 높은 평점을 받은 영화와 최근 개봉한 영화 리스트를 알려주는 Movie App입니다.

✨ state 관리, event 관리, API를 이용해 데이터 받아오기는 물론이고,
react-router-dom을 이용하여 HashRouter, Route, Link를 연습하기에 좋은 프로젝트입니다.

가장 상단에 위치한 컴포넌트 영화 제목, 장르, 개봉 연도, 평점, 러닝타임, 요약 등 자세한 영화 정보를 안내합니다.
그리고 이 컴포넌트를 클릭하면 해당 영화 데이터와 함께 Detail 페이지로 이동하여 더욱 더 자세한 영화 정보를 안내합니다.

TOP RATED 페이지에서는 평점 순위대로 영화 목록이 출력되며,
LATEST 페이지에서는 가장 최근에 개봉한 영화를 출력해줍니다.

웹과 모바일에서 모두 이용 가능하도록 디자인하였습니다.

Top Rated Page
Latest Page
Detail Page
Full Page

728x90

Click! 👉 https://dasolpark.github.io/Dasol_React_Video_Search_With_YouTube_API/

 

Video Search With YouTube API

 

dasolpark.github.io

Github 👉 https://github.com/DasolPark/Dasol_React_Video_Search_With_YouTube_API

 

DasolPark/Dasol_React_Video_Search_With_YouTube_API

ReactJS with YouTube API. Contribute to DasolPark/Dasol_React_Video_Search_With_YouTube_API development by creating an account on GitHub.

github.com

🔍 YouTube API를 이용해 YouTube 영상을 검색하는 간단한 웹 앱 사이드 프로젝트입니다.

✨ Functional? or Class? Component, Communicating Child to Parent,  Deeply Nested Callbacks, Event,
axios를 이용하여 API 다루기 등 개념을 익히기에 좋습니다.
앞서 만들었던 Unsplash 프로젝트와 중복되는 개념이 많아 React 기초를 확고히 다지기 좋은 프로젝트입니다.

영상 리스트는 최대 30개까지 출력되며,
grid를 활용하여 모바일에서도 문제 없이 사용 가능하도록 디자인하였습니다.

랜딩 페이지
영상 리스트
전체 페이지

 

728x90

Click! 👉 https://dasolpark.github.io/Dasol_React_Free_Image_Search_With_Unsplash/

 

Free Image Search with Unsplash

 

dasolpark.github.io

Github 👉https://github.com/DasolPark/Dasol_React_Free_Image_Search_With_Unsplash

 

DasolPark/Dasol_React_Free_Image_Search_With_Unsplash

ReactJS with Unsplash API. Contribute to DasolPark/Dasol_React_Free_Image_Search_With_Unsplash development by creating an account on GitHub.

github.com

🔍Unsplash API를 이용해 무료 이미지를 검색하는 간단한 웹 앱 사이드 프로젝트입니다.

✨ components 구성하기, state 다루기, 부모와 자식 component 간 데이터를 주고 받기, event 다루기, 
React.createRef()를 이용하여 DOM 접근하기, axios를 이용하여 API 다루기 같은 개념을 익히기에 좋습니다.

이미지 결과는 최대 30개까지 출력하며, 각 이미지 크기에 맞게 grid 크기를 적용하였습니다.

 

랜딩 페이지
검색 후 출력된 이미지 일부 페이지
검색 후 출력된 이미지 전체 페이지

728x90

Click! 👉 https://dasolpark.github.io/Dasol_CSS_Web_And_Mobile_App_Design/

 

Colorful eCommers

lorem Lorem ipsum dolor sit amet consectetur adipisicing elit. Ratione, consequatur maxime? Adipisci modi consectetur molestias quis debitis. Nam cupiditate odio sit, numquam sequi debitis necessitatibus. Amet doloremque sunt asperiores officiis. Lear more

dasolpark.github.io

Github 👉https://github.com/DasolPark/Dasol_CSS_Web_And_Mobile_App_Design

 

DasolPark/Dasol_CSS_Web_And_Mobile_App_Design

Flexbox, Grid, Postcss, CSSNext, CSS4, Parcel. Contribute to DasolPark/Dasol_CSS_Web_And_Mobile_App_Design development by creating an account on GitHub.

github.com

✨ 특징

Flexbox, CSS Grid, PostCSS, CSSNext, CSS4

💻 결과물
Website and Mobile App

Colorful eCommers Website
Meal Mobile App
New Mobile App 1
New Mobile App 2

 

Recipe Mobile App
Artistic Social Network Mobile App
Architecture Website
Artistic Blog Website

728x90

Click! 👉 https://dasolpark.github.io/Dasol_React_Current_Weather_With_Open_Weather_Map_API/

 

Current Weather With Open Weather Map API

 

dasolpark.github.io

Github 👉https://github.com/DasolPark/Dasol_React_Current_Weather_With_Open_Weather_Map_API

 

DasolPark/Dasol_React_Current_Weather_With_Open_Weather_Map_API

ReactJS with Open Weather Map API. Contribute to DasolPark/Dasol_React_Current_Weather_With_Open_Weather_Map_API development by creating an account on GitHub.

github.com

Navigator를 이용해 latitude, longitude를 받고,
해당 위치를 기반으로 Open Weather Map API를 이용해 날씨 정보를 받는 간단한 사이드 프로젝트입니다.

봄, 여름, 가을, 겨울 모두 다른 디자인을 적용하였고,
현재위치, 현재 날씨, 체감 온도, 최저 기온, 최고 기온, 현재 습도 정보를 제공합니다.

위치를 제공을 요청하는 페이지
봄 페이지
여름 페이지
가을 페이지
겨울 페이지

728x90

✨ DB를 이용해 게시판을 만들기 전에, 간단히 연습할 수 있는 방법입니다.

Chrome Browser - F12(or Inspect) - Application - Storage - Local Storage
위의 경로를 찾아 들어가면, 내 브라우저에만 저장되는 공간이 있다. 이걸 이용해 간단하게 게시판을 구현할 수 있다.

📢 Local Storage 사용법

1. 데이터 저장하기
localStorage.setItem( 명칭, 저장할 내용 );

2. 데이터 불러오기
localStorage.getItem( 명칭 )

글은 여러 개이며 하나의 글에 필요한 데이터번호, 제목, 내용, 작성자, 작성일, 조회이기 때문에
하나의 글을 저장할 때는 배열로 저장하고, 하나의 글에 들어간 데이터는 Object로 저장해주면 간단히 저장할 수 있다.
예를 들어, objArr = [ { num: 1, title: 'title1'... }, { num: 2, title: 'title2'... }, ... ] 형식으로 저장하면 된다.

📢 게시판을 만들어가는 작업 순서

1. input과 form tag를 이용해 글을 작성하는 부분을 만들어주고, 이 내용을 받아 localStorage에 저장해준다.
2. localStorage에서 데이터를 받아와, DOM을 이용해 목록을 출력해준다.
3. 글 제목을 누르면, 글 내용이 출력되도록 해준다.
4. 한 화면에는 최대 5개의 글만 보여주며, 그 이상의 글은 인덱스 처리를 해주고 눌렀을 때 해당 목록을 보여준다.

😃 보기 쉽게 하기 위해서, 싱글 페이지글 목록, 글 내용, 작성 부분을 한 번에 보여주도록 구성하였다.
이 과정에서 글 번호가 곧 데이터 index이므로 꼬이지 않도록 Sort해주는 작업이 필요하며,
각 글 목록마다 id를 다르게 부여하여, event를 받아줄 수 있도록 해주는 작업이 필요하다.

아래는 예제가 실제로 실행되는 모습이다.

페이지 실행 첫 번째 화면
글 제목을 눌렀을 때, 내용을 보여주는 화면
2번째 글 목록 화면
3번째 글 목록 화면
글 작성하는 부분
위에서 작성한 글 내용 보기

이렇게 연습을 하고, DB와 함께 진행할 때는 어떻게 적용하고 개발을 진행해 나가야 할지 고민하면 될 듯 하다.

궁금한 점이 있으시면 언제든 댓글 달아주세요!

Full Code (https://github.com/DasolPark/Play-Ground_JavaScript) board.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Board with Local Storage</title>
<link
href="https://fonts.googleapis.com/css?family=Jua&display=swap"
rel="stylesheet"
/>
<style>
* {
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-family: 'Jua', sans-serif;
}
body {
padding: 0px;
margin: 0px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
height: 95vh;
background-color: #f6f9fc;
}
 
.main__container {
height: 700px;
padding-top: 10px;
padding-bottom: 10px;
}
 
.board__container,
.contents__container,
.editor__container {
width: 700px;
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: column;
background-color: #ffffff;
}
 
.board__container {
margin: 10px 0px 0px 0px;
height: 220px;
padding-top: 10px;
padding-bottom: 10px;
border-radius: 15px;
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1);
position: relative;
}
 
.contents__container {
margin: 10px 0px;
height: 220px;
padding-top: 10px;
padding-bottom: 10px;
border-radius: 15px;
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1);
}
 
.editor__container {
margin: 10px 0px;
height: 220px;
padding-top: 10px;
padding-bottom: 10px;
border-radius: 15px;
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1);
}
 
/* Board Lists */
.board {
width: 600px;
text-align: center;
margin-bottom: 15px;
}
 
.board__index-container {
position: absolute;
bottom: 10px;
}
 
.board__index-link {
all: unset;
margin-right: 5px;
}
 
.board__index-link:hover {
cursor: pointer;
color: blue;
}
 
/* Contents */
.contents__titles {
width: 600px;
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 10px;
border-bottom: 2px solid rgba(0, 0, 0, 0.08);
margin-bottom: 20px;
}
 
.contents__column {
width: 200px;
display: flex;
justify-content: space-around;
align-items: center;
}
 
.contents__content {
width: 600px;
display: flex;
justify-content: start;
align-items: center;
}
 
/* Editor */
.editor__form {
width: 600px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
 
input {
all: unset;
border-radius: 5px;
border: 1px solid rgba(0, 0, 0, 0.5);
}
 
.editor__title-input,
.editor__content-input {
width: 100%;
padding: 5px 10px;
margin-bottom: 10px;
}
 
.editor__content-input {
height: 100px;
}
 
.editor__btn {
all: unset;
border: 1px solid rgba(0, 0, 0, 0.5);
border-radius: 5px;
padding: 5px 10px;
}
 
button:active {
transform: scale(0.93);
}
</style>
</head>
<body>
<main class="main__container">
<div class="board__container">
<table class="board">
<thead class="board__table-head">
<tr class="board__titles">
<th class="board__column">번호</th>
<th class="board__column">제목</th>
<th class="board__column">작성자</th>
<th class="board__column">작성일</th>
<th class="board__column">조회</th>
</tr>
</thead>
<tbody class="board__contents" id="board-body"></tbody>
</table>
<div class="board__index-container" id="index-container"></div>
</div>
<div class="contents__container"></div>
<div class="editor__container">
<form action="#" class="editor__form" id="editor-form">
<input
type="text"
class="editor__title-input"
id="editor-title-input"
placeholder="제목"
/>
<input
type="text"
class="editor__content-input"
id="editor-content-input"
placeholder="내용"
/>
<button class="editor__btn" id="editor-submit-btn">작성 완료</button>
</form>
</div>
</main>
<script>
const boardTableBody = document.querySelector('#board-body');
 
const contentsContainer = document.querySelector('.contents__container');
 
const editorForm = document.querySelector('#editor-form');
const titleInput = document.querySelector('#editor-title-input');
const contentInput = document.querySelector('#editor-content-input');
 
const BOARDLIST_LS = 'boardLists';
const boardListsObj = [];
let nums = 0;
let author = 'David';
let date = new Date();
let views = Math.floor(Math.random() * 99) + 1;
 
function onTitleClick(e) {
contentsContainer.textContent = '';
const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS));
const index = e.target.parentNode.id.replace(/[a-z|-]/gi, '');
 
const contentsTitles = document.createElement('div');
contentsTitles.classList.add('contents__titles');
 
const contentsColumnFirst = document.createElement('div');
contentsColumnFirst.classList.add('contents__column');
 
const contentsTitle = document.createElement('div');
contentsTitle.classList.add('contents__title');
contentsTitle.textContent = lists[index].title;
 
// contents__titles > column >author, date, views
const contentsColumnSecond = document.createElement('div');
contentsColumnSecond.classList.add('contents__column');
 
const contentsAuthor = document.createElement('div');
contentsAuthor.classList.add('contents__author');
contentsAuthor.textContent = lists[index].author;
 
const contentsDate = document.createElement('div');
contentsDate.classList.add('contents__date');
contentsDate.textContent = lists[index].date;
 
const contentsViews = document.createElement('div');
contentsViews.classList.add('contents__views');
contentsViews.textContent = lists[index].views;
 
const contentsContent = document.createElement('div');
contentsContent.classList.add('contents__content');
contentsContent.textContent = lists[index].content;
 
contentsColumnFirst.appendChild(contentsTitle);
 
contentsColumnSecond.appendChild(contentsAuthor);
contentsColumnSecond.appendChild(contentsDate);
contentsColumnSecond.appendChild(contentsViews);
 
contentsTitles.appendChild(contentsColumnFirst);
contentsTitles.appendChild(contentsColumnSecond);
 
contentsContainer.appendChild(contentsTitles);
contentsContainer.appendChild(contentsContent);
}
 
function assignIndex() {
const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS));
if (!lists) {
nums = 0;
} else {
nums = parseInt(lists[lists.length - 1].num) + 1;
}
}
 
function onEditorFormSubmit(e) {
e.preventDefault();
 
const title = titleInput.value;
const content = contentInput.value;
 
const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS));
if (!lists) {
const objArr = [];
objArr.push({
num: `${nums++}`,
title: `${title}`,
author: `${author}`,
date: `${date.getFullYear()}.${date.getMonth() +
1}.${date.getDate()}.`,
views: `${views++}`,
content: `${content}`
});
 
localStorage.setItem(BOARDLIST_LS, JSON.stringify(objArr));
} else {
lists.push({
num: `${nums++}`,
title: `${title}`,
author: `${author}`,
date: `${date.getFullYear()}.${date.getMonth() +
1}.${date.getDate()}.`,
views: `${views++}`,
content: `${content}`
});
 
localStorage.setItem(BOARDLIST_LS, JSON.stringify(lists));
}
 
titleInput.value = '';
contentInput.value = '';
titleInput.focus();
window.location.reload();
}
 
function showBoardLists() {
const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS));
 
lists.forEach((list, index) => {
if (index < 5) {
const tr = document.createElement('tr');
tr.classList.add('board__content');
 
const tdNum = document.createElement('td');
tdNum.classList.add('board__content-column');
tdNum.textContent = list.num;
 
const aTitle = document.createElement('a');
aTitle.href = '#';
aTitle.id = `link-to-content${index}`;
 
const tdTitle = document.createElement('td');
tdTitle.classList.add('board__content-column');
tdTitle.textContent = list.title;
 
aTitle.appendChild(tdTitle);
 
const tdAuthor = document.createElement('td');
tdAuthor.classList.add('board__content-column');
tdAuthor.textContent = list.author;
 
const tdDate = document.createElement('td');
tdDate.classList.add('board__content-column');
tdDate.textContent = list.date;
 
const tdViews = document.createElement('td');
tdViews.classList.add('board__content-column');
tdViews.textContent = list.views;
 
tr.appendChild(tdNum);
tr.appendChild(aTitle);
tr.appendChild(tdAuthor);
tr.appendChild(tdDate);
tr.appendChild(tdViews);
 
boardTableBody.appendChild(tr);
const linkToContent = document.querySelector(
`#link-to-content${index}`
);
linkToContent.addEventListener('click', onTitleClick);
} else if (index === 5) {
const boardIndexMax = Math.ceil(lists.length / 5);
for (let i = 0; i < boardIndexMax; i++) {
const indexContainer = document.querySelector('#index-container');
 
const aIndex = document.createElement('a');
aIndex.classList.add('board__index-link');
 
const spanIndexText = document.createElement('span');
spanIndexText.classList.add('board__index');
spanIndexText.textContent = i + 1;
 
aIndex.appendChild(spanIndexText);
indexContainer.appendChild(aIndex);
 
aIndex.addEventListener('click', () => {
showBoardListsNewPage(i);
});
}
}
});
}
 
function showBoardListsNewPage(pageIndex) {
boardTableBody.textContent = '';
const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS));
const limitPage = pageIndex * 5;
 
lists.forEach((list, index) => {
if (index >= limitPage && index < limitPage + 5) {
const tr = document.createElement('tr');
tr.classList.add('board__content');
 
const tdNum = document.createElement('td');
tdNum.classList.add('board__content-column');
tdNum.textContent = list.num;
 
const aTitle = document.createElement('a');
aTitle.href = '#';
aTitle.id = `link-to-content${index}`;
 
const tdTitle = document.createElement('td');
tdTitle.classList.add('board__content-column');
tdTitle.textContent = list.title;
 
aTitle.appendChild(tdTitle);
 
const tdAuthor = document.createElement('td');
tdAuthor.classList.add('board__content-column');
tdAuthor.textContent = list.author;
 
const tdDate = document.createElement('td');
tdDate.classList.add('board__content-column');
tdDate.textContent = list.date;
 
const tdViews = document.createElement('td');
tdViews.classList.add('board__content-column');
tdViews.textContent = list.views;
 
tr.appendChild(tdNum);
tr.appendChild(aTitle);
tr.appendChild(tdAuthor);
tr.appendChild(tdDate);
tr.appendChild(tdViews);
 
boardTableBody.appendChild(tr);
const linkToContent = document.querySelector(
`#link-to-content${index}`
);
linkToContent.addEventListener('click', onTitleClick);
}
});
}
 
editorForm.addEventListener('submit', onEditorFormSubmit);
 
if (boardTableBody) {
assignIndex();
showBoardLists();
}
</script>
</body>
</html>
728x90

Click! 👉 https://dasolpark.github.io/Dasol_JS_Momentum_Clone/

 

Welcome to Momentum Clone

 

dasolpark.github.io

Github 👉 https://github.com/DasolPark/Dasol_JS_Momentum_Clone

 

DasolPark/Dasol_JS_Momentum_Clone

Let's make momentum clone with Vanilla JS. Contribute to DasolPark/Dasol_JS_Momentum_Clone development by creating an account on GitHub.

github.com

항상 이용하고 있는 Chrome Extension Momentum
HTML/CSS/JavaScript
를 사용하여 나만의 스타일로 재구성 해봤습니다.

🌳배경 이미지는 무작위로 생성되며, 😃본인의 이름을 저장할 수 있고, ⛅간단한 날씨 정보도 얻을 수 있습니다.
또한, 📑해야 할 일 목록을 작성하여 체크하거나 삭제하며 사용할 수 있습니다.

날씨 APIopenweathermap, 배경 이미지 APIunsplash를 이용하였으며
이름과 해야 할 일 데이터Local Storage에 저장하였습니다.

브라우저 앱이기 때문에, 노트북이나 데스크톱 브라우저에 최적화되어 있습니다.

첫 번째 화면,이름을 묻는 페이지

 

두 번째 화면, 사용자를 반겨주며 오늘 가장 중요한 일을 작성할 수 있습니다.
세 번째 화면, 사용자를 반겨주며 작성된 오늘 가장 중요한 일을 확인할 수 있습니다.
네 번째 화면, 오늘 가장 중요한 일을 완료 표시 할 수 있습니다.
다섯 번째 화면, 해야 할 일 목록을 작성할 수 있습니다.
여섯 번째 화면, 해야 할 일 목록을 완료 표시 또는 삭제할 수 있습니다.

728x90

📳

Click! 👉 https://dasolpark.github.io/Dasol_CSS_WhatsApp_Clone/

 

Chats

Archived Chats 0 Broadcast Lists New Group

dasolpark.github.io

Github👉https://github.com/DasolPark/Dasol_CSS_WhatsApp_Clone

 

DasolPark/Dasol_CSS_WhatsApp_Clone

Let's make WhatsApp Design Clone with Responsive CSS - DasolPark/Dasol_CSS_WhatsApp_Clone

github.com

해외에서 많이 사용하는 메신저앱 WhatsApp의 디자인 패턴HTML CSS를 이용해 복제해 보았습니다.

📳모바일이나 💻데스크톱 등 어떤 브라우저에서도 디자인이 무너지지 않도록, 반응형 CSS를 적용하였으며,
JavaScript를 이용해 현재 시간 띄우기, 전화 목록 지우기, 채팅 메세지 등록을 간단히 구현해 보았습니다.

해당 프로젝트는 width:375, height:638 크기에 최적화되어 있습니다.

좌측 Status, 우측 Calls Page
좌측 Calls - Edit 기능, 우측 Calls - New Call Page
좌측 Chats, 우측 Chats - Chat Page
Settings Page

728x90

💪

Click! 👉 https://github.com/DasolPark/Dasol_JS_WorkoutTimer

JavaScript와 반응형 CSS를 사용하여 데스크톱 또는 모바일에서 사용할 수 있는 운동 도우미 타이머 어플리케이션입니다.

📌운동 종목과 종목의 세트를 상세히 작성할 수 있으며, 각 세트별로 완료한 시간을 체크해줍니다.
💡운동 종목과 세트는 추가 또는 삭제가 가능하며, 운동을 완료하면 완료된 시간을 수정할 수 없습니다.

Date Object를 이용하여 현재 시간을 표시하도록 만들었으며, 브라우저 Local Storage에 닉네임을 저장할 수 있도록 했습니다.
스탑워치는 setTimeout()을 이용하여 시간이 계속 증가될 수 있도록 하였습니다.
또한, DOM을 이용하여 종목이나 세트 element가 추가되거나 삭제될 수 있도록 제작하였습니다.

시작 화면과 운동이 입력된 화면
운동 시간을 체크하며 진행되는 화면
데스크톱 전체 화면

 

  1. 익명 2021.01.14 00:09

    비밀댓글입니다

    • 익명 2021.02.08 20:24

      비밀댓글입니다

+ Recent posts