[2026-09-23 02:13:54 CST]

<?php

$saved_file = 'notebook.txt';

$archive_dir = '/notepad/archive/';

$export_dir = '/notepad/exports/';

$bookmarks_file = 'bookmarks.html';

// ── Helper: wrap notebook content in a standalone HTML shell ──────────────

function make_html_document(string $body_content, string $title): string {

return <<<HTML

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>{$title}</title>

<style>

body { background:#fff; color:#000; font-family:sans-serif; padding:20px; max-width:900px; margin:auto; }

.journal-entry { border-bottom:1px dashed #000; margin-bottom:25px; padding-bottom:15px; }

.journal-entry p, .journal-entry div { line-height:1.05; margin-top:2px; margin-bottom:6px; }

small { color:#000; font-family:monospace; }

</style>

</head>

<body>

{$body_content}

</body>

</html>

HTML;

}

// ── Helper: append a bookmark entry ──────────────────────────────────────

function append_bookmark(string $bookmarks_file, string $label, string $href): void {

$timestamp = (new DateTime('now', new DateTimeZone('America/Chicago')))->format('Y-m-d H:i:s');

$entry = "<li data-ts=\"{$timestamp}\"><a href=\"" . htmlspecialchars($href, ENT_QUOTES) . "\">"

. htmlspecialchars($label, ENT_QUOTES) . "</a> <small style='color:#000;'>[{$timestamp} CST]</small></li>\n";

$current = file_exists($bookmarks_file) ? file_get_contents($bookmarks_file) : "<ul id=\"bookmarks\">\n</ul>";

// Insert new entry right after the opening <ul> tag

$updated = preg_replace('/<ul id="bookmarks">\n/', "<ul id=\"bookmarks\">\n" . $entry, $current, 1);

file_put_contents($bookmarks_file, $updated);

}

// ── Helper: read the 10 most recent bookmark <li> entries ─────────────────

function get_recent_bookmarks(string $bookmarks_file, int $limit = 10): string {

if (!file_exists($bookmarks_file)) return '';

$html = file_get_contents($bookmarks_file);

preg_match_all('/<li data-ts="[^"]*">.*?<\/li>/s', $html, $matches);

if (empty($matches[0])) return '';

$items = array_slice($matches[0], 0, $limit);

return '<ul style="margin:0; padding-left:18px; font-size:1.4 em;">' . implode("\n", $items) . '</ul>';

}

// ── POST handling ─────────────────────────────────────────────────────────

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

// ACTION: Clear + archive + optional export

if (isset($_POST['action']) && $_POST['action'] === 'clear') {

if (file_exists($saved_file)) {

$tz = new DateTimeZone('America/Chicago');

$dt = new DateTime('now', $tz);

$ts = $dt->format('Y.m.d.H.i.s'); // e.g. 2026.09.21.14.22.13

$body = file_get_contents($saved_file);

// ── Auto-archive ──────────────────────────────────────────────

$archive_name = "notebook_{$ts}.html";

$archive_path = $archive_dir . $archive_name;

file_put_contents($archive_path, make_html_document($body, "Notebook archive {$ts}"));

// ── Optional export ───────────────────────────────────────────

$stem = isset($_POST['export_stem']) ? trim($_POST['export_stem']) : '';

// Sanitize: allow only alphanumeric, dash, underscore, dot

$stem = preg_replace('/[^a-zA-Z0-9_\-.]/', '', $stem);

if ($stem !== '') {

$export_name = "{$stem}.html";

$export_path = $export_dir . $export_name;

file_put_contents($export_path, make_html_document($body, $stem));

// Add bookmark — path relative to /notepad so the web link works

$web_href = "exports/{$export_name}";

append_bookmark($bookmarks_file, $stem, $web_href);

}

unlink($saved_file);

}

exit;

}

// ACTION: Append new entry

if (isset($_POST['content_html']) && trim($_POST['content_html']) !== '') {

$new_snippet = $_POST['content_html'];

$tz = new DateTimeZone('America/Chicago');

$timestamp = (new DateTime('now', $tz))->format('Y-m-d H:i:s');

$entry_wrapper = "<div class='journal-entry' style='border-bottom:1px dshed #000; margin-bottom:25px; padding-bottom:15px;'>";

$entry_wrapper .= "<small style='color:#000; font-family:monospace;'>[{$timestamp} CST]</small><br>";

$entry_wrapper .= $new_snippet;

$entry_wrapper .= "</div>";

$old_content = file_exists($saved_file) ? file_get_contents($saved_file) : '';

file_put_contents($saved_file, $entry_wrapper . $old_content);

header("Location: " . $_SERVER['PHP_SELF']);

exit;

}

}

// ── Load display data ─────────────────────────────────────────────────────

$notebook_history = "<p style='color:#000;'>No entries logged yet. Write your first snippet above!</p>";

if (file_exists($saved_file)) {

$notebook_history = file_get_contents($saved_file);

}

$recent_bookmarks = get_recent_bookmarks($bookmarks_file);

?>

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Notebook</title>

<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.css"/>

<script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js"></script>

<style>

.toastui-editor-contents,

.toastui-editor-ww-container .toastui-editor-contents p,

.toastui-editor-ww-container .toastui-editor-contents div {

color:#000; line-height:1.05 !important;

}

.notebook-render, .notebook-render p,

.journal-entry, .journal-entry p, .journal-entry div {

color:#000; line-height:1.0 !important;

margin-top:2px !important; margin-bottom:6px !important;

}

.toastui-editor-contents li, .notebook-render li, .journal-entry li {

color:#000; line-height:1.0 !important; margin-bottom:3px !important;

}

.toastui-editor-defaultUI-toolbar {

height:28px !important; padding:0 2px !important;

background-color:#fff !important;

display:flex !important; align-items:center !important; overflow:hidden !important;

}

.toastui-editor-defaultUI-toolbar .toastui-editor-toolbar-icons {

transform:scale(0.75) !important; transform-origin:center !important; margin:0 -2px !important;

}

.toastui-editor-defaultUI-toolbar .toastui-editor-toolbar-divider {

height:14px !important; margin:0 3px !important;

}

.toastui-editor-toolbar-group {

height:28px !important; display:flex !important; align-items:center !important;

}

/* Export inline prompt */

#clear-section { margin-top:10px; }

#export-row { display:none; margin-top:6px; font-size:0.85em; }

#export-row input[type="text"] {

border:1px solid #000; padding:3px 6px; font-size:1.0em; width:180px;

}

#export-row button, #clear-btn {

background:#fff; border:1px solid #000; color:#000;

padding:5px 10px; cursor:pointer; font-size:1.0em;

}

