Diary ๊ตฌํ˜„ํ•˜๊ธฐ ๐Ÿ“(1)

heeezniยท2025๋…„ 5์›” 19์ผ

๋‹ฌ๋ ฅ์„ ๋งŒ๋“ค์—ˆ์œผ๋‚˜..๋””์ž์ธ์ด ์ฒ˜์ฐธํ–ˆ๋˜ ์ง€๋‚œ ๊ณผ๊ฑฐ..
boxSizing="border-box"๋กœ ํ•ด๊ฒฐ!

1. ๊ธฐ๋ณธ ๊ตฌ์กฐ ์„ค๊ณ„ (HTML + CSS)

#wrapper{
    width: 700px;
    height: 750px;
    margin: auto;
}
#info{
    width: 100%;
    height: 60px;
    background-color: rgb(52, 66, 30);
}
#header{
    width: 100%;
    height: 50px;
    background-color: green;
    text-align: center;
    line-height: 50px;
}
#header h2{
    display: inline-block;
    margin: 0px 5px;
}
#header a{text-decoration: none;}
#days{
    width: 100%;
    height: 40px;
    background-color: rgb(200, 243, 137);
    float: left;
}
#content{
    width: 100%;
    height: 600px;
    background-color: rgb(246, 255, 231);
    float: left;
    position: relative;
}
#dialog{
    width: 220px;
    height: 240px;
    border-radius: 10px;
    background-color: pink;
    position: absolute;
    /* content div์˜ ๋‹ค๋ฅธ ์…€๋“ค๊ณผ ๊ณต์กดํ•ด์•ผ ํ•˜๋ฏ€๋กœ */
    z-index: 50;
    /* z-index๋Š” ์–ด๋–ค ์š”์†Œ๊ฐ€ ํ™”๋ฉด์—์„œ 
    ๋‹ค๋ฅธ ์š”์†Œ๋“ค๋ณด๋‹ค "์œ„์— ๋ณด์ด๊ฒŒ" ํ• ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ์ˆซ์ž
    z์ถ• ๊ฐ’์ด ํด์ˆ˜๋ก ์œ„๋กœ ์˜ฌ๋ผ์˜ด */
    display: none;
    text-align: center;
}
#dialog input, textarea {
    border: 1px solid #ccc;
    margin: 1px;
}
#dialog input{
    width: 96%;
    height: 27px;
}
#dialog textarea{
    width: 96%;
    height: 163px;
}
<body>
    <div id="wrapper">
        <div id="info"></div>
        <div id="header">
            <a href="javascript:prev()">์ด์ „</a>
            <h2></h2>
            <a href="javascript:next()">๋‹ค์Œ</a>
        </div>
        <div id="days"></div>
        <div id="content">
            <div id="dialog">
                <div>
                    <input type="text" placeholder="์ œ๋ชฉ ์ž…๋ ฅ" id="t_title">
                </div>
                <div>
                    <textarea placeholder="๋‚ด์šฉ ์ž…๋ ฅ" id="t_detail"></textarea>
                </div>
                <div>
                    <button id="bt_regist">๋“ฑ๋ก</button>
                    <button id="bt_close">๋‹ซ๊ธฐ</button>
                </div>
            </div>
        </div>
    </div>
</body>

2. JavaScript ๋กœ์ง

์ „์ฒด ํ๋ฆ„

