반응형

2024.0415 업데이트 내용

- 디자인 수정

- 휴일 체크시 입력부분 Disable처리

- 버그 수정 및 코드 정리

 

------------------

 

다니는 회사가 자율 출퇴근이고 근무시간을 관리하는 HR이 있긴 하지만 조금 불편한 부분이 있어서 만들어보았다.

모바일 대응을 하긴 했는데 UX적으로 세로 스크롤이 길어지는 바람에 더 불편한 느낌이다. 나중에 개선을 좀 해야할것같고.

머 기본적으로 사용하는데는 문제는 없는것같다.

출근시간이 입력되어있고 퇴근시간이 입력되지 않은 첫번째 요일의 퇴근시간을 계산해 준다. 원래는 금요일 퇴근시간만 생각하고 만들었다가 금요일 휴일이면 어떻하지 하면서 개발이 수정되었다.

하루 기본 8시간 근무로 주 40시간을 채워야 하고, 하루 최대 근무 인정시간은 9시간으로 한시간을 누적시킬 수 있어서 금요일 전까지 최대 4시간을 누적시키면 (9+9+9+9) 36시간을 채울 수 있고 금요일은 4시간 근무만 하고 퇴근할 수 있다.

경우의 수가 좀 많다보니 코드가 아직은 완벽하지 않지만 조금씩 업데이트 해 나갈 생각이다.

 

테스트 페이지 링크

Github 링크

 

일주일 개인 근무시간 관리

일주일 개인 근무시간 관리 요일 출근 시간 퇴근 시간 휴가 시간 휴일 근무 인정 시간(최대 9시간) 적립시간 퇴근 가능 시간 계산 모든 설정 리셋

h9interaction.github.io

 

index.html

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>일주일 개인 근무시간 관리</title>
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
    <link rel="stylesheet" href="style.css?v=0.0.9">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
    <link rel="stylesheet" as="style" crossorigin
        href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css" />
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"
        integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/timepicker/jquery.timepicker.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/timepicker/jquery.timepicker.min.css">
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

</head>

<body>
    <div calss="content">
        <div class="title-center">일주일 개인 근무시간 관리</div>
        <div class="chart-container">
            <canvas id="workTimeChart"></canvas>
            <div class="total-remainning-time" id="total-remainning-time">
                -
            </div>
        </div>
        <div class="table-container">
            <table id="workHoursTable">
                <thead>
                    <tr>
                        <th class="table-title first">요일</th>
                        <th class="table-title second">출근 시간</th>
                        <th class="table-title third">퇴근 시간</th>
                        <th class="table-title forth">휴가 시간</th>
                        <th class="table-title fifth">휴일</th>
                        <th class="table-title sixth">근무 인정 시간(최대 9시간)</th>
                        <th class="table-title seventh">적립시간</th>
                    </tr>
                </thead>
                <tbody>
                    <!-- JavaScript를 통해 동적으로 행 추가 -->
                </tbody>
            </table>
        </div>
        <div class="action-container">
            <button onclick="calculatedayExitTime()">퇴근 가능 시간 계산</button>
            <button class="reset-all" onclick="resetAll()">모든 설정 리셋</button>
            <div id="dayExitTime"></div>
        </div>

        <script src="script.js?v=0.0.9"></script>
    </div>
</body>

</html>

 

 

script.js

const color1 = '#0ACFD9';
const color2 = '#F67777';
const color3 = '#666666';
const color4 = '#FFFFFF';
const color5 = '#f3f3f3';
const color6 = '#B068FF';
const color7 = '#F6F3FA';
const chartColor11 = '#C8A6F1'; // 휴일 색상
const chartColor22 = '#9CE4F1'; // 근무 인정 시간 색상
const chartColor33 = '#F7E58B'; // 휴가 시간 색상
const chartColor44 = '#F79999'; // 남은 시간 색상

let remainingMinutes;

window.onload = function () {
    makeTable();

    $('.timepicker-input').timepicker({
        'scrollDefault': 'now',
        'timeFormat': 'H:i A',
        'step': 1,
        'disableTimeRanges': [
            ['00:00 AM', '08:00 AM'],
            ['09:30 PM', '11:59 PM']
        ]
    });
    updateWorkHours();
};

