CS Study/Projects
Project 13 : My Chrome
Ryannn
2022. 4. 15. 13:40
#기능
1. 실시간 시간 표시
2. Log-In을 수행하면 username을 로컬 스토리지에 저장하고 Hello (username) 표시
3. To-do list 표시
4. 현재 위치의 날씨 안내
5. 랜덤 명언 하단에 출력
6. 랜덤 배경화면 출력
#구현
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
@import url(style.css);
@import url('https://fonts.googleapis.com/css2?family=Lora:ital@1&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300&display=swap');
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100&family=Roboto:wght@400;700&display=swap" rel="stylesheet">
</head>
<body>
<h2 id = "clock"></h2>
<form class = "hidden" id = "login-form">
<input required maxlength = "15" placeholder="What is your name?">
</form>
<h1 id = "greeting" class = "hidden"></h1>
<form id = "todo-form">
<input type = "text" required placeholder="Write a To do">
</form>
<ul id = "todo-list"></ul>
<div id = "quotes">
<span id = "quote"></span>
<span id = "author"></span>
</div>
<div id = "weather">
<span></span>
<span></span>
</div>
<script src = "greeting.js"></script>
<script src = "clock.js"></script>
<script src = "quote.js"></script>
<script src = "background.js"></script>
<script src = "todo.js"></script>
<script src = "weather.js"></script>
</body>
</html>
.hidden{
display : none;
}
body{
display : block;
height: 100%;
margin : 0;
padding : 0;
}
#greeting,#clock{
font-family: 'Open Sans', sans-serif;
}
input{
background-color: transparent;
border-color : transparent;
border-bottom-color : white;
height : 30px;
width : 30%;
}
input:focus{
outline : none;
color : white;
text-align: center;
font-size: 24px;
}
input::placeholder{
color : white;
text-align: center;
font-size: 24px;
}
#clock{
display : flex;
margin: 0;
align-items: center;
justify-content: center;
height : 100vh;
font-size: 96px;
color : white;
}
#login-form{
position : absolute;
text-align : center;
margin : 0;
top : 55%;
left : 20%;
right : 20%;
font-size : 48px;
color : white;
font-family: 'Roboto', sans-serif;
}
#greeting{
position : absolute;
text-align : center;
margin : 0;
top : 55%;
left : 20%;
right : 20%;
font-size : 48px;
color : white;
}
#todo-form{
position : absolute;
text-align: center;
top : 62%;
left : 20%;
right : 20%;
font-size : 48px;
color : white;
font-family: 'Roboto', sans-serif;
}
#todo-list{
position : absolute;
text-align: center;
top : 70%;
left : 20%;
right : 20%;
font-size : 24px;
color : white;
}
#weather{
position : absolute;
top : 10px;
right : 10px;
text-align: center;
font-family: 'Roboto', sans-serif;
color : white;
}
#quotes{
position : absolute;
width : 100%;
bottom : 20px;
text-align: center;
z-index: 10;
color : white;
font-family: 'Lora', serif;
}
#author{
display : block;
}
button{
background-color: transparent;
border : none;
}
//로그인 후 사용자 환영 메시지 출력 기능
const loginForm = document.querySelector("#login-form");
const loginName = loginForm.querySelector("input");
const greeting = document.querySelector("#greeting");
const HIDDEN_CLASSNAME = "hidden";
const USERNAME_KEY = "username";
function onLoginSubmit(event){
event.preventDefault();
loginForm.classList.add(HIDDEN_CLASSNAME);
const username = loginName.value;
localStorage.setItem(USERNAME_KEY, username);
paintGreeting(username);
}
function paintGreeting(username){
greeting.innerText = "Hello " + username;
greeting.classList.remove(HIDDEN_CLASSNAME);
}
const savedUsername = localStorage.getItem(USERNAME_KEY);
if(savedUsername == null){
loginForm.classList.remove(HIDDEN_CLASSNAME);
loginForm.addEventListener("submit", onLoginSubmit);
}
else {
paintGreeting(savedUsername);
}
//To-do list 입력 및 출력 기능
const todoForm = document.getElementById("todo-form");
const todoInput = todoForm.querySelector("input");
const todoList = document.getElementById("todo-list");
let todos = []; //todo 저장하는 배열
function todoSave(){ //todo localstorage에 저장(string)
localStorage.setItem("todos",JSON.stringify(todos));
}
function todoDelete(event){ //todo 삭제하기
const deleteLi = event.target.parentElement;
deleteLi.remove();
todos = todos.filter((todo) => todo.id != parseInt(deleteLi.id));
todoSave();
}
function todoPaint(newTodoObj){ //리스트에 todo 삽입하기
const li = document.createElement("li");
li.id = newTodoObj.id;
const span = document.createElement("span");
span.innerText = newTodoObj.text;
const button = document.createElement("button");
button.innerText = "❌";
button.addEventListener("click",todoDelete);
li.appendChild(span);
li.appendChild(button);
todoList.appendChild(li);
}
function todoSubmit(event){ //input 폼에서 엔터 눌렀을 때 기능
event.preventDefault();
const newTodo = todoInput.value;
todoInput.value = "";
const newTodoObj = {
text : newTodo,
id : Date.now()
}
todos.push(newTodoObj);
todoPaint(newTodoObj);
todoSave();
}
todoForm.addEventListener("submit", todoSubmit);
const savedTodos = localStorage.getItem("todos");
if(savedTodos){
const parsedTodos = JSON.parse(savedTodos);
todos = parsedTodos;
parsedTodos.forEach(todoPaint);
}
//날씨 표시 기능
const API_KEYS = "c4e0733ed08482258c4ac8ebf689b078";
function geoOk(position){
let lat = position.coords.latitude;
let lon = position.coords.longitude;
const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEYS}&units=metric`;
fetch(url).then(response => response.json()).then(data =>{
const weatherTag = document.querySelector("#weather span:first-child");
const cityTag = document.querySelector("#weather span:last-child");
weatherTag.innerText = data.weather[0].main + "/" + Math.floor(data.main.temp);
cityTag.innerText = data.name;
});
}
function geoError(){
alert("We cannot find you!")
}
navigator.geolocation.getCurrentPosition(geoOk, geoError);
//초 단위 현재 시각 표시 기능
const clock = document.querySelector("#clock");
function getClock(){
const date = new Date();
const hours = String(date.getHours()).padStart(2,"0");
const minutes = String(date.getMinutes()).padStart(2,"0");
const seconds = String(date.getSeconds()).padStart(2,"0");
clock.innerText = hours + ":" + minutes + ":" + seconds;
}
getClock();
setInterval(getClock, 1000);
//랜덤 명언 출력 기능
const quotes = [
{
quote: "The way to get started is to quit talking and begin doing.",
author: "Walt Disney",
},
{
quote: "Life is what happens when you're busy making other plans.",
author: "John Lennon",
},
{
quote:
"The world is a book and those who do not travel read only one page.",
author: "Saint Augustine",
},
{
quote: "Life is either a daring adventure or nothing at all.",
author: "Helen Keller",
},
{
quote: "To Travel is to Live",
author: "Hans Christian Andersen",
},
{
quote: "Only a life lived for others is a life worthwhile.",
author: "Albert Einstein",
},
{
quote: "You only live once, but if you do it right, once is enough.",
author: "Mae West",
},
{
quote: "Never go on trips with anyone you do ntot love.",
author: "Hemmingway",
},
{
quote: "We wander for distraction, but we travel for fulfilment.",
author: "Hilaire Belloc",
},
{
quote: "Travel expands the mind and fills the gap.",
author: "Sheda Savage",
},
];
const quote = document.querySelector("#quotes span:first-child");
const author = document.querySelector("#quotes span:last-child");
const showQuotes = quotes[Math.floor(Math.random()*quotes.length)];
quote.innerText = showQuotes.quote;
author.innerText = showQuotes.author;
//랜덤 배경화면 출력 기능
const images = ["0.jpg", "1.jpg", "2.jpg"];
const randomImage = images[Math.floor(Math.random()*images.length)];
const body = document.querySelector("body");
const bgImage = document.createElement("img");
bgImage.src = randomImage;
bgImage.id = "bgImg";
body.appendChild(bgImage);
//bgImage 제어
bgImage.style.position = "absolute";
bgImage.style.width = "100%";
bgImage.style.height = "100%";
bgImage.style.top = "0";
bgImage.style.left = "0";
bgImage.style.zIndex = "-1";
이전 소규모 개인프로젝트를 진행할 때는 HTML, CSS, Javascript 파일 딱 3개만 만들어서 Javascript 파일에 모든 기능을 쑤셔넣으면서 코드 작성을 했었는데 그렇게 하니 제 머리 속으로 정리도 잘 안되고 복잡하더라구요..
그래서 제가 구현할 기능을 최대한 구분해본 뒤 그 기능에 따른 Javascript 파일을 각각 만들었습니다.