@takagaki/cortex-decisions-viewer 0.4.13 → 0.4.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/render.js +74 -16
  2. package/package.json +1 -1
package/dist/render.js CHANGED
@@ -370,6 +370,27 @@ button.ops-card-btn:disabled { opacity: .6; cursor: default; }
370
370
  background: var(--surface); color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer;
371
371
  }
372
372
  .modal-cancel:hover { background: var(--bg); }
373
+ .modal-ok { color: #047857; font-weight: 600; }
374
+ .modal-status-error { color: #dc2626; font-weight: 600; }
375
+ .modal-paths { margin-top: 8px; display: flex; flex-direction: column; gap: 4px; }
376
+ .modal-paths-label { font-size: 12px; color: var(--muted); }
377
+ .modal-path { font-size: 12.5px; word-break: break-all; color: var(--accent); }
378
+ /* ドラッグ&ドロップ */
379
+ .modal-file-hidden { display: none; }
380
+ .dropzone {
381
+ border: 2px dashed var(--border); border-radius: 10px; padding: 22px 16px; text-align: center;
382
+ cursor: pointer; color: var(--muted); font-size: 13px; background: var(--bg); transition: border-color .15s, background .15s, color .15s;
383
+ }
384
+ .dropzone:hover, .dropzone.dragover { border-color: var(--accent); background: var(--accent-weak); color: var(--accent); }
385
+ .dropzone-text { pointer-events: none; }
386
+ .dropzone-files { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; justify-content: center; }
387
+ .file-chip {
388
+ display: inline-flex; align-items: center; gap: 6px; background: var(--surface);
389
+ border: 1px solid var(--border); border-radius: 999px; padding: 3px 4px 3px 10px; font-size: 12px; color: var(--text); max-width: 100%;
390
+ }
391
+ .file-chip > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 260px; }
392
+ .file-chip-x { border: none; background: none; cursor: pointer; color: var(--muted); font-size: 16px; line-height: 1; padding: 0 4px; }
393
+ .file-chip-x:hover { color: #dc2626; }
373
394
  .summary-box { background: var(--accent-weak); border: 1px solid #dce6fb; border-radius: var(--radius); padding: 12px 16px; color: #1e3a8a; }
374
395
  .deciders { display: flex; flex-wrap: wrap; gap: 8px; }
375
396
  .refs { margin: 0; padding-left: 18px; }
@@ -660,40 +681,64 @@ const CLIENT_JS = `
660
681
  var modal = el("div", { class: "modal" });
661
682
  modal.appendChild(el("h2", { class: "modal-title", text: isT ? "会議の文字起こしを追加" : "共有資料を追加" }));
662
683
  modal.appendChild(el("p", { class: "modal-desc", text: isT
663
- ? "文字起こしファイル(.txt / .docx 等)を選んで送信すると、議事録を自動生成します。"
664
- : "資料ファイル(PDF / PPT / Excel 等)を選んで送信すると、Markdown 化して取り込みます。" }));
665
- var fileInput = el("input", { type: "file", multiple: "multiple", class: "modal-file" });
684
+ ? "文字起こしファイル(.txt / .docx 等)を選んで送信してください。(送信後、数分で議事録が自動生成されます)"
685
+ : "資料ファイル(PDF / PPT / Excel 等)を選んで送信してください。(送信後、数分でファイルの内容が Markdown に変換されて取り込まれます)" }));
686
+
687
+ var selectedFiles = [];
688
+ var fileInput = el("input", { type: "file", multiple: "multiple", class: "modal-file-hidden" });
689
+ var fileListEl = el("div", { class: "dropzone-files" });
690
+ var dropzone = el("div", { class: "dropzone" }, [
691
+ el("div", { class: "dropzone-text", text: "📄 ファイルをドラッグ&ドロップ、またはクリックして選択" }),
692
+ fileListEl,
693
+ fileInput,
694
+ ]);
666
695
  var nameInput = el("input", { type: "text", class: "modal-name", placeholder: "投入者として記録されます" });
667
- modal.appendChild(fieldRow("ファイル(必須)", fileInput));
696
+ modal.appendChild(fieldRow("ファイル(必須)", dropzone));
668
697
  modal.appendChild(fieldRow("お名前(必須)", nameInput));
669
698
  var status = el("div", { class: "modal-status" });
670
699
  var cancelBtn = el("button", { class: "modal-cancel", text: "閉じる" });
671
700
  var submitBtn = el("button", { class: "ops-card-btn", text: "送信" });
701
+ submitBtn.disabled = true;
672
702
  modal.appendChild(status);
673
703
  modal.appendChild(el("div", { class: "modal-actions" }, [cancelBtn, submitBtn]));
674
704
  overlay.appendChild(modal);
675
705
  document.body.appendChild(overlay);
706
+
707
+ function update() { submitBtn.disabled = !(nameInput.value.trim() && selectedFiles.length); }
708
+ function renderFiles() {
709
+ fileListEl.textContent = "";
710
+ selectedFiles.forEach(function (f, idx) {
711
+ var x = el("button", { class: "file-chip-x", type: "button", text: "×" });
712
+ x.addEventListener("click", function (e) { e.stopPropagation(); selectedFiles.splice(idx, 1); renderFiles(); update(); });
713
+ fileListEl.appendChild(el("span", { class: "file-chip" }, [el("span", { text: f.name }), x]));
714
+ });
715
+ }
716
+ function addFiles(list) { Array.prototype.slice.call(list || []).forEach(function (f) { selectedFiles.push(f); }); renderFiles(); update(); }
717
+ dropzone.addEventListener("click", function () { fileInput.click(); });
718
+ fileInput.addEventListener("change", function () { addFiles(fileInput.files); fileInput.value = ""; });
719
+ dropzone.addEventListener("dragover", function (e) { e.preventDefault(); dropzone.classList.add("dragover"); });
720
+ dropzone.addEventListener("dragleave", function () { dropzone.classList.remove("dragover"); });
721
+ dropzone.addEventListener("drop", function (e) { e.preventDefault(); dropzone.classList.remove("dragover"); addFiles(e.dataTransfer.files); });
722
+ nameInput.addEventListener("input", update);
723
+
676
724
  function close() { if (overlay.parentNode) document.body.removeChild(overlay); }
677
725
  cancelBtn.addEventListener("click", close);
678
726
  overlay.addEventListener("click", function (e) { if (e.target === overlay) close(); });
679
- submitBtn.addEventListener("click", function () {
680
- submitIntake(kind, fileInput.files, nameInput.value, status, submitBtn);
681
- });
727
+ submitBtn.addEventListener("click", function () { submitIntake(kind, selectedFiles, nameInput.value, status, submitBtn); });
682
728
  }
683
- async function submitIntake(kind, fileList, submitter, status, submitBtn) {
729
+ async function submitIntake(kind, files, submitter, status, submitBtn) {
684
730
  var intake = SITE.intake;
685
- var files = fileList ? Array.prototype.slice.call(fileList) : [];
686
- // 必須: お名前 ファイル
687
- if (!submitter || !submitter.trim()) { status.textContent = "⚠ お名前を入力してください。"; return; }
688
- if (!files.length) { status.textContent = "⚠ ファイルを選択してください。"; return; }
731
+ function setStatus(msg, isError) { status.className = "modal-status" + (isError ? " modal-status-error" : ""); status.textContent = msg; }
732
+ if (!submitter || !submitter.trim()) { setStatus("⚠ お名前を入力してください。", true); return; }
733
+ if (!files || !files.length) { setStatus("⚠ ファイルを選択してください。", true); return; }
689
734
  submitBtn.disabled = true;
690
735
  var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
691
- function fail(msg) { status.textContent = "✗ " + msg; submitBtn.disabled = false; }
736
+ function fail(msg) { setStatus("✗ " + msg, true); submitBtn.disabled = false; }
692
737
  try {
693
738
  var uploaded = [];
694
739
  for (var i = 0; i < files.length; i++) {
695
740
  var f = files[i];
696
- status.textContent = "アップロード中… (" + (i + 1) + "/" + files.length + ") " + f.name;
741
+ setStatus("アップロード中… (" + (i + 1) + "/" + files.length + ") " + f.name, false);
697
742
  var pres;
698
743
  try {
699
744
  pres = await fetch(pfx + "op=presign&t=" + encodeURIComponent(intake.token), {
@@ -709,7 +754,7 @@ const CLIENT_JS = `
709
754
  if (!put.ok) return fail("ファイルのアップロードに失敗しました(" + put.status + ")。ファイルのサイズ・形式をご確認ください。");
710
755
  uploaded.push({ key: pres.j.key, filename: f.name });
711
756
  }
712
- status.textContent = "取り込み中…";
757
+ setStatus("取り込み中…", false);
713
758
  var sub;
714
759
  try {
715
760
  sub = await fetch(pfx + "op=submit&t=" + encodeURIComponent(intake.token), {
@@ -718,8 +763,21 @@ const CLIENT_JS = `
718
763
  }).then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); });
719
764
  } catch (net3) { return fail("サーバーに接続できませんでした。もう一度お試しください。"); }
720
765
  if (!sub.ok) return fail((sub.j && sub.j.message) || "取り込みに失敗しました。時間をおいて再度お試しください。");
721
- status.textContent = "✓ 送信しました。数分後に" + (kind === "transcript" ? "議事録" : "資料") + "が反映されます。閉じて構いません。";
766
+ status.className = "modal-status";
767
+ status.textContent = "";
768
+ status.appendChild(el("div", { class: "modal-ok", text: "✓ 送信しました。数分後に" + (kind === "transcript" ? "議事録が自動生成され" : "内容がMarkdownに変換されて") + "反映されます。" }));
769
+ var paths = (sub.j && sub.j.committed) || [];
770
+ if (paths.length && sub.j.repo) {
771
+ var br = SITE.branch || "main";
772
+ var box = el("div", { class: "modal-paths" }, [el("div", { class: "modal-paths-label", text: "保存先(GitHub):" })]);
773
+ paths.forEach(function (p) {
774
+ var href = "https://github.com/" + sub.j.repo + "/blob/" + encodeURIComponent(br) + "/" + p.split("/").map(encodeURIComponent).join("/");
775
+ box.appendChild(el("a", { class: "modal-path", href: href, target: "_blank", rel: "noopener", text: p }));
776
+ });
777
+ status.appendChild(box);
778
+ }
722
779
  submitBtn.textContent = "完了";
780
+ submitBtn.disabled = true;
723
781
  } catch (e) {
724
782
  fail(e && e.message ? e.message : "予期しないエラーが発生しました。");
725
783
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.4.13",
3
+ "version": "0.4.15",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,