Git Product home page Git Product logo

markdown-folder-to-html's Introduction

markdown-folder-to-html

Simplest zero-config way to generate html docs from markdown files.

Copies docs to _docs and compiles markdown files to html using docs/template.html.

Live example at chimeces.com/markdown-folder-to-html

Usage

Requires node.js >= 6

Given we have some docs:

  1. mkdir -p docs
  2. Add some docs echo "**Banana**" > docs/banana.md
  3. Add some docs echo "**Apple**" > docs/index.md

In a project

  1. Install npm install -D markdown-folder-to-html
  2. Add docs to npm scripts {"scripts": {"docs": "markdown-folder-to-html"}}
  3. 🎉 npm run docs and open _docs/index.html

Globally

  1. Install npm install -g markdown-folder-to-html
  2. 🎉 markdown-folder-to-html and open _docs/index.html

Conventions

Input/Output folder

You can pass an argument to the cli to change the input folder (by default docs). That will change the output folder too to _FOLDERNAME (by default _docs).

markdown-folder-to-html documentation
# Outputs site to _documentation

If you want to change the output folder name, just mv it to something else.

Custom HTML

The default HTML is extremely basic, but simple and pretty, and is the one used in the docs.

This is the basic template that would work:

<!doctype html>
<html>
<body>
<nav>
	<!--NAV-->
</nav>
<article>
	<!--CONTENT-->
</article>
</body>
</html>

Create your own in your docs folder docs/template.html to use that one instead. Feel free to include styles inline or CSS files (since all will be copied to output).

Order

You may have noticed that files are sorted alphabetically. There's a little trick where if you name your folders/files with XX-folder/XX-file (XX being a number of 1+ digits) those numbers won't show up on the index of the pages, giving you the ability to organize files both in the filesystem and in the generated HTML site.

Also, the root index.md file will always show up at the beginning of the index.

Site contents and information for custom templates

If you want to do things with a custom template HTML you need the information of the site. This will allow you to do things in the front-end UI, like adding search to the static site with lunrjs or other things like adding buttons for the next/previous article.

For this use cases, you will see a contents.json generated in your output folder. It contains the hierarchical paths of the files, and the contents with the original markup, the HTML, the original path and the transformed URL:

{
  "paths": [
    {
      "type": "file",
      "value": "index.md"
    },
    {
      "type": "file",
      "value": "1-banana.md"
    },
    {
      "type": "dir",
      "name": "a-folder",
      "children": [
        {
          "type": "file",
          "value": "a-folder/with-a-post.md"
        }
      ]
    }
    //...
  ],
  "contents": [
    {
      "path": "index.md",
      "url": "index.html",
      "content": "# markdown-folder-to-html\n\nSimplest zero-config ...",
      "html": "<h1>markdown-folder-to-html</h1>\n<p>Simplest zero-config ...",
      "id": 0
    },
    {
      "path": "1-banana.md",
      "url": "1-banana.html",
      "content": "**Banana**\n\nYou can have [nested folders](./n...",
      "html": "<p><strong>Banana</strong></p>\n<p>You can have <a h...",
      "id": 1
    }
    //...
  ]
}

See the JSON file of our documentation site for an example.

You can then fetch this JSON file with JS from your template, and go crazy with it, processing the contents to adapt them for search, looking for the previous/next articles to link to them, etc.

If you have working examples of a template that does something interesting, please let me know and I'll list them here!

Why

After quite a lot of research, I couldn't find a simple and straightforward solution to generating html docs from a folder full of markdown files that relied on simple concepts. That is what this tool does:

  • Simply copy everything over, and translate .md files to .html with a pure HTML layout (feel free to add CSS, or JS, or precompile those assets if you need to)
  • .md links are rewritten to .html so that you can reference files with their real path on your markdown files and they'll work on the HTML version too.
  • Provide sensible defaults and zero-configuration. JUST WORK.
  • Use know abstraction, like the file system, pure HTML, etc

Links

markdown-folder-to-html's People

Contributors

iamnathanj avatar joakin avatar qertis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

markdown-folder-to-html's Issues

Support for anchors in .md links

Thanks for this project, I found it today and really like its simplicity.

