Support overflowing tables in default styles
This commit is contained in:
parent
51b3633077
commit
5dfb004a59
6 changed files with 90 additions and 29 deletions
5
bun.lock
5
bun.lock
|
@ -6,6 +6,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@endeavorance/emdy": "^1.0.0",
|
"@endeavorance/emdy": "^1.0.0",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
"rehype-callouts": "^2.1.0",
|
"rehype-callouts": "^2.1.0",
|
||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"rehype-slug": "^6.0.0",
|
"rehype-slug": "^6.0.0",
|
||||||
|
@ -72,6 +73,8 @@
|
||||||
|
|
||||||
"character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
|
"character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
|
||||||
|
|
||||||
|
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||||
|
|
||||||
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
|
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
|
||||||
|
|
||||||
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||||
|
@ -206,6 +209,8 @@
|
||||||
|
|
||||||
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
||||||
|
|
||||||
|
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||||
|
|
||||||
"rehype-callouts": ["rehype-callouts@2.1.0", "", { "dependencies": { "@types/hast": "^3.0.4", "hast-util-from-html": "^2.0.3", "hast-util-is-element": "^3.0.0", "hastscript": "^9.0.1", "unist-util-visit": "^5.0.0" } }, "sha512-Als/wlYpXg2Rs0p/yofrkSH6IQzn1xh6cvBC5BHy5JVT3lGlzUvVT8wOyVqCEgf8Eun6cQ3f47rLLoaiyLkP0w=="],
|
"rehype-callouts": ["rehype-callouts@2.1.0", "", { "dependencies": { "@types/hast": "^3.0.4", "hast-util-from-html": "^2.0.3", "hast-util-is-element": "^3.0.0", "hastscript": "^9.0.1", "unist-util-visit": "^5.0.0" } }, "sha512-Als/wlYpXg2Rs0p/yofrkSH6IQzn1xh6cvBC5BHy5JVT3lGlzUvVT8wOyVqCEgf8Eun6cQ3f47rLLoaiyLkP0w=="],
|
||||||
|
|
||||||
"rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="],
|
"rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="],
|
||||||
|
|
|
@ -17,3 +17,7 @@ How about a callout?
|
||||||
|
|
||||||
> [!warning]- This is collapsible
|
> [!warning]- This is collapsible
|
||||||
> And how!
|
> And how!
|
||||||
|
|
||||||
|
## A subheading
|
||||||
|
|
||||||
|
This is a section!
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Home | Demo
|
title: Home | Demo
|
||||||
|
and: how
|
||||||
---
|
---
|
||||||
|
|
||||||
# Demo Data
|
# Demo Data
|
||||||
|
@ -33,3 +34,8 @@ Tables should be a thing too
|
||||||
- Need numbers
|
- Need numbers
|
||||||
|
|
||||||
<span style="font-size: 0.5rem">HTML works, still!</span>
|
<span style="font-size: 0.5rem">HTML works, still!</span>
|
||||||
|
|
||||||
|
|
||||||
|
| hello | world | hello | world | hello | world | hello | world | hello | world | hello |
|
||||||
|
| ------------------------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- |
|
||||||
|
| dfjhasfdlkjahslfkjahsdlfjhasldjhasldjhasldk | | | | | | | | | | |
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@endeavorance/emdy": "^1.0.0",
|
"@endeavorance/emdy": "^1.0.0",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
"rehype-callouts": "^2.1.0",
|
"rehype-callouts": "^2.1.0",
|
||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"rehype-slug": "^6.0.0",
|
"rehype-slug": "^6.0.0",
|
||||||
|
|
|
@ -92,16 +92,19 @@ a {
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
display: block;
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
margin: 1em 0;
|
|
||||||
font-size: 1em;
|
|
||||||
background-color: var(--color-bg);
|
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
width: 100%;
|
||||||
|
max-width: -moz-fit-content;
|
||||||
|
max-width: fit-content;
|
||||||
|
overflow-x: auto;
|
||||||
|
font-size: 1em;
|
||||||
border: 1px solid var(--color-text);
|
border: 1px solid var(--color-text);
|
||||||
|
margin: 0 auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
th,
|
th,
|
||||||
td {
|
td {
|
||||||
padding: 0.5em 0.5em;
|
padding: 0.5em 0.5em;
|
||||||
|
|
86
src/index.ts
86
src/index.ts
|
@ -1,7 +1,7 @@
|
||||||
import Path from "node:path";
|
import Path from "node:path";
|
||||||
import { parseArgs } from "node:util";
|
import { parseArgs } from "node:util";
|
||||||
import EMDY from "@endeavorance/emdy";
|
import EMDY from "@endeavorance/emdy";
|
||||||
import type { BunFile } from "bun";
|
import { Glob, type BunFile } from "bun";
|
||||||
import DEFAULT_STYLESHEET from "./defaults/default-style.css" with {
|
import DEFAULT_STYLESHEET from "./defaults/default-style.css" with {
|
||||||
type: "text",
|
type: "text",
|
||||||
};
|
};
|
||||||
|
@ -10,10 +10,17 @@ import DEFAULT_TEMPLATE from "./defaults/default-template.html" with {
|
||||||
};
|
};
|
||||||
import { CLIError } from "./error";
|
import { CLIError } from "./error";
|
||||||
import { parseMarkdown } from "./markdown";
|
import { parseMarkdown } from "./markdown";
|
||||||
|
import { watch } from "node:fs/promises";
|
||||||
|
|
||||||
const DEFAULT_TEMPLATE_FILE = "_template.html";
|
const DEFAULT_TEMPLATE_FILE = "_template.html";
|
||||||
const DEFAULT_STYLESHEET_FILE = "_style.css";
|
const DEFAULT_STYLESHEET_FILE = "_style.css";
|
||||||
|
|
||||||
|
async function isDirectory(path: string): Promise<boolean> {
|
||||||
|
const file = Bun.file(path);
|
||||||
|
const stat = await file.stat();
|
||||||
|
return stat.isDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a file path, attempt to read the text of the file
|
* Given a file path, attempt to read the text of the file
|
||||||
* @param filePath - The path to the file to read
|
* @param filePath - The path to the file to read
|
||||||
|
@ -66,6 +73,9 @@ interface CLIOptions {
|
||||||
/** The path to the stylesheet file */
|
/** The path to the stylesheet file */
|
||||||
stylesheetFilePath: string | null;
|
stylesheetFilePath: string | null;
|
||||||
|
|
||||||
|
/** If the default stylesheet should be included regardless of the provided stylesheet */
|
||||||
|
includeDefaultStylesheet: boolean;
|
||||||
|
|
||||||
/** If true, show help message */
|
/** If true, show help message */
|
||||||
help: boolean;
|
help: boolean;
|
||||||
|
|
||||||
|
@ -107,6 +117,10 @@ function parseCLIArgs(): { options: CLIOptions; args: string[] } {
|
||||||
type: "string",
|
type: "string",
|
||||||
short: "s",
|
short: "s",
|
||||||
},
|
},
|
||||||
|
"include-default-stylesheet": {
|
||||||
|
type: "boolean",
|
||||||
|
short: "S",
|
||||||
|
},
|
||||||
cwd: {
|
cwd: {
|
||||||
type: "string",
|
type: "string",
|
||||||
default: process.cwd(),
|
default: process.cwd(),
|
||||||
|
@ -119,12 +133,14 @@ function parseCLIArgs(): { options: CLIOptions; args: string[] } {
|
||||||
allowPositionals: true,
|
allowPositionals: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Validation
|
// == Argument Validation ==
|
||||||
|
|
||||||
if (positionals.length > 1 && flags.outfile) {
|
// Outfile requires only one argument
|
||||||
|
if (flags.outfile && positionals.length > 1) {
|
||||||
throw new CLIError("--outfile cannot be used with multiple inputs.");
|
throw new CLIError("--outfile cannot be used with multiple inputs.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Outfile and Outdir cannot be used together
|
||||||
if (flags.outdir && flags.outfile) {
|
if (flags.outdir && flags.outfile) {
|
||||||
throw new CLIError("--outdir and --outfile cannot be used together.");
|
throw new CLIError("--outdir and --outfile cannot be used together.");
|
||||||
}
|
}
|
||||||
|
@ -137,6 +153,7 @@ function parseCLIArgs(): { options: CLIOptions; args: string[] } {
|
||||||
stdout: flags.stdout ?? false,
|
stdout: flags.stdout ?? false,
|
||||||
templateFilePath: flags.template ?? null,
|
templateFilePath: flags.template ?? null,
|
||||||
stylesheetFilePath: flags.stylesheet ?? null,
|
stylesheetFilePath: flags.stylesheet ?? null,
|
||||||
|
includeDefaultStylesheet: flags["include-default-stylesheet"] ?? false,
|
||||||
help: flags.help ?? false,
|
help: flags.help ?? false,
|
||||||
title: flags.title ?? null,
|
title: flags.title ?? null,
|
||||||
},
|
},
|
||||||
|
@ -171,8 +188,11 @@ async function loadTemplate(options: CLIOptions): Promise<string> {
|
||||||
* @returns The stylesheet string
|
* @returns The stylesheet string
|
||||||
*/
|
*/
|
||||||
async function loadStylesheet(options: CLIOptions): Promise<string> {
|
async function loadStylesheet(options: CLIOptions): Promise<string> {
|
||||||
|
const preamble = options.includeDefaultStylesheet ? DEFAULT_STYLESHEET : "";
|
||||||
|
|
||||||
if (options.stylesheetFilePath) {
|
if (options.stylesheetFilePath) {
|
||||||
return readFile(options.stylesheetFilePath);
|
const loadedSheet = await readFile(options.stylesheetFilePath);
|
||||||
|
return [preamble, loadedSheet].join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkStylesheetFile = Bun.file(
|
const checkStylesheetFile = Bun.file(
|
||||||
|
@ -180,7 +200,8 @@ async function loadStylesheet(options: CLIOptions): Promise<string> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (await checkStylesheetFile.exists()) {
|
if (await checkStylesheetFile.exists()) {
|
||||||
return checkStylesheetFile.text();
|
const loadedSheet = await checkStylesheetFile.text();
|
||||||
|
return [preamble, loadedSheet].join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return DEFAULT_STYLESHEET;
|
return DEFAULT_STYLESHEET;
|
||||||
|
@ -263,6 +284,27 @@ async function getOutputFile(
|
||||||
return Bun.file(outputPath);
|
return Bun.file(outputPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function processStdin(options: CLIOptions): Promise<void> {
|
||||||
|
const outfile = options.outfile ? Bun.file(options.outfile) : Bun.stdout;
|
||||||
|
return buildFile(Bun.stdin, outfile, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processFile(
|
||||||
|
options: CLIOptions,
|
||||||
|
filePath: string,
|
||||||
|
): Promise<void> {
|
||||||
|
console.log(`Building ${filePath}...`);
|
||||||
|
const file = Bun.file(filePath);
|
||||||
|
|
||||||
|
// Ensure input files exist
|
||||||
|
if (!(await file.exists())) {
|
||||||
|
throw new CLIError(`File ${filePath} does not exist.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const outfile = await getOutputFile(filePath, options);
|
||||||
|
await buildFile(file, outfile, options);
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const { options, args } = parseCLIArgs();
|
const { options, args } = parseCLIArgs();
|
||||||
|
|
||||||
|
@ -277,13 +319,14 @@ Usage:
|
||||||
echo "some markdown" | buildmd
|
echo "some markdown" | buildmd
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--outfile, -o <file> Output path
|
--outfile, -o <file> Output path
|
||||||
--outdir, -d <dir> Output directory
|
--outdir, -d <dir> Output directory
|
||||||
--stdout Force output to stdout
|
--stdout Force output to stdout
|
||||||
--template, -t <file> Template path (default: _template.html)
|
--template, -t <file> Template path (default: _template.html)
|
||||||
--stylesheet, -s <file> Stylesheet path (default: _style.css)
|
--stylesheet, -s <file> Stylesheet path (default: _style.css)
|
||||||
--title, -T <string> Document title override
|
--include-default-stylesheet, -S Extend default CSS instead of overwriting
|
||||||
--help, -h Show this help message
|
--title, -T <string> Document title override
|
||||||
|
--help, -h Show this help message
|
||||||
`.trim(),
|
`.trim(),
|
||||||
);
|
);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
@ -291,22 +334,21 @@ Options:
|
||||||
|
|
||||||
// stdin mode
|
// stdin mode
|
||||||
if (args.length === 0) {
|
if (args.length === 0) {
|
||||||
const outfile = options.outfile ? Bun.file(options.outfile) : Bun.stdout;
|
return processStdin(options);
|
||||||
await buildFile(Bun.stdin, outfile, options);
|
|
||||||
process.exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// file mode
|
// file mode
|
||||||
for (const arg of args) {
|
for (const arg of args) {
|
||||||
const file = Bun.file(arg);
|
const isDir = await isDirectory(arg);
|
||||||
|
|
||||||
// Ensure input files exist
|
if (isDir) {
|
||||||
if (!(await file.exists())) {
|
const dirGlob = new Glob(`${arg}/**/*.md`);
|
||||||
throw new CLIError(`File ${arg} does not exist.`);
|
for await (const file of dirGlob.scan()) {
|
||||||
|
await processFile(options, file);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await processFile(options, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const outfile = await getOutputFile(arg, options);
|
|
||||||
await buildFile(file, outfile, options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue