MENU

4マスメモのコード(バックアップ)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title>4マスメモ</title>
  <link rel="stylesheet" href="../style.css?20250630">

  <script src="https://cdn.jsdelivr.net/npm/jspdf@2.5.1/dist/jspdf.umd.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/jspdf-autotable@3.5.28/dist/jspdf.plugin.autotable.min.js"></script>
  <script src="https://◯◯◯◯◯.github.io/4masumemo/NotoSansJP-Regular-base64_2.js"></script>

  <style>
    table.memo.normal { width: 100%; max-width: 900px; border-collapse:collapse; margin:24px auto; }
    table.memo.wide { width: 100%; max-width: 1200px; border-collapse:collapse; margin:24px auto; }
    .memo th, .memo td { border:1px solid #ccc; text-align:center; vertical-align: top; }
    .memo th { background:#e9ecef; }
    
    .memo td {
      padding: 0;
      vertical-align: top; /* ← 追加 */
    }

    .memo td textarea {
      width: 100%;
      min-height: 480px;
      resize: none;
      overflow: hidden;
      box-sizing: border-box;
      border: none;
      outline: none;
      box-shadow: none;
      background-color: transparent;
      padding: 8px; /* ← 内側に余白をつける! */
    }

    .memo td textarea:focus {
      background-color: rgba(0, 123, 255, 0.05);
      outline: none;
      box-shadow: none;
      border: none;
    }

    .save-btn {
      display:block; width:100%; max-width:200px; margin:16px auto; padding:8px 0;
    }
    #toast {
      position:fixed; left:50%; bottom:40px; transform:translateX(-50%);
      background:#333; color:#fff; padding:8px 16px; border-radius:4px;
      font-size:.9rem; opacity:0; pointer-events:none; transition:opacity .3s;
    }
    #toast.show { opacity:1; }

    .title-bar {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-left: 16px;
    }

    .hamburger-menu {
      font-size: 20px;
      cursor: pointer;
      padding: 4px;
      margin: 0;
      line-height: 1;          /* ← 高さを詰める */
      display: flex;
      align-items: center;
    }

    .menu-list {
      display: none;
      position: absolute;
      top: 30px;
      left: 0;
      background: white;
      border: 1px solid #ccc;
      border-radius: 6px;
      list-style: none;
      padding: 0;
      margin: 0;
      min-width: 180px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.15);
      z-index: 1000;
    }
    .hamburger-menu.open .menu-list { display: block; }
    .menu-list li {
      padding: 10px;
      cursor: pointer;
    }
    .menu-list li:hover {
      background-color: #f0f0f0;
    }
  </style>
</head>
<body>

<div id="header-placeholder"></div>
<div class="page-wrapper">
  <aside id="sidebar"></aside>
  <div class="content-wrapper">
    <div class="main" id="main">

      <div class="title-bar">
        <div class="hamburger-menu" onclick="toggleMenu(this)">☰
          <ul class="menu-list">
            <li onclick="setMemoWidth('wide')">横幅を大きくする</li>
            <li onclick="setMemoWidth('normal')">横幅を通常に戻す</li>
            <li id="savePdfBtn">PDFで保存</li> <!-- ← 追加 -->
          </ul>
        </div>
        <h2>4マスメモ</h2>
      </div>

      <button id="saveTop" class="save-btn">保存</button>

      <form id="memoForm">
        <table class="memo normal" id="memoTable">
          <thead><tr><th>項目 1</th><th>項目 2</th></tr></thead>
          <tbody>
            <tr><td><textarea data-cell="0-0"></textarea></td>
                <td><textarea data-cell="0-1"></textarea></td></tr>
            <tr><td><textarea data-cell="1-0"></textarea></td>
                <td><textarea data-cell="1-1"></textarea></td></tr>
          </tbody>
        </table>
      </form>

      <button id="saveBottom" class="save-btn">保存</button>
      <button id="htmlBtn" class="save-btn">HTMLで保存</button>
      <button id="pdfBtn" class="save-btn">PDF で保存</button>
    </div>
  </div>
</div>

<div id="toast">保存しました</div>

