0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

今回は私個人の予定を管理するためのToDOリストアプリを作成してみました。

準備

使用言語:HTML,CSS,JavaScript
使用ツール:Claude,Excel
実行環境:VSCode

作成方法

1.レイアウトの準備

今回作成したい自己管理アプリのレイアウトをExcelで作成しました。

スクリーンショット (61).png

プログラム

Claudeに指示を出しながらHTMLとCSSとJavaScriptのコーディングを行いました。最終的に完成したプログラムは次の通りです。

自己管理アプリの画面に該当するHTMLのコードがこちらになります。

app.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>自己管理アプリ</title>
</head>

<body>
    <header>
        <div id="date-nav">
            <button id="prev-btn">◁</button>
            <span id="current-date"></span>
            <button id="next-btn">▷</button>
        </div>
    </header>
    <table>
        <thead>
            <tr>
                <th class="col-r">R</th>
                <th class="col-todo">やること</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>1</td>
                <td>
                    <dialog id="dialog01">
                        <button class="cancel-btn" id="cancel_btn01">✕</button>
                        <textarea id="textarea01"></textarea>
                        <button class="save-btn" id="close_btn01">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn01">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>2</td>
                <td>
                    <dialog id="dialog02">
                        <button class="cancel-btn" id="cancel_btn02">✕</button>
                        <textarea id="textarea02"></textarea>
                        <button class="save-btn" id="close_btn02">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn02">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>3</td>
                <td>
                    <dialog id="dialog03">
                        <button class="cancel-btn" id="cancel_btn03">✕</button>
                        <textarea id="textarea03"></textarea>
                        <button class="save-btn" id="close_btn03">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn03">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>4</td>
                <td>
                    <dialog id="dialog04">
                        <button class="cancel-btn" id="cancel_btn04">✕</button>
                        <textarea id="textarea04"></textarea>
                        <button class="save-btn" id="close_btn04">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn04">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>5</td>
                <td>
                    <dialog id="dialog05">
                        <button class="cancel-btn" id="cancel_btn05">✕</button>
                        <textarea id="textarea05"></textarea>
                        <button class="save-btn" id="close_btn05">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn05">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>6</td>
                <td>
                    <dialog id="dialog06">
                        <button class="cancel-btn" id="cancel_btn06">✕</button>
                        <textarea id="textarea06"></textarea>
                        <button class="save-btn" id="close_btn06">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn06">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>7</td>
                <td>
                    <dialog id="dialog07">
                        <button class="cancel-btn" id="cancel_btn07">✕</button>
                        <textarea id="textarea07"></textarea>
                        <button class="save-btn" id="close_btn07">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn07">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>8</td>
                <td>
                    <dialog id="dialog08">
                        <button class="cancel-btn" id="cancel_btn08">✕</button>
                        <textarea id="textarea08"></textarea>
                        <button class="save-btn" id="close_btn08">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn08">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>9</td>
                <td>
                    <dialog id="dialog09">
                        <button class="cancel-btn" id="cancel_btn09">✕</button>
                        <textarea id="textarea09"></textarea>
                        <button class="save-btn" id="close_btn09">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn09">予定を作る</button>
                </td>
            </tr>
            <tr>
                <td>10</td>
                <td>
                    <dialog id="dialog10">
                        <button class="cancel-btn" id="cancel_btn10">✕</button>
                        <textarea id="textarea10"></textarea>
                        <button class="save-btn" id="close_btn10">保存</button>
                    </dialog>
                    <button class="open-btn" id="open_btn10">予定を作る</button>
                </td>
            </tr>
        </tbody>
    </table>
    <script src="script.js"></script>
</body>

</html>

自己管理アプリの装飾に該当するCSSのコードはこちらになります。

style.css
@charset "utf-8";
h1{
            text-align: center;
        }
        header {
            text-align: center;
            padding: 16px 0;
        }
        #date-nav {
            display: inline-flex;
            align-items: center;
            gap: 20px;
            font-size: 1.4rem;
            font-weight: bold;
        }
        #date-nav button {
            font-size: 1.2rem;
            padding: 4px 14px;
            cursor: pointer;
            border: 1px solid #999;
            border-radius: 4px;
            background: #f5f5f5;
        }
        #date-nav button:hover {
            background: #ddd;
        }
        #date-nav button:disabled {
            opacity: 0.3;
            cursor: default;
        }
        table {
            border-collapse: collapse;
            margin-left: auto;
            margin-right: auto;
            width: 800px;
            table-layout: fixed;
        }
        th, td {
            border: 1px solid #000;
            padding: 8px 12px;
            text-align: center;
        }
        /* R列:やること列 = 1:5 の比率(Excel C列:D〜H列) */
        .col-r {
            width: 80px;
        }
        .col-todo {
            width: auto;
        }
        /* tbody の各行の高さ */
        tbody tr {
            height: 60px;
        }
        tbody td {
            vertical-align: middle;
            position: relative;
            padding: 0;
        }
        textarea{
            width:100%;
            height:100%;
        }