// make chart
var ctx = document.getElementById('workTimeChart').getContext('2d');
var workTimeChart = new Chart(ctx, {
    type: 'doughnut', // 원형 그래프 유형
    data: {
        labels: ['휴일', '근무 인정 시간', '휴가 시간', '남은 시간'],
        datasets: [{
            label: '근무 시간',
            data: [0, 0, 0, 0], // 첫 번째 값은 인정된 근무 시간, 두 번째 값은 남은 근무 시간(40시간 중에서)
            backgroundColor: [
                chartColor11, // 휴일 색상
                chartColor22, // 근무한 시간 색상
                chartColor33,
                chartColor44 // 남은 시간 색상
            ],
            borderColor: [
                color4,
                color4,
                color4,
                color4
            ],
            borderWidth: 0
        }]
    },
    options: {
        responsive: true, // 차트가 컨테이너 크기에 맞춰 조정.
        plugins: {
            legend: {
                display: true, // 범례 표시 설정
                position: 'bottom', // 범례의 위치
            },
            tooltip: { // Chart.js 3.x 이상에서는 tooltip을 사용
                callbacks: {
                    label: function (context) {
                        let label = context.label || '';
                        if (label) {
                            label += ': ';
                        }
                        if (context.parsed !== undefined) {
                            const value = context.parsed;
                            label += formatMinutesAsHours(value);
                        }
                        return label;
                    }
                }
            }
        }
    }
});

function makeTable() {
    const days = ['월', '화', '수', '목', '금'];
    const titles = ['요일', '출근 시간', '퇴근 시간', '휴가 시간', '휴일 체크', '인정 시간(최대 9시간)', '적립시간'];
    const tableBody = document.getElementById('workHoursTable').getElementsByTagName('tbody')[0];
    days.forEach((day, index) => {
        let row = tableBody.insertRow();
        row.insertCell(0).innerText = day;
        row.cells[0].setAttribute('data-title', titles[0]);
        row.cells[0].classList.add('title');
        row.cells[0].style.backgroundColor = color5;
        row.cells[0].style.fontWeight = '700';
        row.classList.add('day-row');
        row.setAttribute('data-day', day);
        for (let i = 1; i <= 6; i++) { // 셀 추가로 인덱스 6까지 확장
            let cell = row.insertCell(i);
            cell.setAttribute('data-title', titles[i]);
            cell.classList.add('title');
            cell.classList.add(day);
            if (i < 3) { // 출근 시간과 퇴근 시간 입력란
                let input = document.createElement('input');
                input.type = 'text';
                input.inputMode = 'numeric';
                input.pattern = '[0-9]*';
                input.className = 'timepicker-input';

                if (i === 1) {
                    input.value = localStorage.getItem(`startTime${index + 1}`) || '';
                }
                if (i === 2) {
                    input.value = localStorage.getItem(`endTime${index + 1}`) || '';
                }
                let resetBtn = document.createElement('button');
                resetBtn.className = 'btn item-reset';
                resetBtn.textContent = 'R';
                resetBtn.onclick = () => {
                    input.value = '';
                    updateWorkHours();
                };
                cell.appendChild(input);
                cell.appendChild(resetBtn);
            } else if (i === 3) { // 휴가 시간 선택
                let select = document.createElement('select');
                ['없음', '2시간', '4시간'].forEach(option => {
                    let optionElement = document.createElement('option');
                    optionElement.value = option;
                    optionElement.textContent = option;
                    select.appendChild(optionElement);
                });
                select.value = localStorage.getItem(`vacationTime${index + 1}`) || '없음';
                cell.appendChild(select);
            } else if (i === 4) { // 휴일 체크박스
                let label = document.createElement('label');
                label.className = 'custom-checkbox';

                let input = document.createElement('input');
                input.type = 'checkbox';
                input.checked = localStorage.getItem(`holiday${index + 1}`) === 'true';

                let span = document.createElement('span');

                label.appendChild(input);
                label.appendChild(span);
                cell.appendChild(label);
            } else {
                cell.innerText = ''; // 나머지 셀은 초기값 설정
            }
        }
    });
}

