alchi-book: update config

This commit is contained in:
milahu 2021-05-16 09:29:21 +02:00
parent dd387afb92
commit 7e3eccd3cc
5 changed files with 88 additions and 254 deletions

View file

@ -1,3 +1,5 @@
const fs = require('fs');
const staticConfig = {
// https://github.com/fpapado/eleventy-with-vite/pull/2
@ -14,7 +16,7 @@ const staticConfig = {
dir: {
input: "src",
output: "eleventy-output",
output: "build", // not consistent with "default NPM folder layout" where /build contains helper scripts for the build process
// relative to input https://github.com/11ty/eleventy/issues/232
includes: "_includes",
@ -51,6 +53,8 @@ const staticConfig = {
};
module.exports = function(eleventyConfig) {
// make staticConfig reusable outside of eleventy
@ -407,18 +411,40 @@ module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy({
// source paths are relative to the project root
// we must copy all files, so css includes can be resolved
"node_modules/@fontsource/noto-sans": "css/noto-sans",
"node_modules/@fontsource/noto-mono": "css/noto-mono",
// this would copy too many files
//"node_modules/@fontsource/noto-sans": "css/noto-sans",
//"node_modules/@fontsource/noto-mono": "css/noto-mono",
// copy only needed files
// what files are needed? see output of: npm run dev
"node_modules/@fontsource/noto-sans/latin.css": "css/noto-sans/latin.css",
"node_modules/@fontsource/noto-sans/latin-700.css": "css/noto-sans/latin-700.css", // bold font
"node_modules/@fontsource/noto-sans/files/noto-sans-latin-400-normal.woff2": "css/noto-sans/files/noto-sans-latin-400-normal.woff2",
"node_modules/@fontsource/noto-mono/latin.css": "css/noto-mono/latin.css",
}, { expand: true });
eleventyConfig.addPassthroughCopy({
// source paths are relative to the project root
// we must copy all files, so css includes can be resolved
"src/images": "images",
// this would copy too many files
//"src/images": "images",
// svg images are inlined in the build process
// raster images (jpg, png, gif) could also be inlined as base64 data urls ...
// but for now, we keep them as external files
// we only need to inline svg files to fix svg viewports
// that would be broken with <img src="img/file.svg">
// TODO: make the svg files better accessible in the web interface
// -> click to zoom
// -> allow to share only the svg image: add public URL to https://milahu.github.io/alchi/src/alchi-book/images/...
// copy only needed files
// what files are needed? see output of: npm run dev
"src/images/should-vs-is.disgust-fight.disgusto-pelea.more-contrast.turc-orange.gif": "images/should-vs-is.disgust-fight.disgusto-pelea.more-contrast.turc-orange.gif",
"src/images/milahu-orange.jpg": "images/milahu-orange.jpg",
}, { expand: true });
/* Markdown Overrides */
let markdownLibrary = markdownIt({
html: true,
@ -554,8 +580,11 @@ class JsBundle {
if (this.staticConfig.isProduction) {
return [
this.moduleTag(file),
this.scriptTag("vite/legacy-polyfills"),
this.scriptTag(file.replace(/\.js$/, '-legacy.js'))
// TODO only needed with @vitejs/plugin-legacy -> auto detect?
//this.scriptTag("vite/legacy-polyfills"),
//this.scriptTag(file.replace(/\.js$/, '-legacy.js'))
].join('\n');
} else {
return [

View file

@ -76,19 +76,27 @@ and nonstandard keywords inspired by npm's package.json data format
<a class="close" onclick="closeModal('printing')">X</a>
<p class="title">Print Settings</p>
<div class="content">
<span>
<p>
1. paper format = DIN A4 landscape<br>
2. disable margins, scale to 100%<br>
3. duplex on, with flip on short edge<br>
<br>
</p>
<p>
if you want to print to a different paper format,
or if you need to calibrate the page sizes and offsets,
see the javascipt source code and change the variables:
see the javascipt source code in <code>alchi-book/src/js/main.js</code>
and change the variables:
page_x, page_y, page_margin, font_size<br>
<br>
</p>
<p>
"audit mode" will add space for manual annotations.
(should be printed with "linear" layout).
</span>
</p>
<p>
Print with manual duplex (can be faster than auto duplex):
1. print even pages in forward direction.
2. print odd pages in reverse direction.
</p>
</div>
</div>
</div>

View file

@ -74,15 +74,15 @@ body {
}
#book-title {
font-size: 12mm;
line-height: 12mm;
font-size: 14mm;
line-height: 100%;
height: auto;
text-align: center;
}
#book-subtitle {
font-size: 6mm;
line-height: 6mm;
font-size: 8mm;
line-height: 100%;
height: auto;
text-align: center;
margin-bottom: 4mm;
@ -177,6 +177,8 @@ a {
position: sticky;
top: 0; left: 0; right: 0;
background-color: white;
font-size: 110%;
}
button {
@ -406,6 +408,16 @@ del {
text-decoration: none;
}
/* fiduswriter ModTrack */
span.approved-insertion {
background-color: rgba(0, 255, 0, 0.5);
}
span.approved-deletion {
background-color: rgba(255, 0, 0, 0.5);
}
pre.map16 span.color-1 { color: var(--text1); }
pre.map16 span.color-2 { color: var(--text2); }
pre.map16 span.color-3 { color: var(--text3); }

View file

@ -1,8 +1,5 @@
// TODO split into smaller files
import * as htmldiff from 'htmldiff';
import * as Diff from 'diff';
function get_meta() {
@ -639,17 +636,6 @@ function add_language_menu() {
}
});
/* this would interfere with the text editor
document.addEventListener('keydown', event => {
if (event.key == 'l') {
event.preventDefault();
const sign = +1;
const next_lang = lang_list[(lang_list.indexOf(current_lang) + sign) % lang_list.length];
set_language(next_lang);
}
});
*/
}
@ -972,190 +958,6 @@ class Cursor {
// text editor
const debugTextEditor = false;
const debugTextEditor2 = false;
const lastDiffMap = new Map();
const editHistoryMap = new Map();
let ignoreNextInput = false;
let lastInputWasUndo = false;
function addTextEditor() {
document.querySelectorAll('span[lang]').forEach(editable => {
// FIXME? we use 'display: hidden' to hide unused languages
if (editable.style.display == 'none') return;
//editable.style.display = 'inline-block'; // fix chrome bug https://stackoverflow.com/a/62700928/10440128
// problem: 'display: inline-block' breaks float
editable.setAttribute('data-start-html', editable.innerHTML);
editable.setAttribute('contenteditable', 'true');
const editHistory = [];
editHistoryMap.set(editable, editHistory);
// TODO add input handler only on demand -> editable.onclick
editable.onkeydown = function(keyboardEvent) {
if (debugTextEditor) console.dir(keyboardEvent);
const editable = keyboardEvent.target;
if (keyboardEvent.ctrlKey && keyboardEvent.key == 'z') { // ctrl + z
const editHistory = editHistoryMap.get(editable);
if (debugTextEditor) console.log('undo edit on', editable, editHistory.slice());
ignoreNextInput = true;
if (!lastInputWasUndo) editHistory.pop(); // fix "off by one" bug
lastInputWasUndo = true;
if (editHistory && editHistory.length > 0) {
const { diffHtml, cursor } = editHistory.pop();
editable.innerHTML = diffHtml;
Cursor.setCurrentCursorPosition(cursor, editable);
editable.focus();
}
else {
editable.innerHTML = editable.getAttribute('data-start-html');
}
}
}
editable.oninput = function(inputEvent) {
// TODO use InputEvent and cursor
// always better than a diff algo
// diff algos will always produce false diffs ...
// https://developer.mozilla.org/en-US/docs/Web/API/InputEvent
const inputEventRelevant = {
data: inputEvent.data,
dataTransfer: inputEvent.dataTransfer,
inputType: inputEvent.inputType,
// deleteContentBackward
// deleteByCut
// insertText: insert or replace
// insertFromPaste
// historyUndo = ctrl + z (todo move handler)
// historyRedo = ctrl + y (also without handler)
isComposing: inputEvent.isComposing,
};
console.log('inputEventRelevant = ' + JSON.stringify(inputEventRelevant));
if (ignoreNextInput) {
ignoreNextInput = false;
if (debugTextEditor) console.log(`ignore input`);
return;
}
lastInputWasUndo = false;
if (debugTextEditor) console.dir(inputEvent);
const editable = inputEvent.target;
// save cursor position
let cursor = Cursor.getCurrentCursorPosition(editable);
// NOTE cursor includes html whitespace
if (debugTextEditor) console.log(`----`)
if (debugTextEditor) console.log(`cursor = ${cursor}`)
if (debugTextEditor && debugTextEditor2) document.querySelector('textarea[title="diff html"]').innerText = editable.innerHTML.replace(/\n/g, '\\n').replace(/ /g, '·');
// https://stackoverflow.com/a/23030157/10440128
function getText(node) {
if (node.nodeType == 3) return node.data; // text node
if (!node.childNodes) return '';
let s = '';
for (let i = 0; i < node.childNodes.length; i++) {
s += getText(node.childNodes[i]);
}
return s;
}
// FIXME inserting into a <del> should be a noop
// currently this will move the cursor to the next white-or-green and then start inserting
if (debugTextEditor && debugTextEditor2) {
// FIXME '&nbsp;' is printed as ' '
// no effect: .replace(/&/g, '&amp;')
document.querySelector('textarea[title="diff text"]').innerText = (
getText(editable).slice(0, cursor) + '[cursor]' + getText(editable).slice(cursor)
).replace(/\n/g, '\\n').replace(/ /g, '·');
}
// diff -> after
editable.querySelectorAll('ins').forEach(ins => (ins.outerHTML = ins.innerHTML));
editable.querySelectorAll('del').forEach(del => del.remove());
const htmlA = editable.getAttribute('data-start-html');
const htmlB = editable.innerHTML;
if (debugTextEditor && debugTextEditor2) {
document.querySelector('textarea[title="a"]').innerText = htmlA.replace(/\n/g, '\\n').replace(/ /g, '·');
document.querySelector('textarea[title="b"]').innerText = htmlB.replace(/\n/g, '\\n').replace(/ /g, '·');
}
const tokensA = htmldiff.htmlToTokens(htmlA);
const tokensB = htmldiff.htmlToTokens(htmlB);
const diffOps = htmldiff.calculateOperations(tokensA, tokensB);
const diffHtml = htmldiff.renderOperations(tokensA, tokensB, diffOps);
// get unidiff - quick n dirty
const diffUnified = Diff.createTwoFilesPatch('a/file.html', 'b/file.html', htmlA, htmlB)
.replace(/^===================================================================\n/s, '');
if (debugTextEditor) {
document.querySelector('textarea[title="diff -u"]').innerHTML = diffUnified; // .replace(/\n/g, '<br>\n').replace(/ /g, '·');
console.log(`diffUnified:\n${diffUnified}`)
}
//if (debugTextEditor) console.log('diffOps', { diffOps, tokensA, tokensB });
const lastDiff = lastDiffMap.get(editable);
lastDiffMap.set(editable, { tokensA, tokensB, diffOps });
function getDelsLen(ops, cursor) {
return (ops
.filter(o => (o.action[0] == 'r' || o.action[0] == 'd'))
.map(o => ({
posA1: tokensA[o.startInBefore].pos,
posA2: tokensA[o.endInBefore].pos + tokensA[o.endInBefore].str.length,
}))
.filter(o => (o.posA1 <= cursor))
.map(o => (o.posA2 - o.posA1))
.reduce((acc, val) => (acc + val), 0)
);
}
const cursorOffset = getDelsLen(diffOps, cursor) - (lastDiff ? getDelsLen(lastDiff.diffOps, cursor) : 0);
if (debugTextEditor) {
console.log(`getDelsLen: ${getDelsLen(diffOps, cursor)}, last getDelsLen: ${(lastDiff ? getDelsLen(lastDiff.diffOps, cursor) : 0)}`)
console.dir({ diffOps, tokensA, tokensB });
console.log(`tok a: |${tokensA.map(t => t.str).join('|').replace(/\n/g, '\\n')}|`)
console.log(`tok b: |${tokensB.map(t => t.str).join('|').replace(/\n/g, '\\n')}|`)
console.log(`ops:${diffOps.map(o => `\n * ${o.action} ${o.startInBefore}-${o.endInBefore} |${tokensA.slice(o.startInBefore, 1+o.endInBefore).map(t => t.str).join('|').replace(/\n/g, '\\n')}| -> ${o.startInAfter}-${o.endInAfter} |${tokensB.slice(o.startInAfter, 1+o.endInAfter).map(t => t.str).join('|').replace(/\n/g, '\\n')}|`).join('')}`)
console.log(`cursorOffset: ${cursorOffset}, cursor: ${cursor} -> ${cursor + cursorOffset}`);
}
cursor += cursorOffset;
// FIXME if cursor is too lage, we lose focus on the editable
editHistoryMap.get(editable).push({ diffHtml, cursor })
editable.innerHTML = diffHtml;
Cursor.setCurrentCursorPosition(cursor, editable);
editable.focus();
};
});
}
document.body.onload = function handle_body_loaded() {
console.log('body loaded');
@ -1170,26 +972,6 @@ document.body.onload = function handle_body_loaded() {
set_language(userLang); // must run after add_layout_menu
add_footers();
@ -1497,22 +1279,4 @@ document.body.onload = function handle_body_loaded() {
new MutationObserver(handleMutation).observe(head, { childList: true });
})();
/*
(new MutationObserver(() => document.body.classList.toggle('dark-reader',
document.querySelector('style#dark-reader-style') != null
)).observe(document.querySelector('head'), { childList: true }));
*/
/*
https://gitter.im/tinymce/tinymce?at=5a8f4dd10202dc012e70e7c7
Mike Botsko @viveleroi Feb 23 2018 00:10
is there a plugin that shows a "live" diff? For example if a user deletes a word, that word remains visually with a strike-through style, but the resulting textarea value is purely the final result of their edits?
if not, is that even remotely possible with the API?
*/
addTextEditor(); // must run after set_language
} // handle_body_loaded

View file

@ -1,3 +1,5 @@
// TODO move to config folder
import { defineConfig } from "vite";
import legacy from "@vitejs/plugin-legacy";
@ -16,6 +18,20 @@ const rollupOptions = {
input: Object.fromEntries(bundlerEntryFiles.map(entryFile => (
[assetPath(entryFile), (bundlerEntryDir + entryFile)]
))),
plugins: [],
// disable "filenames with hash" for assets
// so we can commit the "build" folder
// and dont have to delete/rename the old build files
// https://github.com/vitejs/vite/issues/378#issuecomment-768816653
// TODO maybe enable in development mode?
output: {
entryFileNames: `assets/[name].js`,
chunkFileNames: `assets/[name].js`,
assetFileNames: `assets/[name].[ext]`
},
};
// debug
Object.entries(rollupOptions.input).forEach(([key, path]) => {
@ -25,10 +41,15 @@ console.log(`build.outDir: ${eleventyDirOutput}`);
// https://vitejs.dev/config/
export default defineConfig({
// This is not critical, but I include it because there are more HTML transforms via plugins, that templates must handle
// TODO: For legacy() to work without a hitch, we set a known @babel/standalone version in package.json
// Remove that once https://github.com/vitejs/vite/issues/2442 is fixed
plugins: [legacy()],
//plugins: [legacy()],
// disabled the legacy plugin cos it generates "filenames with hash" for asset files
// https://github.com/vitejs/vite/issues/378
// sync with: alchi-book/config/eleventy.config.js footTags(file) {
build: {
// This is important: Generate directly to _site and then assetsDir.
// You could opt to build in an intermediate directory,