remarkableslides
Version:
Build Markdown files into slides using remark.js
144 lines (114 loc) • 4.72 kB
JavaScript
import express from 'express';
import path from 'path';
import livereload from 'livereload';
import connectLivereload from 'connect-livereload';
export function createServer(presentations, PORT = 1234) {
const app = express();
const liveReloadServer = livereload.createServer();
liveReloadServer.server.once("connection", () => {
setTimeout(() => {
liveReloadServer.refresh("/");
}, 100);
});
app.use(connectLivereload());
const endpoints = [];
presentations.forEach((presentation) => {
app.use(express.static(presentation.directoryPath));
const combinedTitle = presentation.filenames.map((filename) => filename.replace(".md", "")).join("_");
const endpoint = generateUniqueEndpoint(endpoints, combinedTitle);
endpoints.push(endpoint);
app.get(endpoint, (req, res) => {
const presentationFilePath = path.resolve(presentation.absolutePresentationPath);
res.sendFile(presentationFilePath);
});
});
app.get("/", (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
margin: 0 5vw;
padding: 0;
height: 100vh;
background-color: #1e1e1e;
color: #ddd;
}
h1 {
font-size: 2rem;
color: rgb(8, 107, 194);
text-align: center;
margin-bottom: 1rem;
text-shadow: 1px 1px 2px #000;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
margin: 2rem 0;
}
a {
text-decoration: none;
color: green;
font-weight: bold;
transition: color 0.3s ease;
font-size: 1.5rem;
}
a:hover {
color: #00ff00;
}
</style>
<title>Remarkable Slides</title>
</head>
<body>
<h1>Presentations</h1>
<ul>
${endpoints.map((endpoint) => {
return `<li><a href="${endpoint}">${endpoint}</a></li>`
}).join('')}
</ul>
</body>
</html>
`);
});
app.get("*", (req, res) => {
// if (req.hostname === "localhost" && req.port === 35729) {
if (req.url.startsWith("/livereload")) {
return next();
}
res.redirect("/");
});
const server = app.listen(PORT, () => console.log("Server running on port", server.address().port));
function handleExit(options, exitCode) {
if (options.cleanup) {
server.close(() => {});
}
if (exitCode || exitCode === 0);
if (options.exit) process.exit();
}
// Do something when app is closing
process.on('exit', handleExit.bind(null, { cleanup: true }));
// Catches ctrl+c event
process.on('SIGINT', handleExit.bind(null, { exit: true }));
// Catches "kill pid" (for example: nodemon restart)
process.on('SIGUSR1', handleExit.bind(null, { exit: true }));
process.on('SIGUSR2', handleExit.bind(null, { exit: true }));
// Catches uncaught exceptions
process.on('uncaughtException', handleExit.bind(null, { exit: true }));
}
function generateUniqueEndpoint(endpoints, absolutePath) {
let filename = path.basename(absolutePath).replace('.html', '');
let endpoint = `/${filename}`;
// If the endpoint already exists, start adding parent directories until it becomes unique
if (endpoints.includes(endpoint)) {
const pathParts = absolutePath.split(path.sep).slice(0, -1); // Exclude the file name
while (pathParts.length > 0 && endpoints.includes(endpoint)) {
endpoint = `/${path.basename(pathParts.pop())}${endpoint}`;
}
}
return endpoint;
}