When linking to a .md file, can an anchor be included? It seems that [link](link.md#anchor) is converted to <a href="link.md#anchor">link</a> instead of <a href="link.html#anchor">link</a>

Add ability to resize images

It would be useful to resize images using standard markdown option:
Maybe something like this:
![sample image](image.png | width=100)
![sample image](image.png =250x250)

Make index generation per file more efficient

Given that we have to have the relative paths for each file for all files to generate the index, we are parsing all files and finding relative paths for every file that we need to generate an index.

Figure out a more efficient way to do this.

Add syntax highlighting easily

To enable syntax highlighting in very easy way, you can add to the template or to the documentation the following lines:

<script>
    (function() {
      var codeTags = document.querySelectorAll('code[class^="language-"]');
      for (var tag of codeTags) {
        tag.className = tag.className.replace("language-", "prettyprint lang-");
      }
    })();
  </script>
  <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>

Can't parse single quotes/apostrophes

When my markdown file has apostrophes, the generated HTML substitutes it with: ’

Example
Input:

* building's 
* sites

Output:

<ul>
    <li>building’s</li>
    <li>sites</li>
</ul>

Funny enough, it works fine in blockquotes:

```
hello's
```

Suggestion to have TOC sidebar with foldable items

Hi,
for very large projects it would be useful to have nested list items to be collapsible.
It will improve incredibly user experience.
Congratulations for your work, code works perfectly and is very very fast.
Bests,
Francesco

Add option to not use default slugify for markdown-it-anchor handling

Thanks for this great repo! We are currently using it to convert our markdown files (converted with https://www.npmjs.com/package/json-schema-to-markdown) of schema docs to html. We have a number of overview tables with schema properties in (sort of) camel case (fixed requirement), e.g. GlobalID, and underneath a list of all props with more information (e.g. type, maximum length, examples). In rendered markdown (e.g. in GitHub), when clicking on the property name in the table, it will scroll down to the more detailed description, which is super useful when having a large table of properties.

When converting to html here, markdown-it-anchor is used to handle these anchors which per default "slugifys" the anchor strings added to the URL (e.g. GlobalID --> globalid). Would it be possible to use an option as described in https://www.npmjs.com/package/markdown-it-anchor to overwrite the slugify default option also for markdown-folder-to-html?

const string = require('string');
const keepStringAsIs = s => string(s);
 
const md = require('markdown-it')()
const anchor = require('markdown-it-anchor', {
    slugify: keepStringAsIs,
});

I am happy to look into it and make a PR if this is something that could be useful for others as well. Thanks for the consideration.

Allow for spaces in image filenames

When working with Typora (my markdown editor) the following markdown code renders as expected:

![img/Untitled 19.png](img/Untitled 19.png)
![img/Untitled 20.png](img/Untitled 20.png)

However, after running markdown-folder-to-html on it, the images are not displayed:
image

I instead have to manually adjust the links like this:

![img/Untitled 19.png](img/Untitled%2019.png)
![img/Untitled 20.png](img/Untitled%2020.png)

to actually get the images to show up as expected.

This is a really annoying issue since it can't even be caught by parsing the page with a testing tool since there isn't actually a missing image in the HTML, the testing tool just sees the text and assumes that nothing is missing.

Improvements suggestion which enables creating whole project of documentation

Changes:
Enable setting the output folder as second argument (first is the input folder).
Line 17: const [docsFolder, outputFolder, ...argsRest] = process.argv.slice(2);
Line 22: const output = (outputFolder) ? outputFolder : `_${folder}`;

When using current folder as source folder (Like: markdown-folder-to-html ./)' the output folder is _. and is located inside the current folder. It causes problem with the recursive copy (cp -R . ./).
The solution is to ignore the output directory. In my case it caused problem because of coping folder node_modules too. I do not want it in the project and it could not be renamed.
Solution line 52: sh.cp("-R", folder + `/!(node_modules|${output})`, output);

Source: (cli.ts)

#! /usr/bin/env node

import fs from "fs";
import path from "path";
import sh from "shelljs";

import groupByPath from "./lib/group-by-path";
import sortByPreferences from "./lib/sort-by-preferences";
import mdUrl from "./lib/markdown-url-to-html";
import md2html from "./lib/markdown-to-html";
import renderNav from "./lib/render-nav";
import generateIndexInfo from "./lib/generate-index-info";
import page from "./lib/render-page";
import mdR from "./lib/markdown-regex";
import { FileTree, StringFile } from "./lib/types";

const [docsFolder, outputFolder, ...argsRest] = process.argv.slice(2);

// Default parameters
const defaultFolder = "docs";
const folder = docsFolder || defaultFolder;
const output = (outputFolder) ? outputFolder : `_${folder}`;
const templateFilename = "template.html";
const contentsFilename = "contents.json";
const preferences = ["index.md", "README.md"];

// Guards
// Bail out if more than 1 args
if (argsRest && argsRest.length > 0) {
  console.error("Too may arguments");
  usage(true);
}

// Bail out if the folder doesn't exist
if (!sh.test("-e", folder)) {
  console.error(
    `Folder ${folder} not found at ${path.join(process.cwd(), folder)}`
  );
  usage(true);
}

// Define template html, user's first, otherwise default
let template = path.join(folder, templateFilename);
if (!sh.test("-e", template)) {
  template = path.join(__dirname, defaultFolder, templateFilename);
}
const tpl = sh.cat(template);

// Prepare output folder (create, clean, copy sources)
sh.mkdir("-p", output);
sh.rm("-rf", output + "/*");
sh.cp("-R", folder + `/!(node_modules|${output})`, output);

// Start processing. Outline:
//
// 1. Get all files
// 2. Sort them
// 3. Group them hierachically
// 4. Parse files and generate output html files

sh.cd(output);
const all = sh.find("*");

const mds = all
  .filter(file => file.match(mdR))
  .sort(sortByPreferences.bind(null, preferences))
  .map(file => {
    const content = sh.cat(file).toString(); // The result is a weird not-string
    return {
      path: file,
      url: mdUrl(file),
      content,
      html: md2html(content)
    };
  });

const groupedMds: FileTree<StringFile> = mds.reduce(
  (grouped: FileTree<StringFile>, value) => groupByPath(grouped, value.path),
  []
);

mds.forEach(({ path, url, html }) => {
  const navHtml = renderNav(generateIndexInfo(path, groupedMds));
  const pageHtml = page(tpl, navHtml, html);
  fs.writeFileSync(url, pageHtml);
});

const contentsJSON = {
  paths: groupedMds,
  contents: mds.map((md, i) => ({ ...md, id: i }))
};
fs.writeFileSync(contentsFilename, JSON.stringify(contentsJSON, null, 2));

sh.rm("-r", "**/*.md");

function usage(error: boolean) {
  console.log(
    `
Usage:

  markdown-folder-to-html [input-folder]

    input-folder [optional] defaults to \`docs\`
  `
  );
  process.exit(error ? 1 : 0);
}

Ignore 'Desktop.ini' files in folders

When you are running this on a windows machine then it will throw an error because Windows will create a desktop.ini file in each folder every time it is edited. This will stop markdown-folder-to-html from progessing. Can the file be ignored?

image

Problem with CSS files

If I add a CSS file (e.g. from https://github.com/sindresorhus/github-markdown-css) near template.html and add <link rel="stylesheet" href="github-markdown.css"> to the template.html, the link to the style sheet will be wrong for files in nested folders: e.g. folder/a.md will be transformed to folder/a.html which would have link to folder/style.css which does not exist.

We can expose an option to change href="github-markdown.css" to href="../github-markdown.css" for files in level-1 folders, href="../../github-markdown.css" for level 2, etc

Ability to add captions

I would like to display the alt tags of an image as captions in HTML. My current solution is to add this code to the template.html:

<script>
      document.querySelectorAll('article img').forEach( img => img.outerHTML = `<figure>${img.outerHTML}<caption>${img.alt}</figcaption></figure>`);
</script>

This does work (if JS is enabled) but it would be nice to have a built-in option for generating images as proper figures when building the pages instead of having to do it client-side.

Path handling is brittle and results in strange output folders some times

cli.ts does string manipulation with paths in a way that can result in strange output folders. See:

  • const folder = docsFolder || defaultFolder;
    const output = `_${folder}`;
    • Both input and output folders should be path.normalized, and the output should be made from the path.dirname of the input folder, and the name of the input folder with the _ prepended
  • sh.rm("-rf", output + "/*");
    sh.cp("-R", folder + "/*", output);
    • The paths should be joined with path.join rather than with string concatenation

Reference: https://nodejs.org/api/path.html

sidebar NAV

Hi
I believe the render-nav.js should be slightly changed to cater for nested options.
closing LI should be moved at the end of parent (dir)
in line

if (f.type === "dir") {
            const childrenNav = renderNav(f.children, level + 1);
            const indexFile = getIndexFile(f.children);
            // Heading with link if there is an index file in the folder
            if (indexFile) {
                const link = renderActive(f.name, indexFile.value.href, indexFile.value.active);
                return `<li class="heading">${link}\n${childrenNav}\n</li>`;
            }
            // Heading without link
            return `<li class="heading"><span>${f.name}</span></li>\n${childrenNav}\n</li>`;
        }

that way you can easily add dropdown menu as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.