Add conflict resolution diff UI and app branding
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
const notice = document.querySelector("[data-version-notice]");
|
||||
const reload = document.querySelector("[data-version-reload]");
|
||||
const offlineNotice = document.querySelector("[data-offline-notice]");
|
||||
const cachedNotice = document.querySelector("[data-cached-notice]");
|
||||
const documentShell = document.querySelector("[data-document-path][data-document-hash]");
|
||||
const browser = document.querySelector(".miller-browser");
|
||||
const isEditing = Boolean(document.querySelector("[data-editor-form]"));
|
||||
|
||||
// Auto-scroll miller browser to show the rightmost (active) column
|
||||
function scrollBrowserToRight() {
|
||||
@@ -23,6 +25,120 @@
|
||||
|
||||
scrollBrowserToRight();
|
||||
|
||||
function initColumnPreviewExpansion() {
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hoverTimer = null;
|
||||
let expandedColumn = null;
|
||||
|
||||
function isCompressedColumn(column) {
|
||||
return (
|
||||
column &&
|
||||
column.matches(".miller-column:not(:first-child):not(:last-child)")
|
||||
);
|
||||
}
|
||||
|
||||
function collapseColumn(column) {
|
||||
if (!column) return;
|
||||
column.classList.remove("is-preview-expanded");
|
||||
column.style.removeProperty("--expanded-column-width");
|
||||
if (expandedColumn === column) {
|
||||
expandedColumn = null;
|
||||
}
|
||||
}
|
||||
|
||||
function expandColumn(column) {
|
||||
if (!isCompressedColumn(column)) return;
|
||||
if (expandedColumn && expandedColumn !== column) {
|
||||
collapseColumn(expandedColumn);
|
||||
}
|
||||
|
||||
const expandedWidth = Math.min(Math.max(column.scrollWidth + 12, 192), 384);
|
||||
column.style.setProperty("--expanded-column-width", expandedWidth + "px");
|
||||
column.classList.add("is-preview-expanded");
|
||||
expandedColumn = column;
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
const leftEdge = column.offsetLeft;
|
||||
const rightEdge = leftEdge + expandedWidth;
|
||||
let targetLeft = browser.scrollLeft;
|
||||
|
||||
if (leftEdge < browser.scrollLeft) {
|
||||
targetLeft = leftEdge - 8;
|
||||
} else if (rightEdge > browser.scrollLeft + browser.clientWidth) {
|
||||
targetLeft = rightEdge - browser.clientWidth + 8;
|
||||
}
|
||||
|
||||
browser.scrollTo({
|
||||
left: Math.max(0, targetLeft),
|
||||
behavior: "smooth",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function scheduleExpansion(column) {
|
||||
if (!isCompressedColumn(column)) return;
|
||||
clearTimeout(hoverTimer);
|
||||
hoverTimer = setTimeout(function () {
|
||||
expandColumn(column);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
browser.querySelectorAll(".miller-column").forEach(function (column) {
|
||||
column.addEventListener("pointerenter", function () {
|
||||
scheduleExpansion(column);
|
||||
});
|
||||
|
||||
column.addEventListener("mouseenter", function () {
|
||||
scheduleExpansion(column);
|
||||
});
|
||||
|
||||
column.addEventListener("mouseover", function () {
|
||||
if (!isCompressedColumn(column)) return;
|
||||
if (expandedColumn === column) return;
|
||||
scheduleExpansion(column);
|
||||
});
|
||||
|
||||
column.addEventListener("pointerleave", function () {
|
||||
clearTimeout(hoverTimer);
|
||||
collapseColumn(column);
|
||||
});
|
||||
|
||||
column.addEventListener("mouseleave", function () {
|
||||
clearTimeout(hoverTimer);
|
||||
collapseColumn(column);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
initColumnPreviewExpansion();
|
||||
|
||||
function updateCachedUI(isCached) {
|
||||
if (!cachedNotice) return;
|
||||
cachedNotice.hidden = !isCached;
|
||||
}
|
||||
|
||||
function cacheCurrentPage() {
|
||||
if (!window.MDHubCache) return;
|
||||
|
||||
const html = document.documentElement.outerHTML;
|
||||
const title = document.title;
|
||||
const pagePath = window.MDHubCache.normalizePath(window.location.pathname);
|
||||
window.MDHubCache.cachePage(pagePath, html, title).catch(function () {});
|
||||
}
|
||||
|
||||
function registerServiceWorker() {
|
||||
if (!("serviceWorker" in navigator)) return;
|
||||
window.addEventListener("load", function () {
|
||||
navigator.serviceWorker.register("/sw.js").catch(function () {});
|
||||
});
|
||||
}
|
||||
|
||||
registerServiceWorker();
|
||||
updateCachedUI(Boolean(window.__MDHUB_OFFLINE_CACHED__));
|
||||
|
||||
function updateOfflineUI() {
|
||||
if (!offlineNotice) return;
|
||||
if (navigator.onLine) {
|
||||
@@ -54,6 +170,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
cacheCurrentPage();
|
||||
|
||||
// Fetch and cache documents
|
||||
function fetchAndCacheDocuments() {
|
||||
if (!window.MDHubCache) return;
|
||||
@@ -130,6 +248,9 @@
|
||||
const bodyEl = documentShell.querySelector(".markdown-body");
|
||||
if (bodyEl) bodyEl.innerHTML = html;
|
||||
|
||||
updateCachedUI(true);
|
||||
cacheCurrentPage();
|
||||
|
||||
// Re-render math and mermaid
|
||||
if (typeof renderMath === "function") renderMath();
|
||||
if (typeof renderMermaid === "function") renderMermaid();
|
||||
@@ -185,6 +306,10 @@
|
||||
|
||||
const change = payload.data;
|
||||
|
||||
if (isEditing && currentPath && change.path === currentPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPath && change.path === currentPath && change.hash !== currentHash) {
|
||||
if (notice) notice.hidden = false;
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user