-
-
Save howyay/efda51d561fc57e395bd28539182dad1 to your computer and use it in GitHub Desktop.
Notion.so Custom Domain + Inline LaTeX Rendering
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const MY_DOMAIN = "YOUR_DOMAIN" | |
const START_PAGE = "URL_TO_NOTION_LANDING_PAGE" | |
addEventListener('fetch', event => { | |
event.respondWith(fetchAndApply(event.request)) | |
}) | |
const corsHeaders = { | |
"Access-Control-Allow-Origin": "*", | |
"Access-Control-Allow-Methods": "GET, HEAD, POST,PUT, OPTIONS", | |
"Access-Control-Allow-Headers": "Content-Type", | |
} | |
function handleOptions(request) { | |
if (request.headers.get("Origin") !== null && | |
request.headers.get("Access-Control-Request-Method") !== null && | |
request.headers.get("Access-Control-Request-Headers") !== null) { | |
// Handle CORS pre-flight request. | |
return new Response(null, { | |
headers: corsHeaders | |
}) | |
} else { | |
// Handle standard OPTIONS request. | |
return new Response(null, { | |
headers: { | |
"Allow": "GET, HEAD, POST, PUT, OPTIONS", | |
} | |
}) | |
} | |
} | |
async function fetchAndApply(request) { | |
if (request.method === "OPTIONS") { | |
return handleOptions(request) | |
} | |
let url = new URL(request.url) | |
let response | |
if (url.pathname.startsWith("/app") && url.pathname.endsWith("js")) { | |
// skip validation in app.js | |
response = await fetch(`https://www.notion.so${url.pathname}`) | |
let body = await response.text() | |
try { | |
response = new Response(body.replace(/www.notion.so/g, MY_DOMAIN).replace(/notion.so/g, MY_DOMAIN), response) | |
response.headers.set('Content-Type', "application/x-javascript") | |
console.log("get rewrite app.js") | |
} catch (err) { | |
console.log(err) | |
} | |
} else if ((url.pathname.startsWith("/api"))) { | |
// Forward API | |
response = await fetch(`https://www.notion.so${url.pathname}`, { | |
body: request.body, // must match 'Content-Type' header | |
headers: { | |
'content-type': 'application/json;charset=UTF-8', | |
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36' | |
}, | |
method: "POST", // *GET, POST, PUT, DELETE, etc. | |
}) | |
response = new Response(response.body, response) | |
response.headers.set('Access-Control-Allow-Origin', "*") | |
} else if (url.pathname === `/`) { | |
// 301 redrict | |
let pageUrlList = START_PAGE.split("/") | |
let redrictUrl = `https://${MY_DOMAIN}/${pageUrlList[pageUrlList.length - 1]}` | |
return Response.redirect(redrictUrl, 301) | |
} else { | |
response = await fetch(`https://www.notion.so${url.pathname}`, { | |
body: request.body, // must match 'Content-Type' header | |
headers: request.headers, | |
method: request.method, // *GET, POST, PUT, DELETE, etc. | |
}) | |
response = new Response(response.body, response) | |
} | |
response.headers.delete("Content-Security-Policy") | |
return new HTMLRewriter().on('body', new ElementHandler()).transform(response) | |
return response | |
} | |
class ElementHandler { | |
element(element) { | |
element.append(` | |
<script src=https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js></script> | |
<script src=https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js></script> | |
<script type="text/javascript"> | |
// right-padding for inline math mode | |
var style = document.createElement('style'); | |
style.innerHTML = '.katex{padding-right:0!important;}'; | |
document.head.appendChild(style); | |
// declare/init vars | |
let timer; // timer identifier | |
let startUpWaitTime = 3000; // ms after startup (adjust as needed) | |
let pageChangeWaitTime = 1500; // ms after page changed (adjust as needed) | |
let backupRender; | |
let backupRenderWaitTime = 6000; | |
// render inline LaTeX | |
function renderInlineLaTeX() { | |
renderMathInElement(document.body, { | |
delimiters: [ | |
// LaTeX delimiters (uncomment/add as needed) | |
{ left: "$$", right: "$$", display: true }, | |
// { left: "\\[", right: "\\]", display: true }, | |
// { left: "\\(", right: "\\)", display: false }, | |
{ left: "$", right: "$", display: false } | |
] | |
}); | |
console.log("Inline LaTeX is rendered."); | |
} | |
let url = window.location.href; | |
['click','popstate'].forEach( evt => | |
window.addEventListener(evt, function () { | |
requestAnimationFrame(()=>{ | |
if (url !== location.href) { | |
renderOnPageChange(); | |
} | |
url = location.href; | |
}); | |
}, true) | |
); | |
function renderOnLoad() { | |
console.log("Rendering inline LaTeX on startup..."); | |
clearTimeout(timer); | |
timer = setTimeout(renderInlineLaTeX, startUpWaitTime); | |
backupRendering(); | |
} | |
function renderOnPageChange() { | |
console.log("Rendering inline LaTeX on navigation..."); | |
clearTimeout(timer); | |
timer = setTimeout(renderInlineLaTeX, pageChangeWaitTime); | |
backupRendering(); | |
} | |
function backupRendering() { | |
clearTimeout(backupRender); | |
backupRender = setTimeout(function() { | |
console.log("Rerendering just in case..."); | |
renderInlineLaTeX(); | |
}, backupRenderWaitTime); | |
} | |
// on startup... | |
window.addEventListener("DOMContentLoaded", renderOnLoad); | |
</script> | |
`, { | |
html: true | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment