forc_doc/render/item/
components.rs1use crate::{
3 doc::module::ModuleInfo,
4 render::{
5 item::context::ItemContext,
6 search::generate_searchbar,
7 sidebar::{Sidebar, SidebarNav},
8 DocStyle, Renderable, IDENTITY,
9 },
10 RenderPlan, ASSETS_DIR_NAME,
11};
12use anyhow::Result;
13use horrorshow::{box_html, Raw, RenderBox};
14
15use sway_types::BaseIdent;
16
17use super::documentable_type::DocumentableType;
18
19const SWAY_LOGO_FILE: &str = "sway-logo.svg";
21const NORMALIZE_CSS_FILE: &str = "normalize.css";
22const SWAYDOC_CSS_FILE: &str = "swaydoc.css";
23const AYU_CSS_FILE: &str = "ayu.css";
24const AYU_MIN_CSS_FILE: &str = "ayu.min.css";
25
26#[derive(Clone, Debug)]
29pub struct ItemHeader {
30 pub module_info: ModuleInfo,
31 pub friendly_name: &'static str,
32 pub item_name: BaseIdent,
33}
34impl Renderable for ItemHeader {
35 fn render(self, _render_plan: RenderPlan) -> Result<Box<dyn RenderBox>> {
37 let ItemHeader {
38 module_info,
39 friendly_name,
40 item_name,
41 } = self;
42
43 let favicon = module_info
44 .to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{SWAY_LOGO_FILE}"));
45 let normalize = module_info
46 .to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{NORMALIZE_CSS_FILE}"));
47 let swaydoc = module_info
48 .to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{SWAYDOC_CSS_FILE}"));
49 let ayu =
50 module_info.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{AYU_CSS_FILE}"));
51 let ayu_hjs = module_info
52 .to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{AYU_MIN_CSS_FILE}"));
53
54 Ok(box_html! {
55 head {
56 meta(charset="utf-8");
57 meta(name="viewport", content="width=device-width, initial-scale=1.0");
58 meta(name="generator", content="swaydoc");
59 meta(
60 name="description",
61 content=format!(
62 "API documentation for the Sway `{}` {} in `{}`.",
63 item_name.as_str(), friendly_name, module_info.location(),
64 )
65 );
66 meta(name="keywords", content=format!("sway, swaylang, sway-lang, {}", item_name.as_str()));
67 link(rel="icon", href=favicon);
68 title: format!("{} in {} - Sway", item_name.as_str(), module_info.location());
69 link(rel="stylesheet", type="text/css", href=normalize);
70 link(rel="stylesheet", type="text/css", href=swaydoc, id="mainThemeStyle");
71 link(rel="stylesheet", type="text/css", href=ayu);
72 link(rel="stylesheet", href=ayu_hjs);
73 }
75 })
76 }
77}
78
79#[derive(Clone, Debug)]
83pub struct ItemBody {
84 pub module_info: ModuleInfo,
85 pub ty: DocumentableType,
86 pub item_name: BaseIdent,
90 pub code_str: String,
91 pub attrs_opt: Option<String>,
92 pub item_context: ItemContext,
93}
94impl SidebarNav for ItemBody {
95 fn sidebar(&self) -> Sidebar {
96 let style = DocStyle::Item {
97 title: Some(self.ty.as_block_title()),
98 name: Some(self.item_name.clone()),
99 };
100 Sidebar::new(
101 None,
102 style,
103 self.module_info.clone(),
104 self.item_context.to_doclinks(),
105 )
106 }
107}
108impl Renderable for ItemBody {
109 fn render(self, render_plan: RenderPlan) -> Result<Box<dyn RenderBox>> {
111 let sidebar = self.sidebar();
112 let ItemBody {
113 module_info,
114 ty,
115 item_name,
116 code_str,
117 attrs_opt,
118 item_context,
119 } = self;
120
121 let doc_name = ty.doc_name().to_string();
122 let block_title = ty.as_block_title();
123 let sidebar = sidebar.render(render_plan.clone())?;
124 let item_context = (item_context.context_opt.is_some()
125 || item_context.impl_traits.is_some())
126 .then(|| -> Result<Box<dyn RenderBox>> { item_context.render(render_plan.clone()) });
127 let sway_hjs =
128 module_info.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/highlight.js"));
129 let rendered_module_anchors = module_info.get_anchors()?;
130
131 Ok(box_html! {
132 body(class=format!("swaydoc {doc_name}")) {
133 : sidebar;
134 main {
136 div(class="width-limiter") {
137 : generate_searchbar(&module_info);
138 section(id="main-content", class="content") {
139 div(class="main-heading") {
140 h1(class="fqn") {
141 span(class="in-band") {
142 : format!("{} ", block_title.item_title_str());
143 @ for anchor in rendered_module_anchors {
144 : Raw(anchor);
145 }
146 a(class=&doc_name, href=IDENTITY) {
147 : item_name.as_str();
148 }
149 }
150 }
151 }
152 div(class="docblock item-decl") {
153 pre(class=format!("sway {}", &doc_name)) {
154 code { : code_str; }
155 }
156 }
157 @ if attrs_opt.is_some() {
158 details(class="swaydoc-toggle top-doc", open) {
160 summary(class="hideme") {
161 span { : "Expand description" }
162 }
163 div(class="docblock") {
165 : Raw(attrs_opt.unwrap())
166 }
167 }
168 }
169 @ if item_context.is_some() {
170 : item_context.unwrap();
171 }
172 }
173 section(id="search", class="search-results");
174 }
175 }
176 script(src=sway_hjs);
177 script {
178 : "hljs.highlightAll();";
179 }
180 }
181 })
182 }
183}