/* ── ダイアログ ── */
dialog {
    position: relative;
    border: 1px solid #999;
    border-radius: 8px;
    padding: 40px 20px 20px;
    width: 400px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.2);
}
dialog textarea {
    width: 100%;
    height: 160px;
    box-sizing: border-box;
    resize: vertical;
    font-size: 1rem;
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 4px;
}
dialog::backdrop {
    background: rgba(0, 0, 0, 0.4);
}
.cancel-btn {
    position: absolute;
    top: 8px;
    left: 8px;
    background: none;
    border: none;
    font-size: 1.1rem;
    cursor: pointer;
    color: #666;
    line-height: 1;
    padding: 2px 6px;
}
.cancel-btn:hover {
    color: #000;
}
.save-btn {
    display: block;
    margin: 12px auto 0;
    padding: 6px 24px;
    font-size: 1rem;
    cursor: pointer;
    background: #4a90d9;
    color: #fff;
    border: none;
    border-radius: 4px;
}
.save-btn:hover {
    background: #357abd;
}
.open-btn {
    display: block;
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    cursor: pointer;
    border: none;
    border-radius: 0;
    background:none;
    font-size: 0.95rem;
    
}
.open-btn:hover {
    background: #e8e8e8;
}

自己管理アプリの操作や予定の保存など機能面を担うJavaScriptのコードは次の通りです。

script.js
// Day.js を動的に読み込んで日付処理に使用
(function () {
    const script = document.createElement('script');
    script.src = 'https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.10/dayjs.min.js';
    script.onload = init;
    document.head.appendChild(script);
})();

function pad(n) { return String(n).padStart(2, '0'); }

// 現在表示中の日付文字列(YYYY-MM-DD)を保持
let currentDateKey = '';

// ローカルストレージのキー:日付+行番号
function storageKey(dateKey, row) {
    return 'todo_' + dateKey + '_' + pad(row);
}

// 全行のボタン・テキストエリアを指定日付のデータで更新
function loadDateData(dateKey) {
    currentDateKey = dateKey;
    for (let i = 1; i <= 10; i++) {
        const id = pad(i);
        const saved = localStorage.getItem(storageKey(dateKey, i)) || '';
        document.getElementById('textarea' + id).value = saved;
        document.getElementById('open_btn' + id).textContent = saved.trim() || '予定を作る';
    }
}

function init() {
    const startDate = dayjs().startOf('day');
    let currentIndex = 0;

    const dateEl = document.getElementById('current-date');
    const prevBtn = document.getElementById('prev-btn');
    const nextBtn = document.getElementById('next-btn');

    function render() {
        const date = startDate.add(currentIndex, 'day');
        const isToday = currentIndex === 0;
        dateEl.textContent = date.format('YYYY年M月D日') + (isToday ? '(今日)' : '');
        prevBtn.disabled = currentIndex === 0;
        nextBtn.disabled = currentIndex === 6;
        loadDateData(date.format('YYYY-MM-DD'));
    }

    prevBtn.addEventListener('click', function () {
        if (currentIndex > 0) { currentIndex--; render(); }
    });

    nextBtn.addEventListener('click', function () {
        if (currentIndex < 6) { currentIndex++; render(); }
    });

    render();
}

// ── ダイアログ開閉 ──────────────────────────────────────────────

function openDialog(id) {
    document.getElementById('dialog' + id).showModal();
}

function closeDialog(id) {
    const ta = document.getElementById('textarea' + id);
    localStorage.setItem(storageKey(currentDateKey, parseInt(id, 10)), ta.value);
    document.getElementById('open_btn' + id).textContent = ta.value.trim() || '予定を作る';
    document.getElementById('dialog' + id).close();
}

function cancelDialog(id) {
    const saved = localStorage.getItem(storageKey(currentDateKey, parseInt(id, 10))) || '';
    document.getElementById('textarea' + id).value = saved;
    document.getElementById('dialog' + id).close();
}

// ボタンへのイベント登録
window.addEventListener('DOMContentLoaded', function () {
    for (let i = 1; i <= 10; i++) {
        const id = pad(i);
        document.getElementById('open_btn' + id).addEventListener('click', function () { openDialog(id); });
        document.getElementById('close_btn' + id).addEventListener('click', function () { closeDialog(id); });
        document.getElementById('cancel_btn' + id).addEventListener('click', function () { cancelDialog(id); });
    }
});

3.実行結果

完成したアプリを実際に使ってみました。
このアプリでは最大で1週間後までのToDoリストを作ることができます。また、最大で10個の予定を優先順位をつけながら記録することが可能です。

スクリーンショット (63).png

スクリーンショット (62).png

スクリーンショット (64).png

4.最後に

自己管理アプリを使って私個人のタスクを管理していきたいですね。
自己管理アプリを実際に操作してみたいという方がいましたら、コメントでお声がけください。
最後までお読みいただきありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?