feat(html): add meta tags for document authors and keywords

This commit is contained in:
Approximately Equal 2025-04-03 22:02:17 -07:00 committed by Chance Addis
parent ed2106e28d
commit b8d1c7cf87
17 changed files with 73 additions and 8 deletions

View File

@ -5,9 +5,12 @@ mod encode;
pub use self::encode::html; pub use self::encode::html;
use comemo::{Track, Tracked, TrackedMut}; use comemo::{Track, Tracked, TrackedMut};
use typst_library::diag::{bail, warning, At, SourceResult}; pub use ecow::EcoVec;
use typst_library::diag::{bail, warning, At, SourceDiagnostic, SourceResult, StrResult};
use typst_library::engine::{Engine, Route, Sink, Traced}; use typst_library::engine::{Engine, Route, Sink, Traced};
use typst_library::foundations::{Content, StyleChain, Target, TargetElem}; use typst_library::foundations::{
Content, Datetime, Smart, StyleChain, Target, TargetElem,
};
use typst_library::html::{ use typst_library::html::{
attr, tag, FrameElem, HtmlDocument, HtmlElem, HtmlElement, HtmlNode, attr, tag, FrameElem, HtmlDocument, HtmlElem, HtmlElement, HtmlNode,
}; };
@ -84,7 +87,7 @@ fn html_document_impl(
let output = handle_list(&mut engine, &mut locator, children.iter().copied())?; let output = handle_list(&mut engine, &mut locator, children.iter().copied())?;
let introspector = Introspector::html(&output); let introspector = Introspector::html(&output);
let root = root_element(output, &info)?; let root = root_element(&mut engine, output, &info)?;
Ok(HtmlDocument { info, root, introspector }) Ok(HtmlDocument { info, root, introspector })
} }
@ -262,18 +265,24 @@ fn handle(
/// Wrap the nodes in `<html>` and `<body>` if they are not yet rooted, /// Wrap the nodes in `<html>` and `<body>` if they are not yet rooted,
/// supplying a suitable `<head>`. /// supplying a suitable `<head>`.
fn root_element(output: Vec<HtmlNode>, info: &DocumentInfo) -> SourceResult<HtmlElement> { fn root_element(
engine: &mut Engine,
output: Vec<HtmlNode>,
info: &DocumentInfo,
) -> SourceResult<HtmlElement> {
let head = head_element(engine, info).map_err(|err| {
EcoVec::from([SourceDiagnostic::warning(Span::detached(), err)])
})?;
let body = match classify_output(output)? { let body = match classify_output(output)? {
OutputKind::Html(element) => return Ok(element), OutputKind::Html(element) => return Ok(element),
OutputKind::Body(body) => body, OutputKind::Body(body) => body,
OutputKind::Leafs(leafs) => HtmlElement::new(tag::body).with_children(leafs), OutputKind::Leafs(leafs) => HtmlElement::new(tag::body).with_children(leafs),
}; };
Ok(HtmlElement::new(tag::html) Ok(HtmlElement::new(tag::html).with_children(vec![head.into(), body.into()]))
.with_children(vec![head_element(info).into(), body.into()]))
} }
/// Generate a `<head>` element. /// Generate a `<head>` element.
fn head_element(info: &DocumentInfo) -> HtmlElement { fn head_element(engine: &mut Engine, info: &DocumentInfo) -> StrResult<HtmlElement> {
let mut children = vec![]; let mut children = vec![];
children.push(HtmlElement::new(tag::meta).with_attr(attr::charset, "utf-8").into()); children.push(HtmlElement::new(tag::meta).with_attr(attr::charset, "utf-8").into());
@ -302,7 +311,47 @@ fn head_element(info: &DocumentInfo) -> HtmlElement {
); );
} }
HtmlElement::new(tag::head).with_children(children) if !info.author.is_empty() {
children.push(
HtmlElement::new(tag::meta)
.with_attr(attr::name, "authors")
.with_attr(attr::content, info.author.join(", "))
.into(),
)
}
if !info.keywords.is_empty() {
children.push(
HtmlElement::new(tag::meta)
.with_attr(attr::name, "keywords")
.with_attr(attr::content, info.keywords.join(", "))
.into(),
)
}
match info.date {
Smart::Auto => children.push(
HtmlElement::new(tag::meta)
.with_attr(attr::name, "date")
.with_attr(
attr::content,
Datetime::today(engine, Smart::Auto)?.display(Smart::Auto)?,
)
.into(),
),
Smart::Custom(optional_date) => {
if let Some(date) = optional_date {
children.push(
HtmlElement::new(tag::meta)
.with_attr(attr::name, "date")
.with_attr(attr::content, date.display(Smart::Auto).unwrap())
.into(),
)
}
}
}
Ok(HtmlElement::new(tag::head).with_children(children))
} }
/// Determine which kind of output the user generated. /// Determine which kind of output the user generated.

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<table> <table>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<p>Paragraph</p> <p>Paragraph</p>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<p>Text <span style="display: inline-block;">Span</span>.</p> <p>Text <span style="display: inline-block;">Span</span>.</p>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<table> <table>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<table> <table>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<div> <div>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<ol start="3"> <ol start="3">

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<h2>Level 1</h2> <h2>Level 1</h2>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<p><a href="https://example.com/">https://example.com/</a></p> <p><a href="https://example.com/">https://example.com/</a></p>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<div> <div>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<h2>Heading is no paragraph</h2> <h2>Heading is no paragraph</h2>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<blockquote cite="https://typst.app/home">Compose papers faster</blockquote> <blockquote cite="https://typst.app/home">Compose papers faster</blockquote>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<p>When you said that “he surely meant that she intended to say “I'm sorry””, I was quite confused.</p> <p>When you said that “he surely meant that she intended to say “I'm sorry””, I was quite confused.</p>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<blockquote>… ἔοικα γοῦν τούτου γε σμικρῷ τινι αὐτῷ τούτῳ σοφώτερος εἶναι, ὅτι ἃ μὴ οἶδα οὐδὲ οἴομαι εἰδέναι.</blockquote> <blockquote>… ἔοικα γοῦν τούτου γε σμικρῷ τινι αὐτῷ τούτῳ σοφώτερος εἶναι, ὅτι ἃ μὴ οἶδα οὐδὲ οἴομαι εἰδέναι.</blockquote>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<table> <table>

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="date" content="1970-01-01">
</head> </head>
<body> <body>
<div> <div>