use crate::tests::prelude::*;
track_file!("ref/asciidoc-lang/docs/modules/macros/pages/icon-macro.adoc");
non_normative!(
r#"
= Icon Macro
In addition to built-in icons, you can add icons anywhere in your content where macros are substituted using the icon macro.
This page covers the anatomy of the icon macro, how the target is resolved, and what features it support (subject to the icon mode).
"#
);
mod anatomy {
use crate::tests::prelude::*;
non_normative!(
r#"
== Anatomy
The icon macro is an inline macro.
Like other inline macros, its syntax follows the familiar pattern of the macro name and target separated by a colon followed by an attribute list enclosed in square brackets.
[source]
----
icon:<target>[<attrlist>]
----
The `<target>` is the icon name or path.
The `<attrlist>` specifies various named attributes to configure how the icon is displayed.
"#
);
#[test]
fn example() {
verifies!(
r#"
For example:
[source]
----
icon:heart[2x,role=red]
----
"#
);
let doc = Parser::default().parse("icon:heart[2x,role=red]");
assert_eq!(
doc,
Document {
header: Header {
title_source: None,
title: None,
attributes: &[],
author_line: None,
revision_line: None,
comments: &[],
source: Span {
data: "",
line: 1,
col: 1,
offset: 0,
},
},
blocks: &[Block::Simple(SimpleBlock {
content: Content {
original: Span {
data: "icon:heart[2x,role=red]",
line: 1,
col: 1,
offset: 0,
},
rendered: "<span class=\"icon red\">[heart]</span>",
},
source: Span {
data: "icon:heart[2x,role=red]",
line: 1,
col: 1,
offset: 0,
},
style: SimpleBlockStyle::Paragraph,
title_source: None,
title: None,
caption: None,
number: None,
anchor: None,
anchor_reftext: None,
attrlist: None,
},),],
source: Span {
data: "icon:heart[2x,role=red]",
line: 1,
col: 1,
offset: 0,
},
warnings: &[],
source_map: SourceMap(&[]),
catalog: Catalog::default(),
}
);
}
}
mod example {
use crate::tests::prelude::*;
#[test]
fn tags_example() {
verifies!(
r#"
== Example
Here's an example that shows how to inserts an icon named _tags_ in front of a list of tag names.
[source]
----
icon:tags[] ruby, asciidoctor
----
Here's how the HTML converter converts an icon macro when the `icons` attribute is not set or empty.
.Result: HTML output
[source,html]
----
<div class="paragraph">
<p><span class="image"><img src="./images/icons/tags.png" alt="tags"></span> ruby, asciidoctor</p>
</div>
----
"#
);
let doc = Parser::default().parse(":icons:\n\nicon:tags[] ruby, asciidoctor");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><img src="./images/icons/tags.png" alt="tags"></span> ruby, asciidoctor"#
);
}
non_normative!(
r#"
Here's how the DocBook converter converts an icon macro.
[source,xml]
----
<inlinemediaobject>
<imageobject>
<imagedata fileref="./images/icons/tags.png"/>
</imageobject>
<textobject><phrase>tags</phrase></textobject>
</inlinemediaobject> ruby, asciidoctor
----
When the image for an icon can't be located in the icons directory, the AsciiDoc processor displays the icon macro's alt (i.e. fallback) text.
"#
);
}
mod how_the_icon_is_resolved {
use crate::tests::prelude::*;
#[test]
fn resolves_by_mode() {
verifies!(
r#"
== How the icon is resolved
The target of the icon macro is an icon name (or path).
How that target is resolved depends on the icon mode assigned to the xref:icons.adoc#icons-attribute[icons attribute].
text::
The icon name will be enclosed in square brackets (e.g., `[heart]`).
image::
The icon name will be resolved to a file in the `iconsdir` with the file extension specified by `icontype` (e.g., [.path]_./images/icons/heart.png_).
font::
The icon name will be resolved to a glyph in an icon font (as mapped by a CSS class) (e.g., `fa fa-heart`).
WARNING: If you include a file extension in the image target, the icon macro will not work correctly when using the font icon mode (i.e., `icons=font`).
"#
);
let doc = Parser::default().parse("icon:heart[]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon">[heart]</span>"#
);
let doc = Parser::default().parse(":icons: image\n\nicon:heart[]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><img src="./images/icons/heart.png" alt="heart"></span>"#
);
let doc = Parser::default().parse(":icons: font\n\nicon:heart[]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><i class="fa fa-heart"></i></span>"#
);
let doc = Parser::default().parse(":icons: font\n\nicon:heart.png[]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><i class="fa fa-heart.png"></i></span>"#
);
}
}
mod shared_attributes {
use crate::tests::prelude::*;
#[test]
fn title() {
verifies!(
r#"
== Icon macro attributes (shared)
The following attributes of the icon macro are shared for all icon modes.
`role`::
The role applied to the element that surrounds the icon.
`title`::
The title of the image displayed when the mouse hovers over it.
`link`::
The URI target used for the icon, which will wrap the converted icon in a link.
`window`::
The target window of the link (when the `link` attribute is specified).
"#
);
let doc = Parser::default().parse(":icons: image\n\nicon:tags[title=Tags]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><img src="./images/icons/tags.png" alt="tags" title="Tags"></span>"#
);
}
#[test]
fn role() {
verifies!(
r#"
=== Role
Here's an example of an icon that uses a role to specify the color.
[source]
----
icon:tags[role=blue] ruby, asciidoctor
----
"#
);
let doc =
Parser::default().parse(":icons: image\n\nicon:tags[role=blue] ruby, asciidoctor");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon blue"><img src="./images/icons/tags.png" alt="tags"></span> ruby, asciidoctor"#
);
}
#[test]
fn link_and_window() {
verifies!(
r#"
=== Link and window
Here's an example of an icon with a link that targets a separate window:
[source]
----
icon:download[link=https://rubygems.org/downloads/whizbang-1.0.0.gem, window=_blank]
----
"#
);
let doc = Parser::default().parse(
":icons: image\n\nicon:download[link=https://rubygems.org/downloads/whizbang-1.0.0.gem, window=_blank]",
);
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
concat!(
r#"<span class="icon">"#,
r#"<a class="image" href="https://rubygems.org/downloads/whizbang-1.0.0.gem" target="_blank" rel="noopener">"#,
r#"<img src="./images/icons/download.png" alt="download"></a></span>"#,
)
);
}
}
mod image_mode_attributes {
use crate::tests::prelude::*;
#[test]
fn alt_and_width() {
verifies!(
r#"
== Icon macro attributes (image mode only)
The attributes listed below only apply when using the image icon mode.
`alt`::
The alternative text on the `<img>` element (HTML output) or text of `<inlinemediaobject>` element (DocBook output)
`width`::
The width applied to the image.
For example, here's how to control the icon alt text and width when using the image icon mode:
[source]
----
icon:tags[Tags,width=16] ruby, asciidoctor
----
"#
);
let doc = Parser::default().parse(":icons: image\n\nicon:tags[alt=Tags]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><img src="./images/icons/tags.png" alt="Tags"></span>"#
);
let doc = Parser::default().parse(":icons: image\n\nicon:tags[width=16]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><img src="./images/icons/tags.png" alt="tags" width="16"></span>"#
);
let doc =
Parser::default().parse(":icons: image\n\nicon:tags[Tags,width=16] ruby, asciidoctor");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><img src="./images/icons/tags.png" alt="tags" width="16"></span> ruby, asciidoctor"#
);
}
non_normative!(
r#"
The icon macro doesn't support any options to change its physical position (such as alignment).
"#
);
}
mod font_mode_attributes {
use crate::tests::prelude::*;
#[test]
fn size_rotate_flip() {
verifies!(
r#"
== Icon macro attributes (font mode only)
The icon macro has a few attributes that modify the size and orientation of a font-based icon.
These attributes are only recognized in the font icon mode.
`size`::
First positional attribute; scales the icon; values: `1x` (default), `2x`, `3x`, `4x`, `5x`, `lg`, `fw`
`rotate`::
Rotates the icon; values: `90`, `180`, `270`
`flip`::
Flips the icon; values: `horizontal`, `vertical`
"#
);
let doc = Parser::default().parse(":icons: font\n\nicon:heart[2x]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><i class="fa fa-heart fa-2x"></i></span>"#
);
let doc = Parser::default().parse(":icons: font\n\nicon:shield[rotate=90]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><i class="fa fa-shield fa-rotate-90"></i></span>"#
);
let doc = Parser::default().parse(":icons: font\n\nicon:shield[flip=vertical]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><i class="fa fa-shield fa-flip-vertical"></i></span>"#
);
}
#[test]
fn size() {
verifies!(
r#"
=== Size
To make the icon twice the size as the default, enter `2x` inside the square brackets.
[source]
----
icon:heart[2x]
----
or
[source]
----
icon:heart[size=2x]
----
"#
);
let expected = r#"<span class="icon"><i class="fa fa-heart fa-2x"></i></span>"#;
let doc = Parser::default().parse(":icons: font\n\nicon:heart[2x]");
assert_eq!(rendered_paragraphs(&doc).join("\n"), expected);
let doc = Parser::default().parse(":icons: font\n\nicon:heart[size=2x]");
assert_eq!(rendered_paragraphs(&doc).join("\n"), expected);
}
#[test]
fn fixed_width() {
verifies!(
r#"
[TIP]
====
If you want to line up icons so that you can use them as bullets in a list, use the `fw` size as follows:
----
[%hardbreaks]
icon:bolt[fw] bolt
icon:heart[fw] heart
----
====
"#
);
let doc = Parser::default().parse(":icons: font\n\nicon:bolt[fw] bolt");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><i class="fa fa-bolt fa-fw"></i></span> bolt"#
);
let doc = Parser::default().parse(":icons: font\n\nicon:heart[fw] heart");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><i class="fa fa-heart fa-fw"></i></span> heart"#
);
}
#[test]
fn rotate_and_flip() {
verifies!(
r#"
=== Rotate and flip
To rotate and flip an icon, specify these options using named attributes:
[source]
----
icon:shield[rotate=90, flip=vertical]
----
"#
);
let doc = Parser::default().parse(":icons: font\n\nicon:shield[rotate=90, flip=vertical]");
assert_eq!(
rendered_paragraphs(&doc).join("\n"),
r#"<span class="icon"><i class="fa fa-shield fa-flip-vertical"></i></span>"#
);
}
}