function updateWorkHours() {
    const { totalHolidayTime, totalAccumulatedMinutes, totalVacationMinutes } = calcTotalRequiredMinutesAndUpdateTable();
    updateChart(totalAccumulatedMinutes - totalVacationMinutes, remainingMinutes, totalHolidayTime, totalVacationMinutes);
}
// update chart
function updateChart(completedTime, remainingTime, holidayTime, vacationTime) {
    workTimeChart.data.datasets[0].data[0] = holidayTime;
    workTimeChart.data.datasets[0].data[1] = completedTime;
    workTimeChart.data.datasets[0].data[2] = vacationTime;
    workTimeChart.data.datasets[0].data[3] = remainingTime;
    workTimeChart.update();
    var numColor = color2;
    if (remainingMinutes > 0) {
        numColor = color2
    } else {
        numColor = color1
    }
    document.getElementById('total-remainning-time').innerHTML =
        '<div>잔여 근무시간' + '<span class="total-remainning-time-num" style="color: ' + numColor + '">' + formatMinutesAsHours(remainingMinutes) + '</span></div>'; // 잔여 근무 시간 업데이트

    document.getElementById('dayExitTime').innerText = '';
}

// 잔여 근무 시간 계산
function calcTotalRequiredMinutesAndUpdateTable() {
    const rows = document.getElementById('workHoursTable').rows;
    let totalAccumulatedMinutes = 0;

    // 휴일에 대해 빼줄 근무 시간 총합
    let totalHolidayTime = 0;
    let totalVacationMinutes = 0;

    for (let i = 1; i < rows.length; i++) {
        const isHoliday = rows[i].cells[4].children[0].children[0].checked;
        rows[i].cells[0].style.color = color3;
        rows[i].style.backgroundColor = color4;
        if (isHoliday) {
            // 휴일인 경우 전체 근무 시간에서 하루 8시간(480분)을 빼줌
            totalHolidayTime += 8 * 60;
            rows[i].cells[5].innerText = '휴일(8시간 제외)'; // 휴일인 경우 근무 시간을 '휴일'로 표시
            rows[i].cells[5].style.color = color6;
            rows[i].style.backgroundColor = color7;
            rows[i].cells[1].children[0].style.backgroundColor = color7;
            // rows[i].cells[1].children[0].value = '';
            rows[i].cells[1].children[0].disabled = true;
            rows[i].cells[2].children[0].style.backgroundColor = color7;
            // rows[i].cells[2].children[0].value = '';
            rows[i].cells[2].children[0].disabled = true;
            rows[i].cells[3].children[0].style.backgroundColor = color7;
            rows[i].cells[3].children[0].value = '없음';
            rows[i].cells[3].children[0].disabled = true;
            rows[i].cells[6].innerText = '';
            rows[i].cells[0].style.color = color6;
            // rows[i].cells[5].backgroundColor = color5;
            continue;
        }

        rows[i].cells[1].children[0].style.backgroundColor = color4;
        rows[i].cells[2].children[0].style.backgroundColor = color4;
        rows[i].cells[3].children[0].style.backgroundColor = color4;
        rows[i].cells[1].children[0].disabled = false;
        rows[i].cells[2].children[0].disabled = false;
        rows[i].cells[3].children[0].disabled = false;

        const startTime = rows[i].cells[1].children[0].value;
        const endTime = rows[i].cells[2].children[0].value;
        const vacationTime = rows[i].cells[3].children[0].value;
        let vacationMinutes = vacationTime === '없음' ? 0 : parseInt(vacationTime) * 60;
        totalVacationMinutes += vacationMinutes;
        let workMinutes = calculateWorkDuration(startTime, endTime);

        // 근무 인정 시간에 휴가 시간 포함
        workMinutes += vacationMinutes;
        let dailyMaxWorkMinutes = Math.min(workMinutes, 9 * 60); // 하루 최대 근무 인정 시간 9시간으로 제한

        totalAccumulatedMinutes += dailyMaxWorkMinutes; // 휴가 시간 포함하여 누적

        let hours = Math.floor(dailyMaxWorkMinutes / 60);
        let mins = dailyMaxWorkMinutes % 60;
        rows[i].cells[5].innerText = (workMinutes > 0) ? `${pad(hours)}:${pad(mins)}` : ''; // 근무 인정 시간 업데이트
        if (dailyMaxWorkMinutes < 480) {
            if (dailyMaxWorkMinutes === 0) {
                rows[i].cells[5].style.color = color3;
                // rows[i].cells[5].style.backgroundColor = color4
            } else {
                rows[i].cells[5].style.color = color2;
                if (dailyMaxWorkMinutes < 0) {
                    rows[i].cells[5].innerText = `출퇴근시간 AM/PM 확인`;
                }
            }
        } else {
            rows[i].cells[5].style.color = color1;
        }
        // 적립시간 표시
        rows[i].cells[6].innerText = ''; // 리셋먼저...
        if (i < rows.length && dailyMaxWorkMinutes !== 0) {
            let addedTime = dailyMaxWorkMinutes - 480;
            let isMinus = false;
            if (addedTime < 0) {
                isMinus = true;
                addedTime *= -1;
            }
            let _hours = Math.floor(addedTime / 60);
            let _mins = addedTime % 60;
            if (isMinus) {
                rows[i].cells[6].innerText = `-${pad(_hours)}:${pad(_mins)} 부족`;
                rows[i].cells[6].style.color = color2;
            } else {
                if (addedTime === 0) {
                    rows[i].cells[6].style.color = color3;
                    rows[i].cells[6].innerText = '.';
                } else {
                    rows[i].cells[6].innerText = `+${pad(_hours)}:${pad(_mins)} 적립`;
                    rows[i].cells[6].style.color = color1;
                }
            }
        }
    }
    let totalRequiredMinutes = (40 * 60) - totalHolidayTime; // 주당 근무 시간에서 휴일 시간을 뺀 값
    remainingMinutes = Math.max(0, totalRequiredMinutes - totalAccumulatedMinutes); // 음수 방지

    return { totalHolidayTime, totalAccumulatedMinutes, totalVacationMinutes };
}

