diff --git a/sites/labs/public/CommonMark-Demo/CommonMark/commonmark-0.27.1.jar b/sites/labs/public/CommonMark-Demo/CommonMark/commonmark-0.27.1.jar new file mode 100644 index 00000000..d673738f Binary files /dev/null and b/sites/labs/public/CommonMark-Demo/CommonMark/commonmark-0.27.1.jar differ diff --git a/sites/labs/public/CommonMark-Demo/Template/preview.css b/sites/labs/public/CommonMark-Demo/Template/preview.css new file mode 100644 index 00000000..29cd98dd --- /dev/null +++ b/sites/labs/public/CommonMark-Demo/Template/preview.css @@ -0,0 +1,189 @@ +:root { + color-scheme: light; + + /* Layout */ + --pad: 18px; + --max: 920px; + + /* Typography */ + --font: ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif; + --mono: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + + /* Colors */ + --fg: #0b1220; + --muted: #475569; + --bg: #ffffff; + --link: #2563eb; + + --surface: #f7f9fc; + --border: #e6eaf2; + + /* Radius */ + --r-sm: 8px; + --r-md: 12px; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html, +body { + height: 100%; +} + +body { + margin: 0; + background: var(--bg); + color: var(--fg); + font-family: var(--font); + line-height: 1.6; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* Keep the preview readable on wide screens */ +body > * { + max-width: var(--max); + margin-left: auto; + margin-right: auto; +} + +body { + padding: var(--pad); +} + +/* Typography */ +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 1.2; + margin: 1.05em 0 0.4em; + letter-spacing: -0.01em; +} + +h1 { + font-size: 1.65em; +} +h2 { + font-size: 1.35em; +} +h3 { + font-size: 1.15em; +} + +p { + margin: 0.65em 0; +} + +small { + color: var(--muted); +} + +a { + color: var(--link); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +/* Lists */ +ul, +ol { + margin: 0.65em 0; + padding-left: 1.25em; +} + +li { + margin: 0.25em 0; +} + +li > p { + margin: 0.35em 0; +} + +/* Code */ +code, +pre, +kbd { + font-family: var(--mono); + font-size: 0.95em; +} + +code { + background: var(--surface); + border: 1px solid var(--border); + padding: 0.12em 0.38em; + border-radius: var(--r-sm); +} + +pre { + background: var(--surface); + border: 1px solid var(--border); + padding: 12px 14px; + border-radius: var(--r-md); + overflow: auto; + line-height: 1.45; +} + +/* Ensure code blocks don't double-style */ +pre code { + background: transparent; + border: none; + padding: 0; + border-radius: 0; +} + +/* Quotes */ +blockquote { + margin: 0.9em 0; + padding: 0.35em 0 0.35em 14px; + border-left: 3px solid #d3dcf3; + color: var(--muted); +} + +/* Tables */ +table { + border-collapse: collapse; + margin: 0.9em 0; + width: 100%; +} + +th, +td { + border: 1px solid var(--border); + padding: 7px 10px; + vertical-align: top; +} + +th { + background: #f1f5ff; + text-align: left; +} + +/* Images and rules */ +img { + max-width: 100%; + height: auto; + border-radius: var(--r-md); +} + +hr { + border: 0; + border-top: 1px solid var(--border); + margin: 18px 0; +} + +/* Subtle selection */ +::selection { + background: rgba(37, 99, 235, 0.18); +} diff --git a/sites/labs/public/CommonMark-Demo/Template/preview.html b/sites/labs/public/CommonMark-Demo/Template/preview.html new file mode 100644 index 00000000..e88ef3e0 --- /dev/null +++ b/sites/labs/public/CommonMark-Demo/Template/preview.html @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/sites/labs/public/CommonMark-Demo/index.html b/sites/labs/public/CommonMark-Demo/index.html new file mode 100644 index 00000000..1f7ecd64 --- /dev/null +++ b/sites/labs/public/CommonMark-Demo/index.html @@ -0,0 +1,152 @@ + + + + + +${String(e)}
+ `;
+ }
+ }
+ setStatus("Rendered", { busy: false });
+ } catch (err) {
+ console.error("Render failed:", err);
+ setStatus("Render failed — see console", { busy: false });
+ }
+}
+
+async function loadPreviewAssets() {
+ if (previewHtmlTpl && previewCssText) return;
+
+ const htmlUrl = new URL(
+ "./Template/preview.html",
+ window.location.href
+ ).toString();
+ const cssUrl = new URL(
+ "./Template/preview.css",
+ window.location.href
+ ).toString();
+
+ const [htmlResp, cssResp] = await Promise.all([
+ fetch(htmlUrl),
+ fetch(cssUrl),
+ ]);
+
+ if (!htmlResp.ok)
+ throw new Error(
+ `Failed to load preview.html: ${htmlResp.status} ${htmlResp.statusText}`
+ );
+ if (!cssResp.ok)
+ throw new Error(
+ `Failed to load preview.css: ${cssResp.status} ${cssResp.statusText}`
+ );
+
+ previewHtmlTpl = await htmlResp.text();
+ previewCssText = await cssResp.text();
+}
+
+async function buildPreviewDoc(htmlBody) {
+ await loadPreviewAssets();
+
+ if (!previewHtmlTpl.includes("")) {
+ throw new Error("preview.html missing marker");
+ }
+ if (!previewHtmlTpl.includes("")) {
+ throw new Error("preview.html missing marker");
+ }
+
+ return previewHtmlTpl
+ .replace("", ``)
+ .replace("", htmlBody || "");
+}
+
+// Events
+mdInput.addEventListener("input", () => {
+ if (liveToggle.checked) debounceRender(300);
+});
+
+liveToggle.addEventListener("change", () => {
+ applyLiveUiState();
+ // If user turns live ON, render once immediately
+ if (liveToggle.checked) renderMarkdown({ reason: "manual" });
+});
+
+btnRender.addEventListener("click", () => renderMarkdown({ reason: "manual" }));
+
+btnReset.addEventListener("click", async () => {
+ mdInput.value = defaultMarkdown();
+ await renderMarkdown({ reason: "manual" });
+});
+
+btnHelp.addEventListener("click", () => {
+ const isHidden = side.classList.contains("side-hidden");
+ setSideVisible(isHidden);
+});
+
+btnCloseSide.addEventListener("click", () => {
+ setSideVisible(false);
+});
+
+// Start
+init().catch((err) => {
+ console.error("Init failed:", err);
+ setStatus("Failed to start", { busy: false });
+});
diff --git a/sites/labs/public/CommonMark-Demo/style.css b/sites/labs/public/CommonMark-Demo/style.css
new file mode 100644
index 00000000..8e13a52c
--- /dev/null
+++ b/sites/labs/public/CommonMark-Demo/style.css
@@ -0,0 +1,437 @@
+:root {
+ /* Neutral “product” palette */
+ --bg: #0b1020;
+ --surface: rgba(255, 255, 255, 0.06);
+ --border: rgba(255, 255, 255, 0.1);
+ --text: rgba(255, 255, 255, 0.92);
+ --muted: rgba(255, 255, 255, 0.6);
+
+ --accent: #3b82f6;
+ --ok: #22c55e;
+ --warn: #f59e0b;
+
+ --radius-xl: 18px;
+ --radius-lg: 14px;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+html,
+body {
+ height: 100%;
+ margin: 0;
+ background: radial-gradient(
+ 1200px 800px at 20% 0%,
+ #121a35 0%,
+ var(--bg) 55%,
+ #070a14 100%
+ );
+ color: var(--text);
+ font-family:
+ system-ui,
+ -apple-system,
+ BlinkMacSystemFont,
+ "Segoe UI",
+ sans-serif;
+}
+
+.app {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+.appbar {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ padding: 12px 14px;
+ border-bottom: 1px solid var(--border);
+ background: rgba(10, 14, 28, 0.72);
+ backdrop-filter: blur(10px);
+}
+
+.brand {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ min-width: 0;
+}
+.brand-text {
+ display: flex;
+ flex-direction: column;
+ gap: 1px;
+ min-width: 0;
+}
+.brand-title {
+ font-weight: 700;
+ font-size: 0.95rem;
+ line-height: 1.1;
+}
+.brand-subtitle {
+ font-size: 0.78rem;
+ color: var(--muted);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.appbar-spacer {
+ flex: 1;
+}
+
+.toolbar {
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.btn {
+ border: 1px solid var(--border);
+ background: rgba(255, 255, 255, 0.04);
+ color: var(--text);
+ border-radius: 999px;
+ padding: 7px 12px;
+ font-size: 0.82rem;
+ cursor: pointer;
+ transition:
+ transform 0.05s ease,
+ background 0.15s ease,
+ border-color 0.15s ease;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.btn:hover {
+ background: rgba(255, 255, 255, 0.07);
+ border-color: rgba(255, 255, 255, 0.16);
+}
+.btn:active {
+ transform: translateY(1px);
+}
+
+.btn-primary {
+ border-color: rgba(59, 130, 246, 0.45);
+ background: rgba(59, 130, 246, 0.18);
+}
+
+.btn-primary:hover {
+ background: rgba(59, 130, 246, 0.25);
+ border-color: rgba(59, 130, 246, 0.55);
+}
+
+.btn-ghost {
+ background: transparent;
+}
+
+.toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 10px;
+ border-radius: 999px;
+ border: 1px solid var(--border);
+ background: rgba(255, 255, 255, 0.04);
+ font-size: 0.82rem;
+ color: var(--muted);
+ user-select: none;
+}
+
+.toggle input {
+ display: none;
+}
+
+.toggle-ui {
+ width: 34px;
+ height: 20px;
+ border-radius: 999px;
+ position: relative;
+ background: rgba(255, 255, 255, 0.12);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ transition: background 0.15s ease;
+}
+
+.toggle-ui::after {
+ content: "";
+ position: absolute;
+ top: 2px;
+ left: 2px;
+ width: 16px;
+ height: 16px;
+ border-radius: 999px;
+ background: rgba(255, 255, 255, 0.86);
+ transition: transform 0.15s ease;
+}
+
+.toggle input:checked + .toggle-ui {
+ background: rgba(34, 197, 94, 0.18);
+ border-color: rgba(34, 197, 94, 0.28);
+}
+
+.toggle input:checked + .toggle-ui::after {
+ transform: translateX(14px);
+ background: rgba(255, 255, 255, 0.95);
+}
+
+.toggle-label {
+ color: var(--text);
+ opacity: 0.85;
+}
+
+.workspace {
+ flex: 1;
+ min-height: 0;
+ display: grid;
+ grid-template-columns: 1fr 1fr 340px;
+ gap: 12px;
+ padding: 12px;
+}
+
+.workspace.no-side {
+ grid-template-columns: 1fr 1fr;
+}
+
+.panel {
+ min-width: 0;
+ border: 1px solid var(--border);
+ border-radius: var(--radius-xl);
+ background: var(--surface);
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.35);
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.panel-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 10px 12px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
+ background: rgba(0, 0, 0, 0.2);
+}
+
+.panel-title {
+ font-weight: 650;
+ font-size: 0.86rem;
+ letter-spacing: 0.01em;
+}
+
+.editor-wrap {
+ flex: 1;
+ min-height: 0;
+ display: flex;
+}
+
+#md-input {
+ font-family:
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
+ "Courier New", monospace;
+ font-size: 14px;
+ line-height: 20px;
+ padding: 12px;
+ flex: 1;
+ width: 100%;
+ height: 100%;
+}
+
+#md-input {
+ border: none;
+ outline: none;
+ resize: none;
+ overflow: auto;
+ background: transparent;
+ white-space: pre-wrap;
+ line-height: 1.5;
+ color: var(--text-main);
+}
+
+#preview {
+ flex: 1;
+ width: 100%;
+ min-height: 0;
+ border: none;
+ background: #ffffff;
+}
+
+.side {
+ min-width: 0;
+ border: 1px solid var(--border);
+ border-radius: var(--radius-xl);
+ background: rgba(255, 255, 255, 0.04);
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.side-hidden {
+ display: none;
+}
+
+.side-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 10px 12px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
+ background: rgba(0, 0, 0, 0.2);
+}
+
+.side-title {
+ font-weight: 650;
+ font-size: 0.86rem;
+}
+
+.icon-btn {
+ border: 1px solid rgba(255, 255, 255, 0.12);
+ background: rgba(255, 255, 255, 0.04);
+ color: var(--text);
+ border-radius: 10px;
+ padding: 6px 8px;
+ cursor: pointer;
+}
+
+.icon-btn:hover {
+ background: rgba(255, 255, 255, 0.07);
+}
+
+.side-body {
+ padding: 10px 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ color: var(--muted);
+ font-size: 0.84rem;
+}
+
+.accordion {
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ border-radius: var(--radius-lg);
+ background: rgba(0, 0, 0, 0.16);
+ padding: 8px 10px;
+}
+
+.accordion summary {
+ cursor: pointer;
+ color: rgba(255, 255, 255, 0.88);
+ font-weight: 600;
+}
+
+.steps,
+.bullets {
+ margin: 8px 0 0;
+ padding-left: 18px;
+}
+
+.kv {
+ display: grid;
+ grid-template-columns: 90px 1fr;
+ gap: 6px 10px;
+ margin-top: 8px;
+ font-size: 0.82rem;
+}
+
+.kv .k {
+ color: rgba(255, 255, 255, 0.55);
+}
+.kv .v {
+ color: rgba(255, 255, 255, 0.88);
+ font-family: ui-monospace, monospace;
+ font-size: 0.8rem;
+}
+
+.side-footer {
+ margin-top: 6px;
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+}
+
+.link {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ text-decoration: none;
+ color: rgba(255, 255, 255, 0.88);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ background: rgba(255, 255, 255, 0.04);
+ padding: 6px 10px;
+ border-radius: 999px;
+ font-size: 0.8rem;
+}
+
+.link:hover {
+ background: rgba(255, 255, 255, 0.07);
+}
+
+.statusbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 12px;
+ padding: 10px 14px;
+ border-top: 1px solid var(--border);
+ background: rgba(10, 14, 28, 0.72);
+ backdrop-filter: blur(10px);
+ font-size: 0.82rem;
+ color: var(--muted);
+}
+
+.status-left {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+}
+
+.dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 999px;
+ background: var(--ok);
+}
+
+.dot.busy {
+ background: var(--warn);
+ animation: pulse 1.1s ease-in-out infinite;
+}
+
+@keyframes pulse {
+ 0%,
+ 100% {
+ opacity: 0.55;
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+.status-right {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+@media (max-width: 1100px) {
+ .workspace {
+ grid-template-columns: 1fr;
+ }
+ .workspace.no-side {
+ grid-template-columns: 1fr;
+ }
+}
+
+@media (max-width: 640px) {
+ .toolbar {
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ }
+ .brand-subtitle {
+ display: none;
+ }
+}