/* Bookmarks strip */

#bookmarks-strip {

font-size:1.0em; border:1px solid #ccc;

padding:8px 12px; margin-top:18px; margin-bottom:0;

background:#fafafa;

}

#bookmarks-strip summary {

cursor:pointer; font-weight:bold; font-size:1.0em; color:#444;

}

</style>

</head>

<body style="background:#fff; color:#000; font-family:sans-serif; padding:10px;">

<p style="font-size:x-small; font-style:italic; text-align:right;">

Quick notes - code snippets, ndcs, etc (no PHI, PII, financial info)

</p>

<!-- ── Entry form ─────────────────────────────────────────────── -->

<form id="notebook-form" action="index.php" method="POST">

<div id="editor"></div>

<input type="hidden" id="hidden-content-input" name="content_html">

<p style="margin-top:15px;">

<button type="button" id="save-btn"

style="background:#fff; border:1px solid #000; color:#000; padding:8px 16px; cursor:pointer; font-weight:bold;">

Add Entry

</button>

</p>

</form>

<!-- ── Clear + export section ────────────────────────────────── -->

<div id="clear-section">

<button type="button" id="clear-btn">Clear Content</button>

<!-- Inline export prompt — shown after clicking Clear -->

<div id="export-row">

<label>Export filename stem (leave blank to skip):&nbsp;

<input type="text" id="export-stem-input" placeholder="e.g. weekly_notes_sep21" autocomplete="off">

</label>

&nbsp;

<button type="button" id="confirm-clear-btn">Archive & Clear</button>

&nbsp;

<button type="button" id="cancel-clear-btn">Cancel</button>

</div>

</div>

<a href = "bookmarks.html">bookmarks.html</a>

<!-- <div> <iframe src = "bookmarks.html"> </iframe></div> -->

<!-- Hidden form submitted programmatically for clear action -->

<form id="clear-form" action="index.php" method="POST" style="display:none;">

<input type="hidden" name="action" value="clear">

<input type="hidden" id="export-stem-hidden" name="export_stem" value="">

</form>

<!-- ── Recent bookmarks ───────────────────────────────────────── -->

<?php if ($recent_bookmarks): ?>

<details id="bookmarks-strip" open>

<summary>Recent exports / bookmarks</summary>

<div style="margin-top:6px;">

<?php echo $recent_bookmarks; ?>

</div>

</details>

<?php endif; ?>

<!-- ── Notebook viewer ────────────────────────────────────────── -->

<div style="background:#fff; border:1px solid #000; padding:25px; margin-top:30px;">

<div class="notebook-render">

<?php echo $notebook_history; ?>

</div>

</div>

<script>

// ── ToastUI editor ────────────────────────────────────────────

const editor = new toastui.Editor({

el: document.querySelector('#editor'),

previewStyle: 'vertical',

height: '250px',

initialValue: '',

initialEditType: 'wysiwyg'

});

document.querySelector('#save-btn').addEventListener('click', function () {

if (editor.getMarkdown().trim() === '') {

alert('Please write something before logging it.');

return;

}

document.querySelector('#hidden-content-input').value = editor.getHTML();

document.getElementById('notebook-form').submit();

});

// ── Clear / export flow ───────────────────────────────────────

const clearBtn = document.getElementById('clear-btn');

const exportRow = document.getElementById('export-row');

const confirmClearBtn = document.getElementById('confirm-clear-btn');

const cancelClearBtn = document.getElementById('cancel-clear-btn');

const exportStemInput = document.getElementById('export-stem-input');

const exportStemHidden = document.getElementById('export-stem-hidden');

const clearForm = document.getElementById('clear-form');

// Step 1: reveal inline prompt

clearBtn.addEventListener('click', function () {

exportRow.style.display = 'block';

exportStemInput.focus();

clearBtn.style.display = 'none';

});

// Step 2a: user confirms (with or without a stem)

confirmClearBtn.addEventListener('click', function () {

exportStemHidden.value = exportStemInput.value.trim();

clearForm.submit();

});

// Step 2b: user cancels — restore original state

cancelClearBtn.addEventListener('click', function () {

exportRow.style.display = 'none';

exportStemInput.value = '';

clearBtn.style.display = 'inline-block';

});

// Allow Enter key in the stem field to confirm

exportStemInput.addEventListener('keydown', function (e) {

if (e.key === 'Enter') { e.preventDefault(); confirmClearBtn.click(); }

if (e.key === 'Escape') { cancelClearBtn.click(); }

});

</script>

</body>

</html>