function calculateWorkDuration(startTime, endTime) {
    const startMoment = moment(startTime, "HH:mm");
    const endMoment = moment(endTime, "HH:mm");
    let duration = 0;
    if (startMoment.isValid() && endMoment.isValid()) {
        duration = moment.duration(endMoment.diff(startMoment)).asMinutes();
        // 점심 시간 체크
        if (!endMoment.isBefore(moment('12:30', "HH:mm")) && !startMoment.isAfter(moment('13:30', "HH:mm"))) {
            duration -= 60;
        }
    }
    return duration;
}

function formatMinutesAsHours(minutes) {
    let hours = Math.floor(minutes / 60);
    let mins = minutes % 60;
    return `${pad(hours)}:${pad(mins)}`;
}

function pad(number) {
    return number < 10 ? '0' + number : number.toString();
}


function saveTimeToLocalStorage() {
    const rows = document.getElementById('workHoursTable').rows;
    for (let i = 1; i < rows.length; i++) {
        const startTime = rows[i].cells[1].children[0].value;
        const endTime = rows[i].cells[2].children[0].value;
        const vacationTime = rows[i].cells[3].children[0].value;
        const isHoliday = rows[i].cells[4].children[0].children[0].checked;

        localStorage.setItem(`startTime${i}`, startTime);
        localStorage.setItem(`endTime${i}`, endTime);
        localStorage.setItem(`vacationTime${i}`, vacationTime);
        localStorage.setItem(`holiday${i}`, isHoliday);
    }
}

function resetAll() {
    const rows = document.getElementById('workHoursTable').rows;
    for (let i = 1; i < rows.length; i++) {
        localStorage.removeItem(`startTime${i}`);
        localStorage.removeItem(`endTime${i}`);
        localStorage.removeItem(`vacationTime${i}`);
        localStorage.removeItem(`holiday${i}`);
        rows[i].cells[0].style.color = color3;
        rows[i].cells[1].children[0].value = '';
        rows[i].cells[2].children[0].value = '';
        rows[i].cells[3].children[0].value = '없음';
        rows[i].cells[4].children[0].children[0].checked = false;
        rows[i].cells[5].innerText = '';
        // rows[i].cells[5].style.backgroundColor = color4;
        rows[i].style.backgroundColor = color4;
        rows[i].cells[5].style.color = color3;
        rows[i].cells[6].innerText = '';
        rows[i].cells[1].children[0].style.backgroundColor = color4;
        rows[i].cells[2].children[0].style.backgroundColor = color4;
        rows[i].cells[3].children[0].style.backgroundColor = color4;
        rows[i].cells[1].children[0].disabled = false;
        rows[i].cells[2].children[0].disabled = false;
        rows[i].cells[3].children[0].disabled = false;
    }
    remainingMinutes = 2400;
    document.getElementById('total-remainning-time').innerHTML = '<div>잔여 근무시간' + '<span class="total-remainning-time-num" style="color: ' + color2 + '">' + formatMinutesAsHours(remainingMinutes) + '</span></div>';
    document.getElementById('dayExitTime').innerText = '';
    updateChart(0, 2400);
}

