Skip to content

Commit

Permalink
Add macro to inline SVG files (#1761)
Browse files Browse the repository at this point in the history
* Add macro to inline SVG files

* Add modifier for originally styled attributes

* Add test for inlined svg with its original styling

* Create separate test cases for stripping out unwanted elements in SVGs

* Replace newlines with a space to avoid attribute concatenation

* Strip leading an trailing whitespace on icons
  • Loading branch information
wout authored Nov 17, 2022
1 parent 8d0681a commit dbd66f9
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 0 deletions.
9 changes: 9 additions & 0 deletions spec/fixtures/lucky_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions spec/lucky/text_helpers/svg_inliner_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require "./text_helpers_spec"

@[Lucky::SvgInliner::Path("spec/fixtures")]
module Lucky::SvgInliner
end

class TextHelperTestPage
def with_inlined_svg
inline_svg("lucky_logo.svg")
end

def with_inlined_and_styled_svg
inline_svg("lucky_logo.svg", false)
end
end

describe Lucky::SvgInliner do
describe ".inline_svg" do
it "inlines an svg in a page" do
inlined_svg = view.tap(&.with_inlined_svg).render
inlined_svg.should start_with %(<svg data-inline-svg="lucky_logo.svg")
inlined_svg.should_not contain %(<?xml version="1.0" encoding="UTF-8"?>)
inlined_svg.should_not contain %(<!-- lucky logo -->)
inlined_svg.should_not contain "\n"
inlined_svg.should_not contain %(fill="none" stroke="#2a2a2a" class="logo")
end

it "strips the xml declaration" do
inlined_svg = view.tap(&.with_inlined_svg).render
inlined_svg.should_not contain %(<?xml version="1.0" encoding="UTF-8"?>)
end

it "strips comments" do
inlined_svg = view.tap(&.with_inlined_svg).render
inlined_svg.should_not contain %(<!-- lucky logo -->)
end

it "strips newlines" do
inlined_svg = view.tap(&.with_inlined_svg).render
inlined_svg.should_not contain "\n"
end

it "strips styling attributes by default" do
inlined_svg = view.tap(&.with_inlined_svg).render
inlined_svg.should_not contain %(fill="none" stroke="#2a2a2a" class="logo")
end

it "allows inlinging an svg without stripping its styling attributes" do
inlined_svg = view.tap(&.with_inlined_and_styled_svg).render
inlined_svg.should start_with %(<svg data-inline-svg-styled="lucky_logo.svg")
inlined_svg.should contain %(fill="none" stroke="#2a2a2a" class="logo")
end
end
end
1 change: 1 addition & 0 deletions src/lucky/html_builder.cr
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module Lucky::HTMLBuilder
include Lucky::RenderIfDefined
include Lucky::TagDefaults
include Lucky::LiveReloadTag
include Lucky::SvgInliner

abstract def view : IO

Expand Down
28 changes: 28 additions & 0 deletions src/lucky/page_helpers/svg_inliner.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
annotation Lucky::SvgInliner::Path
end
annotation Lucky::SvgInliner::StripRegex
end

@[Lucky::SvgInliner::Path("src/svgs")]
@[Lucky::SvgInliner::StripRegex(/(class|fill|stroke|stroke-width|style)="[^"]+" ?/)]
module Lucky::SvgInliner
macro inline_svg(path, strip_styling = true)
{%
svgs_path = Lucky::SvgInliner.annotation(Lucky::SvgInliner::Path).args.first
regex = Lucky::SvgInliner.annotation(Lucky::SvgInliner::StripRegex).args.first
full_path = "#{svgs_path.id}/#{path.id}"

raise "SVG file #{full_path.id} is missing" unless file_exists?(full_path)

svg = read_file(full_path)
.gsub(/<\?xml[^>]+>/, "")
.gsub(/<!--[^>]+>/, "")
.gsub(/\n\s*/, " ")
.strip
svg = svg.gsub(regex, "") if strip_styling
modifier = strip_styling ? "" : "-styled"
%}

raw {{svg.gsub(/<svg/, %(<svg data-inline-svg#{modifier.id}="#{path.id}"))}}
end
end

0 comments on commit dbd66f9

Please sign in to comment.