Skip to content

Commit

Permalink
Wrap emoji with span and use a font for emojis. (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
fnando authored Jan 29, 2024
1 parent 5a92548 commit bd9fcb8
Show file tree
Hide file tree
Showing 17 changed files with 113 additions and 67 deletions.
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

## unreleased

- Add `before_markdown_render` and `after_markdown_render` hooks, allowing
content manipulation.
- Add link anchor on each title.
- Add `before_render` and `after_render` hooks, allowing content manipulation.
Use `Kitabu::Markdown.add_hook(event, &block)`.
- Add link anchor on each title, so you can display an anchor link on HTML
pages.
- Improve epub final file (better table of contents, less epubcheck errors, CSS
localization, and more).
- Add support for frontmatter on `.md` and `.md.erb` files.
- Wrap emoji with `span.emoji` and use a font for emojis so it renders the same
in any system.

## v3.1.0

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,18 +242,18 @@ The following Redcarpet options are enabled:
### Hooks

There are a few hooks that allows manipulating the content. You can use
`before_markdown_render` and `after_markdown_render`. You can add such hooks to
your `config/helpers.rb` file.
`before_render` and `after_render` to process the Markdown content. You can add
such hooks to your `config/helpers.rb` file.

```ruby
Kitabu.add_hook(:before_markdown_render) do |markdown|
Kitabu::Markdown.add_hook(:before_render) do |content|
# manipulate content and return it.
markdown
content
end

Kitabu.add_hook(:after_markdown_render) do |html|
Kitabu::Markdown.add_hook(:after_render) do |content|
# manipulate content and return it.
html
content
end
```

Expand Down
1 change: 1 addition & 0 deletions kitabu.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Gem::Specification.new do |s|
s.add_dependency "rouge"
s.add_dependency "rubyzip"
s.add_dependency "thor"
s.add_dependency "unicode-emoji"

s.add_development_dependency "pry-meta"
s.add_development_dependency "rake"
Expand Down
24 changes: 1 addition & 23 deletions lib/kitabu.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
require "pathname"
require "thor"
require "thor/group"
require "unicode/emoji"
require "yaml"
require "cgi"

Expand Down Expand Up @@ -53,29 +54,6 @@ module Kitabu
require "kitabu/front_matter"
require "kitabu/context"

# Hook up and run custom code before certain actions. Existing hooks:
#
# * before_markdown_render
# * after_markdown_render
#
# To add a new hook:
#
# Kitabu.add_hook(:before_markdown_render) do |content|
# content
# end
#
def self.hooks
@hooks ||= Hash.new {|h, k| h[k] = [] }
end

def self.add_hook(name, &block)
hooks[name.to_sym] << block
end

def self.run_hooks(name, arg)
hooks[name.to_sym].reduce(arg) {|buffer, hook| hook.call(buffer) }
end

def self.config(root_dir = nil)
root_dir ||= Pathname.new(Dir.pwd)
path = root_dir.join("config/kitabu.yml")
Expand Down
14 changes: 12 additions & 2 deletions lib/kitabu/css.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ module Kitabu
class CSS
def self.create_file(root_dir:, config:)
buffer = StringIO.new
buffer << emoji
buffer << "\n\n"
buffer << accent_color(config:)
buffer << "\n\n"
buffer << syntax_highlight(config:)
buffer << "\n\n"
buffer << translations(config:)
buffer << translations

support_dir = root_dir.join("assets/styles/support")

Expand All @@ -34,7 +36,7 @@ def self.syntax_highlight(config:)
).render(scope: ".highlight")
end

def self.translations(config:)
def self.translations
backend = I18n.backend.translations

translations =
Expand All @@ -52,5 +54,13 @@ def self.translations(config:)

translations.join("\n")
end

def self.emoji
<<~CSS
.emoji {
font-family: "Noto Color Emoji";
}
CSS
end
end
end
2 changes: 0 additions & 2 deletions lib/kitabu/exporter/epub.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ def write_sections!
# Save file to disk.
#
File.open(section.filepath, "w") do |file|
section.html = Kitabu.run_hooks(:process_epub_section, section.html)

content = section.html.css("body").to_xhtml.gsub(
%r{<body>(.*?)</body>}m, "\\1"
)
Expand Down
4 changes: 1 addition & 3 deletions lib/kitabu/exporter/html.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ def content
matter.content
end

content = Kitabu.run_hooks(:before_markdown_render, content)
content = Kitabu::Markdown.render(content)
Kitabu.run_hooks(:after_markdown_render, content)
Kitabu::Markdown.render(content)
end

private def file_format(file_path)
Expand Down
36 changes: 35 additions & 1 deletion lib/kitabu/markdown.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,41 @@ class << self
self.processor = Redcarpet::Markdown.new(renderer, default_markdown_options)

def self.render(text)
processor.render(text)
text = run_hooks(:before_render, text)
run_hooks(:after_render, processor.render(text))
end

# Hook up and run custom code before certain actions. Existing hooks:
#
# * before_render
# * after_render
#
# To add a new hook:
#
# Kitabu::Markdown.add_hook(:before_render) do |content|
# content
# end
#
def self.hooks
@hooks ||= Hash.new {|h, k| h[k] = [] }
end