function calculatedayExitTime() {
    var targetDayOfWeek = "";
    const rows = document.getElementById('workHoursTable').rows;
    let targetRow = null;

    for (let i = 1; i < rows.length; i++) {
        if (
            rows[i].cells[2].children[0].value === '' &&
            rows[i].cells[4].children[0].children[0].checked === false) {
            targetRow = rows[i];
            if (i === 1) {
                targetDayOfWeek = "월요일";
            } else if (i === 2) {
                targetDayOfWeek = "화요일";
            } else if (i === 3) {
                targetDayOfWeek = "수요일";
            } else if (i === 4) {
                targetDayOfWeek = "목요일";
            } else if (i === 5) {
                targetDayOfWeek = "금요일";
            }
            break;
        }
    }
    if (targetRow === null) {
        alert(`퇴근시간이 궁금한 요일의 퇴근시간을 비워주세요.`);
        return;
    }
    const startTime = targetRow.cells[1].children[0].value; // 출근 시간

    if (!startTime) {
        alert(`${targetDayOfWeek}의 출근 시간을 입력해주세요.`);
        return;
    }

    let remainingTotalMinutes = remainingMinutes;// (remainingHours * 60) + remainingMinutes;

    const targetdayStartMoment = moment(startTime, "HH:mm");
    const lunchStart = moment('12:30', "HH:mm");
    const lunchEnd = moment('13:30', "HH:mm");

    // 출근 시간과 남은 근무 시간을 기준으로 초기 퇴근 시간을 계산
    let tentativeTargetdayExitMoment = targetdayStartMoment.clone().add(remainingTotalMinutes, 'minutes');

    let isLaunchTime = false;
    // 점심시간이 근무 시간에 포함되어 있는지 확인 후 조정
    if (targetdayStartMoment.isBefore(lunchEnd) && tentativeTargetdayExitMoment.isAfter(lunchStart)) {
        // 점심시간이 포함되어 있으면, 퇴근 시간을 60분 연장
        remainingTotalMinutes += 60;
        isLaunchTime = true;
    }
    // 금요일이 아닌경우 휴가가 포함되어있으면 휴가시간 제외
    if (targetDayOfWeek !== "금요일") {
        const vacationTime = targetRow.cells[3].children[0].value;
        let vacationMinutes = vacationTime === '없음' ? 0 : parseInt(vacationTime) * 60;
        remainingTotalMinutes -= vacationMinutes;
    }

    // 조정된 근무 시간으로 최종 퇴근 시간 계산
    const targetdayExitMoment = targetdayStartMoment.clone().add(remainingTotalMinutes, 'minutes');

    // 퇴근 시간을 AM/PM 포맷으로 출력
    const exitTimeFormatted = targetdayExitMoment.format("hh:mm A");
    let remainingTimeFormatted = formatMinutesAsHours(remainingTotalMinutes);

    const vacationTime = targetRow.cells[3].children[0].value;
    let checkVacationMinutes = vacationTime === '없음' ? 0 : parseInt(vacationTime) * 60;
    let checkRemainingTotalMinutes = remainingTotalMinutes + checkVacationMinutes;
    if (checkRemainingTotalMinutes / 60 > 10) {
        let overWorkTime = checkRemainingTotalMinutes - 540 - 60;
        let overWorkTimeFormatted = formatMinutesAsHours(overWorkTime);
        const targetdayOverExitMoment = targetdayStartMoment.clone().add(remainingTotalMinutes - overWorkTime, 'minutes');
        const exitOverTimeFormatted = targetdayOverExitMoment.format("hh:mm A");
        document.getElementById('dayExitTime').innerHTML = `<span class="dayExitTimeNormal">${targetDayOfWeek} 근무시간을 최대한 채울 수 있는 시간(9시간)인 </span>${exitOverTimeFormatted}<span class="dayExitTimeNormal">에 퇴근하면</span><br /> 
            <span class="dayExitTimeNormal">남은 총 근무시간은</span> <span class="dayExitTimeAlert">${overWorkTimeFormatted}</span> <span class="dayExitTimeNormal">입니다.</span>`
    } else {
        document.getElementById('dayExitTime').innerHTML
            = `<span class="dayExitTimeNormal">남은 근무시간은 ${isLaunchTime ? "휴게시간 포함</span>" : "</span>"} ${remainingTimeFormatted} <br />
                <span class="dayExitTimeNormal">${targetDayOfWeek} 퇴근은</span> ${exitTimeFormatted} <span class="dayExitTimeNormal">이후부터 가능해요.</span>`;
    }
}