[ ํŽ˜์ด์ง€ ๋กœ๋“œ ]
โ†“
[ getCurrentTime() โ†’ ํ˜„์žฌ ์—ฐ/์›” ์ €์žฅ ]
โ†“
[ createCell() โ†’ 42๊ฐœ ์…€ ๋งŒ๋“ค๊ธฐ ]
โ†“
[ printNum() โ†’ ๋‚ ์งœ ์ถœ๋ ฅ ]
โ†“
[ ์ด์ „ / ๋‹ค์Œ ํด๋ฆญ ์‹œ ]
โ†’ getCurrentTime()
โ†’ printTitle()
โ†’ clearCell()
โ†’ printNum()
โ†“
[ ์…€ ํด๋ฆญ ] โ†’ openDialog(obj)
โ†“
[ '๋‹ซ๊ธฐ' ๋˜๋Š” esc ] โ†’ closeDialog()
โ†“
[ ์ œ๋ชฉ/๋‚ด์šฉ ์ž…๋ ฅ ํ›„ '๋“ฑ๋ก' ] โ†’ regist()
โ†“
[ ์…€์— ์ œ๋ชฉ/์•„์ด์ฝ˜ ํ‘œ์‹œ + diaryArray์— ์ €์žฅ ]

    let cellArray=Array.from({length:6},()=> Array(7).fill(0)); // 6ํ–‰ 7์—ด ์…€ ๋ฐฐ์—ด
    let currentYear;     // ํ˜„์žฌ ์—ฐ๋„
    let currentMonth;    // ํ˜„์žฌ ์›”
    let currentCell;     // ์„ ํƒ๋œ ์…€ ๊ฐ์ฒด (๋ชจ๋“ ๊ฒŒ ๋‹ค ๋“ค์–ด ์žˆ์Œ)
    let diaryArray=[]; // ๋“ฑ๋ก๋œ ๋‹ค์ด์–ด๋ฆฌ ๊ฐ์ฒด๋“ค ์ €์žฅ (DB ๋Œ€์‹  ๋ฐฐ์—ด)

    function printTitle(){
        document.querySelector("#header h2").innerText = `${currentYear}๋…„ ${currentMonth +1}์›”`;
    }

    function getStartday(year, month){
        let d = new Date(year, month, 1);
        return d.getDay(); // 1์ผ์˜ ์š”์ผ
    }

    function getLastdate(year, month){
        let d = new Date(year, month + 1, 0);
        return d.getDate(); // ๋งˆ์ง€๋ง‰ ๋‚ ์งœ
    }

    function printNum(){
        let index = 0; //์…€์˜ ์ˆœ๋ฒˆ
        let date = 1; //์ถœ๋ ฅ๋  ์‹ค์ œ ๋‚ ์งœ

        for (let i = 0; i < 6; i++){
            for (let j = 0; j < 7; j++) {
              	//โญ์ด๋ฒˆ ๋‹ฌ 1์ผ ์š”์ผ(index)๋ถ€ํ„ฐ ๋‚ ์งœ๋ฅผ ํ•˜๋‚˜์”ฉ ์ฐ๊ณ , ๋งˆ์ง€๋ง‰ ๋‚ ์งœ๊นŒ์ง€๋งŒ ์ฐ์ž
                if (index >= getStartday(currentYear, currentMonth) &&
                    date <= getLastdate(currentYear, currentMonth)){
                    cellArray[i][j].setDate(currentYear, currentMonth, date);
                  	date++;
                }
                index++;
            }
        }
    }

    /*---------------------------------------------
    ๋กœ๋“œ ์‹œ์  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋‹ค์Œ๋ฒ„ํŠผ, ์ด์ „๋ฒ„ํŠผ์— ์˜ํ•ด์„œ๋„ 
    currentYear, currentMonth ๊ตฌํ•ด์•ผ ํ•˜๋ฏ€๋กœ
    ์ฝ”๋“œ๊ฐ€ ์ค‘๋ณต๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜๋กœ ๋นผ๋†“์ž!
     ------------------------------------------------*/
    function getCurrentTime(year, month){
      	/*์ „๋‹ฌ๋ฐ›์€ month๊ฐ€ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด (์˜ˆ: -1, 12) 
        Date๊ฐ€ ์ž๋™์œผ๋กœ ์—ฐ๋„ ๊ณ„์‚ฐํ•ด์คŒ*/
        let d = new Date(year, month);
        currentYear = d.getFullYear();
        currentMonth = d.getMonth();
    }

    function createCell(){
        for (let i = 0; i < 6; i++){
            for (let j = 0; j < 7; j++){
                cellArray[i][j] = new Cell(
                    document.getElementById("content"),
                    100 * j, 100 * i, 100, 100,
                    "rgb(246, 255, 231)", "lightgreen", 0);
            }
        }
    }

    function clearCell(){
        for (let i = 0; i < 6; i++){
            for (let j = 0; j < 7; j++){
                cellArray[i][j].numDiv.innerText = "";
                cellArray[i][j].titleDiv.innerText = "";
                // ์•„์ด์ฝ˜ ์ œ๊ฑฐ๋Š” ํ•„์š” ์‹œ ๊ตฌํ˜„
            }
        }
    }

    function prev(){
        getCurrentTime(currentYear, currentMonth - 1);
        printTitle();
        clearCell();
        printNum();
    }

    function next(){
        getCurrentTime(currentYear, currentMonth + 1);
        printTitle();
        clearCell();
        printNum();
    }

    /*---------------------------------------------
    ์ˆจ๊ฒจ์ ธ ์žˆ๋˜ ๋Œ€ํ™”์ฐฝ์„ ๋„์šฐ๋˜, 
    ๊ทธ ์œ„์น˜๋Š” ์ง€๊ธˆ ํด๋ฆญํ•œ ๋ฐ”๋กœ ๊ทธ ์…€์˜ x,y๋ฅผ ๋”ฐ๋ผ๊ฐ€์•ผํ•จ
    ------------------------------------------------*/
    function openDialog(obj){ // ํด๋ฆญ๋œ Cell ์ธ์Šคํ„ด์Šค๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์Œ
      	//ํ˜„์žฌ ์…€์— ๋Œ€ํ•œ ์ „์—ญ๋ณ€์ˆ˜์ธ currentCell์— 
      	//obj๋ฅผ ๋ณด๊ด€ํ•ด๋†“์ž
        currentCell = obj;
        let dialog = document.getElementById("dialog");
        dialog.style.display = "block"; // โ†” none
        dialog.style.position = "absolute"; //ํด๋ฆญํ•œ ์…€ ์œ„์น˜์— ๋งž์ถฐ ์ •ํ™•ํžˆ ๋„์šฐ๊ธฐ ์œ„ํ•ด
        dialog.style.left = obj.x + "px";
        dialog.style.top = obj.y + "px";
    }

    function closeDialog(){
        document.getElementById("dialog").style.display = "none";
        document.getElementById("t_title").value = "";
        document.getElementById("t_detail").value = "";
    }

    function regist(){
        let diary ={ //๋‹ค์ด์–ด๋ฆฌ ํ•œ ๊ฑด์˜ ๋ฐ์ดํ„ฐ๋ฅผ โญ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿดโญ๋กœ ๊ตฌ์„ฑ
            year: currentYear,
            month: currentMonth,
            date: currentCell.date,
            title: document.getElementById("t_title").value, //์ œ๋ชฉ ์ž…๋ ฅ๊ฐ’
            icon: "./images/diarystar.png",
            detail: document.getElementById("t_detail").value //๋‚ด์šฉ ์ž…๋ ฅ๊ฐ’
        };

        currentCell.titleDiv.innerText = diary.title;
        currentCell.renderIcon(diary.icon, 25);
        diaryArray.push(diary);
        closeDialog();
    }

    addEventListener("load", ()=>{
        let d = new Date();
        getCurrentTime(d.getFullYear(), d.getMonth());
        printTitle();
        createCell();
        printNum();

       	//๋“ฑ๋ก ์ด๋ฒคํŠธ ๊ตฌํ˜„
        document.getElementById("bt_regist").addEventListener("click", ()=>{
            regist();
        });

  		//์ƒˆ ์ฐฝ ๋‹ซ๊ธฐ ์ด๋ฒคํŠธ ๊ตฌํ˜„
      	document.getElementById("bt_close").addEventListener("click", ()=>{
            closeDialog();
        });

        document.body.addEventListener("keyup", function (e){
            if(e.keyCode == 27) closeDialog(); //esc๋ˆŒ๋ €์„ ๋•Œ ์ฐฝ ๋‹ซ๊ธฐ
        });
    });

