Skip to content

Commit

Permalink
Merge branch 'main' into exec-editor
Browse files Browse the repository at this point in the history
* main:
  Remove font stuff
  Update documentation
  Heading anchors and link previews
  Image rendering test
  Render local images
  • Loading branch information
AndrewRadev committed Feb 26, 2021
2 parents 8798e6c + a9021a2 commit 9e09b02
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 29 deletions.
49 changes: 34 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,45 @@ Running the app is as simple as:
quickmd <markdown-file>
```

Pressing escape will close the window. Running it with `--help` should provide more info on the available options:
Pressing escape will close the window. Running it with `--help` should provide more info on the available options. Here's how the output looks for me:

```
quickmd 0.3.0
A simple markdown previewer.
quickmd 0.3.1
A simple self-contained markdown previewer.
Code highlighting via highlight.js version 9.18.1
Edit configuration in: /home/andrew/.config/quickmd/config.yaml
Add custom CSS in: /home/andrew/.config/quickmd/custom.css
USAGE:
quickmd [FLAGS] [OPTIONS] <input-file.md>
quickmd [FLAGS] [OPTIONS] [input-file.md]
FLAGS:
-d, --debug Activates debug logging
-h, --help Prints help information
-V, --version Prints version information
--no-watch Disables watching file for changes
-d, --debug
Activates debug logging
-h, --help
Prints help information
--install-default-config
Creates a configuration file for later editing if one doesn't exist. Exits when done
-V, --version
Prints version information
--no-watch
Disables watching file for changes
OPTIONS:
--output <directory> Builds output HTML and other assets in the given directory instead of in a tempdir. Will
be created if it doesn't exist. Not deleted on application exit
--output <directory>
Builds output HTML and other assets in the given directory instead of in a tempdir. Will be created if it
doesn't exist. Not deleted on application exit
ARGS:
<input-file.md> Markdown file to render. Use "-" to read markdown from STDIN (implies --no-watch)
<input-file.md>
Markdown file to render. Use "-" to read markdown from STDIN (implies --no-watch)
```

## Features
Expand All @@ -69,9 +87,10 @@ ARGS:

## Configuration

You can change the CSS of the preview HTML by writing CSS in one of these files:
You can change the CSS of the preview HTML by writing a file named "custom.css" in the application's config directory. On a linux machine, it would be: `~/.config/quickmd/`.

You can also change some configuration options in a config file. Run `quickmd` with `--install-default-config` to create that file with all the defaults and comments.

- `~/.quickmd.css`
- `~/.config/quickmd.css`
Run `--help` to know where the config files will be located on your system.

The built-in CSS that is used is stored in [/res/style](./res/style).
The built-in CSS that is used is stored in [/res/style](./res/style) and the default config is in [/res/default_config.yaml](./res/default_config.yaml)
35 changes: 30 additions & 5 deletions res/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ let page_state = JSON.parse(title.innerHTML);
// Update scroll position on load:
window.scroll(0, page_state.scroll_top);

// Set image sizes we have data for, store sizes for new images.
// Store scroll position on scroll:
window.addEventListener('scroll', function() {
page_state.scroll_top = window.pageYOffset;
title.innerHTML = JSON.stringify(page_state);
});

// Set image sizes we have data for, store sizes for new images:
document.querySelectorAll('img').forEach(function(img) {
const width = page_state.image_widths[img.src];
const height = page_state.image_heights[img.src];
Expand All @@ -28,8 +34,27 @@ document.querySelectorAll('img').forEach(function(img) {
};
});

// Store scroll position on scroll:
window.addEventListener('scroll', function() {
page_state.scroll_top = window.pageYOffset;
title.innerHTML = JSON.stringify(page_state);
// Create anchors for all the headings:
document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(function(heading) {
if (!heading.id) {
let content = heading.innerHTML.trim().toLowerCase();
let slug = content.replace(/[^\w\d]+/g, '-');

heading.id = slug;
}
});

// Show link preview at the bottom:
let linkPreview = document.querySelector('#link-preview');
document.querySelectorAll('a').forEach(function(link) {
link.addEventListener('mouseenter', function() {
linkPreview.innerHTML = link.href;
linkPreview.classList.remove('hidden');
linkPreview.classList.add('visible');
});

link.addEventListener('mouseleave', function() {
linkPreview.classList.remove('visible');
linkPreview.classList.add('hidden');
});
});
3 changes: 3 additions & 0 deletions res/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
{body}
</main>

<div id="link-preview">
</div>

<script src="main.js" type="text/javascript">
</script>

Expand Down
26 changes: 23 additions & 3 deletions res/style/main.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
main {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-weight: 400;

width: 66%;
margin: 0 auto;
}

#link-preview {
position: fixed;
bottom: 0;
right: 0;
padding: 5px 10px;
background-color: #f5f6f7;
border-radius: 5px 0 0 0;
border-top: 1px solid #dcdfe3;
border-left: 1px solid #dcdfe3;
font-size: 0.7em;
opacity: 0;
}

#link-preview.visible {
opacity: 0.95;
transition: 300ms ease-out;
}

#link-preview.hidden {
opacity: 0;
transition: 300ms ease-out;
}
19 changes: 13 additions & 6 deletions src/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use std::fs;
use std::io;
use std::path::PathBuf;
use std::path::{PathBuf, Path};
use std::collections::HashSet;
use pulldown_cmark::{Parser, Options, Event, html};

Expand Down Expand Up @@ -33,6 +33,7 @@ impl Renderer {
///
pub fn run(&self) -> Result<RenderedContent, io::Error> {
let markdown = fs::read_to_string(&self.canonical_md_path)?;
let root_dir = self.canonical_md_path.parent().unwrap_or_else(|| Path::new(""));

let mut options = Options::empty();
options.insert(Options::ENABLE_TABLES);
Expand All @@ -42,13 +43,19 @@ impl Renderer {
let parser = Parser::new_ext(&markdown, options);

let mut languages = HashSet::new();
let parser = parser.map(|event| {
let parser = parser.map(|mut event| {
use pulldown_cmark::{Tag, CodeBlockKind};

if let Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(content))) = &event {
if content.len() > 0 {
languages.insert(content.to_string());
}
match &mut event {
Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(content))) => {
if content.len() > 0 {
languages.insert(content.to_string());
}
},
Event::Start(Tag::Image(_, url, _)) if url.starts_with("./") => {
*url = format!("file://{}/{}", root_dir.display(), &url[2..]).into();
},
_ => (),
}

event
Expand Down
20 changes: 20 additions & 0 deletions tests/test_markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,23 @@ fn test_keeps_track_of_rendered_languages() {

assert_eq!(expected, content.code_languages);
}

#[test]
fn test_renders_local_images() {
let mut file = NamedTempFile::new().unwrap();
let tempdir = file.path().parent().unwrap().to_path_buf();

writeln!(file, "![demo image](./local-image.png)").unwrap();
writeln!(file, "![demo image](http://remote-image.png)").unwrap();
writeln!(file, "![demo image](unprefixed_image.png)").unwrap();

let renderer = Renderer::new(file.path().to_path_buf());
let content = renderer.run().unwrap();

let local_src = format!("src=\"file://{}/local-image.png\"", tempdir.display());
assert!(content.html.contains(&local_src));
assert!(content.html.contains("src=\"http://remote-image.png\""));

// Without a ./ prefix, it's left alone
assert!(content.html.contains("src=\"unprefixed_image.png\""));
}

0 comments on commit 9e09b02

Please sign in to comment.