document.getElementById('workHoursTable').addEventListener('change', (event) => {
    updateWorkHours();
    saveTimeToLocalStorage();
});

 

 

style.css

html,
body {
    margin: 20px;
    padding: 0px;
    min-height: calc(100%-40px);
    font-family: 'Pretendard Variable', 'Apple SD Gothic Neo', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 1.5;
    color: #666666;
    text-size-adjust: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    text-align: center;
}

table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}

table,
th,
td {
    border: 1px solid #dfdfdf;
}

th,
td {
    padding: 10px;
    text-align: center;
    word-wrap: break-word;
}

.table-title {
    background-color: #f3f3f3;
    width: auto;
}

.first {
    width: 40px;
}

.second {
    width: 100px;
}

.third {
    width: 100px;
}

.forth {
    width: 60px;
}

.fifth {
    width: 50px;
}

.sixth {
    width: 180px;
}

.seventh {
    width: 150px;
}

.chart-container {
    position: relative;
    text-align: center;
    display: flex;
    justify-content: center;
    align-items: center;
    /* height: 100vh; */
}

canvas {
    position: relative;
    max-width: auto;
    max-height: 300px;
    margin-bottom: 40px;
    z-index: 100;
}

.total-remainning-time {
    position: absolute;
    width: 100%;
    height: 100%;
    margin: 0px;
    padding: 0px;
    z-index: 0;
    top: -40px;
    left: 0px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 12px;
    pointer-events: none;
}

.total-remainning-time-num {
    font-weight: 900;
    display: block;
    font-size: 20px;
}

button {
    margin: 10px 5px;
    padding: 10px 20px;
    font-size: 1rem;
    cursor: pointer;
    border: none;
    background-color: #0ACFD9;
    color: #ffffff;
    border-radius: 10px;
    transition: background-color 0.3s ease;
}

.reset-all {
    background-color: #898989;
}

.item-reset {
    position: relative;
    font-size: 0.7rem;
    width: 20px;
    height: 20px;
    text-align: center;
    border-radius: 10px;
    margin: 0px;
    padding: 0px;
    background-color: #d2d2d2;
}

.table-container {
    width: 100%;
    overflow-x: auto;
}

.action-container {
    text-align: center;
    margin-top: 40px;
    margin-bottom: 40px;
}

button:hover {
    background-color: #18aab1;
}

.item-reset:hover,
.reset-all:hover {
    background-color: #7d7d7d;
}

#dayExitTime {
    margin-top: 20px;
    font-size: 14px;
    font-weight: 400;
    color: #0ACFD9;
}

.dayExitTimeNormal {
    color: #6f6f6f;
    font-weight: 200;
}

.dayExitTimeAlert {
    color: #EF6D81;
    font-weight: 400;
}

.title-center {
    font-weight: 900;
    font-size: 3rem;
    text-align: center;
    margin-top: 20px;
    margin-bottom: 20px;
    color: #3f3f3f;
}

input[type="text"] {
    padding: 5px 5px 5px 5px;
    border-radius: 5px;
    border: 1px solid #d4d4d4;
    color: #777777;
    background-color: #ffffff;
    width: 80px;
    margin-right: 10px;
}

select {
    padding: 5px 5px 5px 5px;
    border-radius: 5px;
    border: 1px solid #d4d4d4;
    color: #777777;
    background-color: #ffffff;
    text-align: center;
}

.custom-checkbox input {
    display: none;
}