์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ

0์œผ๋กœ ์ฑ„์šด 6ํ–‰ 7์—ด์˜ 2์ฐจ์› ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด๋ณด์ž

"๋ฐ˜๋ณต๋ฌธ์„ ๋‚ด๊ฐ€ ๋Œ๋ ค?"
์ด ๋•Œ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ

โœ… ์„ ์–ธํ˜•

โ€œ๋ฌด์—‡์„ ํ•  ๊ฒƒ์ธ์ง€โ€๋ฅผ ์„ ์–ธ์ ์œผ๋กœ ์ ์€ ๋ฐฉ์‹

let cellArray = Array.from({ length: 6 }, ()=> Array(7).fill(0));

Array.from({ length: 6 }, ...)
๊ธธ์ด 6์˜ ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ณ  โ†’ ํ–‰(row) 6๊ฐœ
()=> Array(7).fill(0)
๊ฐ ํ–‰๋งˆ๋‹ค ๊ธธ์ด 7์˜ ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด์„œ 0์œผ๋กœ ์ฑ„์›€ โ†’ ์—ด(column) 7๊ฐœ

โœ… ๋ช…๋ นํ˜•

โ€œ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€โ€๋ฅผ ์ ˆ์ฐจ์ ์œผ๋กœ ๋ช…๋ นํ•˜๋Š” ๋ฐฉ์‹

let cellArray = [];
for (let i = 0; i < 6; i++) {
    let row = [];
    for (let j = 0; j < 7; j++) {
        row.push(0);
    }
    cellArray.push(row);
}

3. Cellํด๋ž˜์Šค

๋ชฉ์ : ์บ˜๋ฆฐ๋” ์…€ 1์นธ์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐ์ฒด