def self.add_hook(name, &block)
hooks[name.to_sym] << block
end

def self.run_hooks(name, arg)
hooks[name.to_sym].reduce(arg) {|buffer, hook| hook.call(buffer) }
end

def self.setup_default_hooks
add_hook(:after_render) do |content|
content.gsub(Unicode::Emoji::REGEX) do |emoji|
%[<span class="emoji">#{emoji}</span>]
end
end
end

setup_default_hooks
end
end
26 changes: 5 additions & 21 deletions spec/kitabu/exporter/html_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,6 @@
let(:root) { SPECDIR.join("support/mybook") }
let(:format) { described_class.new(root) }

context "hooks" do
let(:file) { SPECDIR.join("support/mybook/output/mybook.html") }
let(:html) { File.read(file) }

it "calls before markdown render hook" do
index = 0

Kitabu.add_hook(:after_markdown_render) do |_content|
index += 1
"<p>after #{index}</p>"
end

format.export

expect(html).to have_tag("p", "after 1")
expect(html).to have_tag("p", "after 2")
expect(html).to have_tag("p", "after 3")
expect(html).to have_tag("p", "after 4")
end
end

context "when generating HTML" do
let(:file) { SPECDIR.join("support/mybook/output/mybook.html") }
let(:html) { File.read(file) }
Expand Down Expand Up @@ -67,6 +46,11 @@
expect(html).to have_tag("div.note.info > p", "This is a note!")
end

it "wraps emojis" do
expect(html).to have_tag("span.emoji", "🫠")
expect(html).to have_tag("span.emoji", "👋")
end

it "copies assets" do
expect(root.join("output/assets/images/cover.png")).to be_file
expect(root.join("output/assets/images/logo.gif")).to be_file
Expand Down
14 changes: 14 additions & 0 deletions spec/kitabu/markdown_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,18 @@ class User
expect(html.css(".note").count).to eql(0)
expect(html.css("blockquote").text.chomp).to eql("This is just a quote")
end

it "calls before render hook" do
Kitabu::Markdown.add_hook(:before_render, &:upcase)

expect(Kitabu::Markdown.render("Hello")).to eql("<p>HELLO</p>\n")
end

it "calls after render hook" do
Kitabu::Markdown.add_hook(:after_render) do |content|
content.gsub("<p>Hello</p>", "<em>BYE</em>")
end

expect(Kitabu::Markdown.render("Hello")).to eql("<em>BYE</em>\n")
end
end
10 changes: 7 additions & 3 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ def bundle_install

cleaner = proc do
[
TMPDIR
# SPECDIR.join("support/mybook/output")
TMPDIR,
SPECDIR.join("support/mybook/output")
].each do |i|
FileUtils.rm_rf(i)
end
Expand All @@ -59,5 +59,9 @@ def bundle_install
config.before(&cleaner)
config.after(&cleaner)
config.before { FileUtils.mkdir_p(TMPDIR) }
config.before { Kitabu.hooks.clear }

config.before do
Kitabu::Markdown.hooks.clear
Kitabu::Markdown.setup_default_hooks
end
end
5 changes: 5 additions & 0 deletions spec/support/mybook/assets/styles/support/kitabu.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.emoji {
font-family: "Noto Color Emoji";
}


:root {
--accent-color: #5091b1;
}
Expand Down
9 changes: 7 additions & 2 deletions spec/support/mybook/text/01_Markdown_Chapter.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
## Markdown

This chapter was written with [Markdown](http://daringfireball.net/projects/markdown/).
This chapter was written with
[Markdown](http://daringfireball.net/projects/markdown/).

``` ruby
```ruby
nice to hear that!
```

👋

🫠
Binary file added templates/assets/fonts/NotoColorEmoji-Regular.ttf
Binary file not shown.
9 changes: 9 additions & 0 deletions templates/assets/styles/support/fonts.css
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,12 @@
font-stretch: condensed;
src: url("../../fonts/OpenSans-SemiboldItalic.ttf");
}

/* Noto Color Emoji, Regular */
@font-face {
font-family: "Noto Color Emoji";
font-weight: normal;
font-style: normal;
font-stretch: normal;
src: url("../../fonts/NotoColorEmoji-Regular.ttf");
}
3 changes: 2 additions & 1 deletion templates/config.erb
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,5 @@ css_accent_color: "#0089F0"
#
# $ strings output/kitabu.pdf | grep FontName
#
prince_args: [--no-system-fonts, --debug, --log, output/prince.log]
prince_args:
[--tagged-pdf, --no-system-fonts, --debug, --log, output/prince.log]
2 changes: 2 additions & 0 deletions templates/text/01_Getting_Started.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Getting Started

Hey! 👋

This guide is designed for beginners who want to get started with Kitabu from
scratch. Kitabu uses Ruby to generate e-books in different formats by using
[Markdown](https://en.wikipedia.org/wiki/Markdown).
Expand Down

0 comments on commit bd9fcb8

Please sign in to comment.