/* 커스텀 디자인 */
.custom-checkbox span {
    height: 18px;
    width: 18px;
    background-color: #ffffff;
    display: inline-block;
    position: relative;
    border-radius: 5px;
    border: 1px solid #d4d4d4;
}

/* 체크된 상태의 스타일 */
.custom-checkbox input:checked+span {
    background-color: #DCBCFF;
    border: 1px solid #B068FF;
}

.custom-checkbox input:checked+span:after {
    content: "";
    position: absolute;
    left: 7px;
    top: 3px;
    width: 3px;
    height: 8px;
    border: solid white;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

@media screen and (max-width: 1100px) {

    html,
    body {
        margin: 10px;
        font-size: 14px;
        line-height: 1.3;
        min-height: calc(100%-20px);
    }

    .title-center {
        font-size: 2.5rem;
        text-align: center;
        margin-top: 0px;
        margin-bottom: 20px;
    }

    th,
    td {
        padding: 10px 0px 10px 0px;
    }


}

@media screen and (max-width: 935px) {


    th,
    td {
        padding: 10px 0px 10px 0px;
    }

    input[type="text"],
    select {
        width: 60px;
        transform: scale(0.9);
    }

    input[type="checkbox"] {
        transform: scale(1.3);
    }
}

@media screen and (max-width: 784px) {

    table,
    thead,
    tbody,
    th,
    td,
    tr {
        display: block;
        width: 100%;
        border: 0px;
    }

    .title-center {
        font-size: 2.5rem;
        text-align: center;
        margin-top: 0px;
        margin-bottom: 20px;
    }

    thead tr {
        position: absolute;
        top: -9999px;
        left: -9999px;
        border: 0px;
    }

    tr {
        border: 1px solid #ccc;
        border-radius: 0px;
        margin-bottom: 20px;
        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        width: calc(100% - 2px);
    }

    td {
        position: relative;
        align-items: flex-start;
        justify-content: center;
        border: none;
        border-bottom: 1px solid #dedede;
        /* padding: 10px; */
        padding: 10px 10px 10px 10px;
        padding-left: calc(28% + 30px);
        text-align: right;
        white-space: normal;
        height: 22px;
        width: auto;
        margin: 0px;
    }

    td:last-child {
        border-bottom: none;
    }

    td:before {
        position: absolute;
        top: 0;
        left: 0;
        width: 28%;
        height: 22px;
        padding: 10px;
        content: attr(data-title);
        font-weight: bold;
        font-size: 14px;
        color: #666666;
        background-color: #f3f3f3;
        text-align: right;
    }

    input[type="text"],
    select {
        margin: 0px;
        padding: 4Px;
        transform: scale(1);
        margin-right: 10px;
        width: auto;
        /* max-width: 100%; */
    }

    select {
        transform: scale(1);
        /* padding: 5px 5px 5px 5px; */
        border-radius: 5px;
        border: 1px solid #d4d4d4;
        color: #777777;
        background-color: #ffffff;
        margin: 0px;
        padding: 4Px;
        /* text-align: center; */
        /* margin: 0px; */
    }

    input[type="checkbox"] {
        transform: scale(1.3);
        margin: 0px;
        /* margin-right: 5px; */
        color: #777777;
        margin: 0px;
        padding: 4Px;
    }
}

@media screen and (max-width: 510px) {

    html,
    body {
        margin: 10px;
        font-size: 14px;
        min-height: calc(100%-20px);
    }

    .title-center {
        font-size: 2rem;
        text-align: center;
    }

    .action-container,
    .title-center,
    #dayExitTime {
        margin-top: 15px;
        margin-bottom: 15px;
    }

    td {
        font-size: 12px;
        padding-left: calc(40% + 30px);
        height: 18px;
    }

    td:before {
        width: 40%;
        font-size: 12px;
        height: 18px;
    }

    input[type="text"],
    select {
        max-width: 60%;
        padding: 4px;
        font-size: 12px;
    }

    button {
        font-size: 0.8rem;
        font-size: 14px;
    }

    .item-reset {
        padding: 0px 0px;
        font-size: 0.8rem;
        font-size: 12px;
    }
}

@media screen and (max-width: 309px) {
    .total-remainning-time {
        top: -50px;
        font-size: 10px;
    }

    .total-remainning-time-num {
        font-size: 18px;
    }
}
반응형

+ Recent posts