class Cell{
    constructor(container,x,y,width,height,bg,borderColor,date){
        //[๋‹ค์ด์–ด๋ฆฌ ๊ด€๋ จ ๋‚ด์šฉ]
        this.year;
        this.month;
        this.date=date;
        this.icon;

        //[UI ๊ด€๋ จ ๋‚ด์šฉ]
        this.container=container;
        this.div=document.createElement("div"); //์…€ ์ž์ฒด๋ฐ•์Šค
        this.numDiv=document.createElement("div"); //๋‹ฌ๋ ฅ ๋‚ ์งœ ์ถœ๋ ฅํ•  ์˜์—ญ
        this.titleDiv=document.createElement("div"); //์ผ์ •์ œ๋ชฉ
        this.iconDiv=document.createElement("div"); //์•„์ด์ฝ˜์ด ์œ„์น˜ํ•  ์˜์—ญ
        this.x=x;
        this.y=y;
        this.width=width;
        this.height=height;
        this.bg=bg;
        this.borderColor=borderColor;
        
        //์…€ div style
        this.div.style.position="absolute";
        this.div.style.left=this.x+"px";
        this.div.style.top=this.y+"px";
        this.div.style.width=this.width+"px";
        this.div.style.height=this.height+"px";
        this.div.style.background=this.bg;
        this.div.style.border="1px solid "+this.borderColor;
        this.div.style.borderRadius=5+"px";
        this.div.style.boxSizing="border-box"; //border, margin, padding์— ์˜ํ•œ ๋ฐ•์Šค์˜ ํฌ๊ธฐ๊ฐ€
                                                // outside์ชฝ์œผ๋กœ ์ปค์ง€์ง€ ์•Š๊ณ  inside์ชฝ์œผ๋กœ ์ ์šฉ๋˜์–ด 
                                                // ๋„ˆ๋น„์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ
        
        //๋‚ ์งœ ์ถœ๋ ฅ div style
        this.numDiv.style.width=100+"%";
        this.numDiv.style.height=25+"px";
        this.numDiv.style.textAlign="right";
        this.numDiv.style.padding="0px 5px 0px 0px"; // (top-right-bottom-left) ์˜ค๋ฅธ์ชฝ์— 5pxํŒจ๋”ฉ
        this.numDiv.style.boxSizing="border-box";

        //๋‹ค์ด์–ด๋ฆฌ ์ œ๋ชฉ div style
        this.titleDiv.style.width=100+"%";
        this.titleDiv.style.height=25+"px";
      
        //์•„์ด์ฝ˜ ์˜์—ญ div style
        this.iconDiv.style.width=100+"%";
        this.iconDiv.style.height=50+"px";

        //์…€์— 3์ธต div ๊ฐ๊ฐ ๋ถ€์ฐฉ
        this.div.appendChild(this.numDiv);
        this.div.appendChild(this.titleDiv);
        this.div.appendChild(this.iconDiv);

        this.container.appendChild(this.div);

        //์…€ ํด๋ฆญ์‹œ ํŒ์—…๋„์šฐ๊ธฐ
        this.div.addEventListener("click", ()=>{ //ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋Š” this๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†์Œ
            openDialog(this); //์ด this๋Š” ์ƒ์œ„์Šค์ฝ”ํ”„์˜ this(=ํ˜„์žฌ ์…€ ์ธ์Šคํ„ด์Šค)
        });
    }
    //์…€์— ๋ณด์—ฌ์งˆ ๋‚ ์งœ๋ฅผ ์ˆ˜์‹œ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋ฉ”์„œ๋“œ์˜ ๋Œ€์ƒ์ด ๋  ์ˆ˜ ์žˆ์Œ
    setDate(year, month, date){
        this.year=year;
        this.month=month;
        this.date=date;

        //๋ Œ๋”๋ง ์ฒ˜๋ฆฌ
        this.numDiv.innerText=date;
    }
    //์…€์ด ์ž์‹ ์ด ๋ณด์œ ํ•œ ์•„์ด์ฝ˜์„ ๊ทธ๋ฆฌ๊ธฐ
    renderIcon(src, width){ //์–ด๋–ค ์ด๋ฏธ์ง€๋ฅผ ์›ํ•˜๋Š”์ง€๋Š” ํ˜ธ์ถœ์ž๊ฐ€ ๊ฒฐ์ •
        this.icon=document.createElement("img");
        this.icon.src=src;
        this.icon.style.width=width+"px"; //์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ ์กฐ์ •
        this.iconDiv.appendChild(this.icon);
    }
}
profile
์•„์ด๋“ค์˜ ๊ฐ€๋Šฅ์„ฑ์„ ๋ฏฟ์—ˆ๋˜ ๋งˆ์Œ ๊ทธ๋Œ€๋กœ, ์ด์ œ๋Š” ๋‚˜์˜ ๊ฐ€๋Šฅ์„ฑ์„ ๋ฏฟ๊ณ  ๋‚˜์•„๊ฐ€๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.๐ŸŒฑ

0๊ฐœ์˜ ๋Œ“๊ธ€