<script>
  const form = document.getElementById('memoForm');
  const toast = document.getElementById('toast');
  const lsKey = 'memo_2x2';

  function showToast() {
    toast.classList.add('show');
    setTimeout(() => toast.classList.remove('show'), 2000);
  }

  function autoResizeTextarea(el){
    el.style.height = 'auto';
    el.style.height = el.scrollHeight + 'px';
  }

  function loadMemo(){
    const data = JSON.parse(localStorage.getItem(lsKey) || '{}');
    form.querySelectorAll('textarea').forEach(ta => {
      ta.value = data[ta.dataset.cell] || '';
      autoResizeTextarea(ta);
    });
  }

  function saveMemo(){
    const data = {};
    form.querySelectorAll('textarea').forEach(ta => {
      data[ta.dataset.cell] = ta.value;
    });
    localStorage.setItem(lsKey, JSON.stringify(data));
    showToast();
  }

  document.getElementById('saveTop').onclick =
  document.getElementById('saveBottom').onclick = e => {
    e.preventDefault();
    saveMemo();
  };

  form.querySelectorAll('textarea').forEach(t => {
    autoResizeTextarea(t);
    t.addEventListener('input', () => autoResizeTextarea(t));
  });
  loadMemo();

  document.getElementById('htmlBtn').onclick = () => {
    saveMemo();
    const vals = [...form.querySelectorAll('textarea')].map(t => t.value.replace(/\n/g, '<br>'));
    const html = `<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><title>4マスメモ - HTML出力</title>
    <style>body{font-family:sans-serif;padding:20px}
    h1{font-size:20px;margin-bottom:20px}
    table{border-collapse:collapse;width:100%;max-width:900px;margin-top:20px;table-layout:fixed}
    th,td{border:1px solid #999;padding:10px;font-size:14px;vertical-align:top;width:50%;word-wrap:break-word}
    th{background:#f2f2f2}</style></head><body>
    <h1>メモ</h1><table><thead><tr><th>項目 1</th><th>項目 2</th></tr></thead>
    <tbody><tr><td>${vals[0]}</td><td>${vals[1]}</td></tr><tr><td>${vals[2]}</td><td>${vals[3]}</td></tr></tbody></table></body></html>`;

    const blob = new Blob([html], {type: 'text/html;charset=utf-8'});
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `memo_2x2_${Date.now()}.html`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };


document.getElementById("savePdfBtn").addEventListener("click", () => {
  const { jsPDF } = window.jspdf;
  const doc = new jsPDF({ unit: 'pt', format: 'a4' });

  // ✅ 日本語フォントを埋め込み
  doc.addFileToVFS("NotoSansJP-Regular.ttf", window.NotoSansJP_Base64);
  doc.addFont("NotoSansJP-Regular.ttf", "NotoSansJP", "normal");
  doc.setFont("NotoSansJP");
  doc.setFontSize(16);

  // ✅ テキストエリアからデータ収集
  const tableData = [];
  document.querySelectorAll(".memo tr").forEach((row) => {
    const rowData = [];
    row.querySelectorAll("td textarea").forEach((textarea) => {
      rowData.push((textarea.value || '').replace(/\r\n|\r/g, '\n'));
    });
    if (rowData.length > 0) tableData.push(rowData);
  });

  // ✅ PDF表として出力
  doc.autoTable({
    head: [['項目 1', '項目 2']],
    body: tableData,
    startY: 60,
    styles: {
      font: "NotoSansJP",
      fontSize: 10,
      cellPadding: 8,
      valign: 'top',
      lineColor: [0, 0, 0],
      lineWidth: 0.2
    },
    headStyles: {
      fillColor: [100, 100, 100],
      fontStyle: 'normal',
      halign: 'center'
    },
    columnStyles: {
      0: { cellWidth: doc.internal.pageSize.getWidth() / 2 - 40 },
      1: { cellWidth: doc.internal.pageSize.getWidth() / 2 - 40 }
    },
    margin: { left: 40, right: 40 }
  });

  // ✅ PDFとして保存
  doc.save("4masu-memo.pdf");
});



  document.getElementById('pdfBtn').onclick = () => {
    saveMemo();
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF({ unit: 'pt', format: 'a4' });
    doc.addFileToVFS("NotoSansJP-Regular.ttf", window.NotoSansJP_Base64);
    doc.addFont("NotoSansJP-Regular.ttf", "NotoSansJP", "normal");
    doc.setFont("NotoSansJP");
    doc.setFontSize(16);
    doc.text('メモ', 40, 40);

    const vals = [...document.querySelectorAll('textarea')].map(t =>
      (t.value || '').replace(/\r\n|\r/g, '\n')
    );
    const body = [[vals[0], vals[1]], [vals[2], vals[3]]];
    doc.autoTable({
      head: [['項目 1', '項目 2']],
      body,
      startY: 60,
      styles: {
        font: "NotoSansJP",
        fontSize: 10,
        cellPadding: 8,
        valign: 'top',
        lineColor: [0, 0, 0],      // 黒色の罫線
        lineWidth: 0.2             // 線の太さ(0.1〜0.5程度がおすすめ)
      },
      headStyles: {
        fillColor: [100, 100, 100],
        fontStyle: 'normal',
        halign: 'center'
      },
      columnStyles: {
        0: { cellWidth: doc.internal.pageSize.getWidth() / 2 - 40 },
        1: { cellWidth: doc.internal.pageSize.getWidth() / 2 - 40 }
      },
      margin: { left: 40, right: 40 }
    });

    doc.save(`memo_2x2_${Date.now()}.pdf`);
    showToast();
  };

  function setMemoWidth(size) {
    const memoTable = document.getElementById('memoTable');
    const mainDiv = document.getElementById('main');  // ← 修正ポイント

    memoTable.classList.remove('normal', 'wide');
    memoTable.classList.add(size);

    // 幅の切替を確実に
    if (size === 'wide') {
      mainDiv.style.width = '1200px';
      mainDiv.style.maxWidth = '100%';
    } else {
      mainDiv.style.width = '850px';
      mainDiv.style.maxWidth = '100%';
    }

    localStorage.setItem('memoWidth', size);
  }

  function loadMemoWidth() {
    const savedWidth = localStorage.getItem('memoWidth') || 'normal';
    setMemoWidth(savedWidth);
  }

  function toggleMenu(btn) {
    btn.classList.toggle('open');
  }

  document.addEventListener('click', e => {
    if (!e.target.closest('.hamburger-menu')) {
      document.querySelector('.hamburger-menu').classList.remove('open');
    }
  });

  document.addEventListener('DOMContentLoaded', () => {
    loadMemoWidth();
  });
