Merge 7e418ad1482102e7e53a854f99e6a91283df48a2 into 36ecbb2c8dccc1a31c43fee1466f1425844d8607

This commit is contained in:
Johann Birnick 2025-07-08 10:54:49 +08:00 committed by GitHub
commit d0243ea7f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 110 additions and 0 deletions

View File

@ -20,6 +20,7 @@ mod reference;
mod strong;
mod table;
mod terms;
mod title;
pub use self::bibliography::*;
pub use self::cite::*;
@ -39,6 +40,7 @@ pub use self::reference::*;
pub use self::strong::*;
pub use self::table::*;
pub use self::terms::*;
pub use self::title::*;
use crate::foundations::Scope;
@ -49,6 +51,7 @@ pub fn define(global: &mut Scope) {
global.define_elem::<RefElem>();
global.define_elem::<LinkElem>();
global.define_elem::<OutlineElem>();
global.define_elem::<TitleElem>();
global.define_elem::<HeadingElem>();
global.define_elem::<FigureElem>();
global.define_elem::<FootnoteElem>();

View File

@ -0,0 +1,68 @@
use crate::{
diag::SourceResult,
engine::Engine,
foundations::{
elem, Content, NativeElement, Packed, Show, ShowSet, Smart, StyleChain, Styles,
TargetElem,
},
html::{tag, HtmlElem},
introspection::Locatable,
layout::{AlignElem, Alignment, BlockBody, BlockElem, Em},
text::{FontWeight, TextElem, TextSize},
};
/// A document title.
///
/// Should be used to display the main title of the whole document, and should
/// occur only once per document.
///
/// Shows as `h1` in HTML. In contrast, a heading of level 1
/// (created with `= Some Heading`) will show as `h2`.
///
/// # Example
/// ```example
/// #title[Interstellar Mail Delivery]
///
/// = Introduction
/// In recent years, ...
/// ```
#[elem(Locatable, Show, ShowSet)]
pub struct TitleElem {
/// The content of the title.
#[required]
pub body: Content,
}
impl Show for Packed<TitleElem> {
#[typst_macros::time(name = "title", span = self.span())]
fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let html = TargetElem::target_in(styles).is_html();
let span = self.span();
let realized = self.body().clone();
Ok(if html {
HtmlElem::new(tag::h1).with_body(Some(realized)).pack().spanned(span)
} else {
let realized = BlockBody::Content(realized);
BlockElem::new().with_body(Some(realized)).pack().spanned(span)
})
}
}
impl ShowSet for Packed<TitleElem> {
fn show_set(&self, _styles: StyleChain) -> Styles {
const SIZE: Em = Em::new(1.6);
const ABOVE: Em = Em::new(1.125);
const BELOW: Em = Em::new(0.75);
let mut out = Styles::new();
out.set(TextElem::set_size(TextSize(SIZE.into())));
out.set(TextElem::set_weight(FontWeight::BOLD));
out.set(BlockElem::set_above(Smart::Custom(ABOVE.into())));
out.set(BlockElem::set_below(Smart::Custom(BELOW.into())));
out.set(BlockElem::set_sticky(true));
out.set(AlignElem::set_alignment(Alignment::CENTER));
out
}
}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>
A cool title
</h1>
<h2>
Some level one heading
</h2>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>
Some Title
</h1>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
tests/ref/title-basic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,12 @@
// Test title element.
--- title-basic render html ---
#title[Some Title]
--- title-and-heading render html ---
#title([A cool title])
= Some level one heading
--- title-show-rule ---
#show title: set text(3em)
#title[Some Title]