</script>

<script src="../load_header.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>4マスメモ</title>
    <link rel="stylesheet" href="../style.css">

<link rel="stylesheet" href="../style.css?20250630">
<script defer src="../header.js"></script>
<script defer src="../sidebar.js"></script>

<!-- jsPDF & autoTable(PDF 出力用) -->
<script src="https://cdn.jsdelivr.net/npm/jspdf@2.5.1/dist/jspdf.umd.min.js"></script>
<script src="data/jspdf-font-noto.js"></script>     <!-- NotoSansJP 登録 -->
<script src="https://cdn.jsdelivr.net/npm/jspdf-autotable@3.5.28/dist/jspdf.plugin.autotable.min.js"></script>

<style>
/* ■ 表(2×2)専用スタイル ●*/
table.memo{
  width:100%;
  max-width:1200px;               /* ★ 横幅をゆったり広げる */
  border-collapse:collapse;
  margin:24px auto;
}
.memo th,.memo td{border:1px solid #ccc;padding:6px;text-align:center}
.memo th{background:#e9ecef}
.memo td textarea {
  width: 100%;
  min-height: 480px;       /* 初期高さ(任意) */
  resize: none;
  overflow: hidden;        /* スクロールバー非表示 */
  border: none;
  box-sizing: border-box;
}
.save-btn{display:block;width:100%;max-width:200px;margin:16px auto;padding:8px 0}
#toast{position:fixed;left:50%;bottom:40px;transform:translateX(-50%);
       background:#333;color:#fff;padding:8px 16px;border-radius:4px;font-size:.9rem;
       opacity:0;pointer-events:none;transition:opacity .3s}
#toast.show{opacity:1}
</style>
</head>
<body>
    <div id="header-placeholder"></div>
    <div class="page-wrapper">
        <aside id="sidebar">
            <!-- Sidebar content will be injected here by JS -->
        </aside>
        <div class="content-wrapper">
            <div class="main" style="width:900px;">
    <button id="saveTop" class="save-btn">保存</button>

    <h2 class="head-i">4マスメモ</h2>

 <a href="shoshiki-memo.html">書式メモ</a>

    <form id="memoForm">
      <table class="memo">
        <!-- ★ ヘッダー行を追加 -->
        <thead>
          <tr><th>項目 1</th><th>項目 2</th></tr>
        </thead>
        <tbody>
          <tr>
            <td><textarea data-cell="0-0"></textarea></td>
            <td><textarea data-cell="0-1"></textarea></td>
          </tr>
          <tr>
            <td><textarea data-cell="1-0"></textarea></td>
            <td><textarea data-cell="1-1"></textarea></td>
          </tr>
        </tbody>
      </table>
    </form>

    <button id="saveBottom" class="save-btn">保存</button>
    <button id="htmlBtn" class="save-btn">HTMLで保存</button>
    <button id="pdfBtn" class="save-btn">PDF で保存</button>
  </main>
</div>

<div id="toast">保存しました</div>

<script>
/* ---------- 保存/読込 ---------- */
const form  = document.getElementById('memoForm');
const toast = document.getElementById('toast');
const lsKey = 'memo_2x2';

function showToast(){toast.classList.add('show');setTimeout(()=>toast.classList.remove('show'),2000);}

function loadMemo(){
  const data = JSON.parse(localStorage.getItem(lsKey) || '{}');
  form.querySelectorAll('textarea').forEach(ta=>{
    ta.value = data[ta.dataset.cell] || '';
  });
}

function autoResizeTextarea(el) {
  el.style.height = 'auto'; // 一旦リセット
  el.style.height = (el.scrollHeight) + 'px';
}

// 初期化 & 入力時に高さ調整
form.querySelectorAll('textarea').forEach(textarea => {
  autoResizeTextarea(textarea); // ページ表示時
  textarea.addEventListener('input', () => autoResizeTextarea(textarea));
});

function saveMemo(){
  const data = {};
  form.querySelectorAll('textarea').forEach(ta=>{
    data[ta.dataset.cell] = ta.value;
  });
  localStorage.setItem(lsKey, JSON.stringify(data));
  showToast();
}
loadMemo();
document.getElementById('saveTop').onclick =
document.getElementById('saveBottom').onclick = e=>{e.preventDefault();saveMemo();};

/* ---------- HTML 出力 ---------- */
document.getElementById('htmlBtn').onclick = () => {
  saveMemo(); // 現在の内容を保存

  // テキスト取得
  const vals = [...form.querySelectorAll('textarea')].map(t =>
    t.value.replace(/\n/g, '<br>')
  );

  // HTML内容を作成
  let html = `
    <!DOCTYPE html>
    <html lang="ja">
    <head>
      <meta charset="UTF-8">
      <title>4マスメモ - HTML出力</title>
      <style>
        body { font-family: sans-serif; padding: 20px; }
        h1 { font-size: 20px; margin-bottom: 20px; }
        table { border-collapse: collapse; width: 100%; max-width: 900px; margin-top: 20px; }
        th, td { border: 1px solid #999; padding: 10px; font-size: 14px; vertical-align: top; }
        th { background: #f2f2f2; }
      </style>
    </head>
    <body>
      <h1>メモ</h1>
      <table>
        <thead>
          <tr><th>項目 1</th><th>項目 2</th></tr>
        </thead>
        <tbody>
          <tr><td>${vals[0]}</td><td>${vals[1]}</td></tr>
          <tr><td>${vals[2]}</td><td>${vals[3]}</td></tr>
        </tbody>
      </table>
    </body>
    </html>
  `;

  // Blob を使ってHTMLファイルとしてダウンロード
  const blob = new Blob([html], { type: 'text/html;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `memo_2x2_${Date.now()}.html`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
};


/* ---------- PDF 出力 ---------- */
document.getElementById('pdfBtn').onclick = ()=>{
  saveMemo();
  const { jsPDF } = window.jspdf;
  const doc = new jsPDF({unit:'pt',format:'a4'});
  doc.setFont('NotoSansJP','normal').setFontSize(12);

  const vals=[...form.querySelectorAll('textarea')].map(t=>t.value.replace(/\n/g,' / '));
  const body=[[vals[0],vals[1]],[vals[2],vals[3]]];

  doc.autoTable({
    head: [['項目 1','項目 2']],       /* ヘッダーも反映 */
    body,
    startY:60,
    styles:{font:'NotoSansJP',cellPadding:5,valign:'top'},
    columnStyles:{0:{cellWidth:430},1:{cellWidth:430}}  /* ★ 備考:横幅拡大 */
  });
  doc.save('memo_2x2.pdf');
};
</script>

            </div>
        </div>
    </div>
    <script src="../load_header.js"></script>
</body>
</html>
よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

目次