mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Figures
This commit is contained in:
parent
529d3e10c6
commit
1a390deaea
@ -191,6 +191,12 @@ impl From<Em> for Spacing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Length> for Spacing {
|
||||||
|
fn from(length: Length) -> Self {
|
||||||
|
Self::Rel(length.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Fr> for Spacing {
|
impl From<Fr> for Spacing {
|
||||||
fn from(fr: Fr) -> Self {
|
fn from(fr: Fr) -> Self {
|
||||||
Self::Fr(fr)
|
Self::Fr(fr)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::layout::{AlignNode, GridLayouter, TrackSizings};
|
use crate::layout::{AlignNode, GridLayouter, TrackSizings};
|
||||||
|
use crate::meta::LocalName;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// A table of items.
|
/// A table of items.
|
||||||
@ -31,7 +32,7 @@ use crate::prelude::*;
|
|||||||
///
|
///
|
||||||
/// Display: Table
|
/// Display: Table
|
||||||
/// Category: layout
|
/// Category: layout
|
||||||
#[node(Layout)]
|
#[node(Layout, LocalName)]
|
||||||
pub struct TableNode {
|
pub struct TableNode {
|
||||||
/// Defines the column sizes. See the [grid documentation]($func/grid) for
|
/// Defines the column sizes. See the [grid documentation]($func/grid) for
|
||||||
/// more information on track sizing.
|
/// more information on track sizing.
|
||||||
@ -264,3 +265,12 @@ impl<T: Into<Value>> From<Celled<T>> for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LocalName for TableNode {
|
||||||
|
fn local_name(&self, lang: Lang) -> &'static str {
|
||||||
|
match lang {
|
||||||
|
Lang::GERMAN => "Tabelle",
|
||||||
|
Lang::ENGLISH | _ => "Table",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -88,6 +88,7 @@ fn global(math: Module, calc: Module) -> Module {
|
|||||||
global.define("link", meta::LinkNode::id());
|
global.define("link", meta::LinkNode::id());
|
||||||
global.define("outline", meta::OutlineNode::id());
|
global.define("outline", meta::OutlineNode::id());
|
||||||
global.define("heading", meta::HeadingNode::id());
|
global.define("heading", meta::HeadingNode::id());
|
||||||
|
global.define("figure", meta::FigureNode::id());
|
||||||
global.define("numbering", meta::numbering);
|
global.define("numbering", meta::numbering);
|
||||||
|
|
||||||
// Symbols.
|
// Symbols.
|
||||||
|
120
library/src/meta/figure.rs
Normal file
120
library/src/meta/figure.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use super::{LocalName, Numbering, NumberingPattern};
|
||||||
|
use crate::layout::{BlockNode, TableNode, VNode};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::text::TextNode;
|
||||||
|
|
||||||
|
/// A figure with an optional caption.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```example
|
||||||
|
/// = Pipeline
|
||||||
|
/// @fig-lab shows the central step of
|
||||||
|
/// our molecular testing pipeline.
|
||||||
|
///
|
||||||
|
/// #figure(
|
||||||
|
/// image("molecular.jpg", width: 80%),
|
||||||
|
/// caption: [
|
||||||
|
/// The molecular testing pipeline.
|
||||||
|
/// ],
|
||||||
|
/// ) <fig-lab>
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Display: Figure
|
||||||
|
/// Category: meta
|
||||||
|
#[node(Synthesize, Show, LocalName)]
|
||||||
|
pub struct FigureNode {
|
||||||
|
/// The content of the figure. Often, an [image]($func/image).
|
||||||
|
#[required]
|
||||||
|
pub body: Content,
|
||||||
|
|
||||||
|
/// The figure's caption.
|
||||||
|
pub caption: Option<Content>,
|
||||||
|
|
||||||
|
/// How to number the figure. Accepts a
|
||||||
|
/// [numbering pattern or function]($func/numbering).
|
||||||
|
#[default(Some(Numbering::Pattern(NumberingPattern::from_str("1").unwrap())))]
|
||||||
|
pub numbering: Option<Numbering>,
|
||||||
|
|
||||||
|
/// The vertical gap between the body and caption.
|
||||||
|
#[default(Em::new(0.65).into())]
|
||||||
|
pub gap: Length,
|
||||||
|
|
||||||
|
/// The figure's number.
|
||||||
|
#[synthesized]
|
||||||
|
pub number: Option<NonZeroUsize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FigureNode {
|
||||||
|
fn element(&self) -> NodeId {
|
||||||
|
let mut id = self.body().id();
|
||||||
|
if id != NodeId::of::<TableNode>() {
|
||||||
|
id = NodeId::of::<Self>();
|
||||||
|
}
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Synthesize for FigureNode {
|
||||||
|
fn synthesize(&self, vt: &mut Vt, styles: StyleChain) -> Content {
|
||||||
|
let my_id = vt.identify(self);
|
||||||
|
let element = self.element();
|
||||||
|
|
||||||
|
let numbering = self.numbering(styles);
|
||||||
|
let mut number = None;
|
||||||
|
if numbering.is_some() {
|
||||||
|
number = NonZeroUsize::new(
|
||||||
|
1 + vt
|
||||||
|
.locate(Selector::node::<Self>())
|
||||||
|
.into_iter()
|
||||||
|
.take_while(|&(id, _)| id != my_id)
|
||||||
|
.filter(|(_, node)| node.to::<Self>().unwrap().element() == element)
|
||||||
|
.count(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let node = self.clone().with_number(number).with_numbering(numbering).pack();
|
||||||
|
let meta = Meta::Node(my_id, node.clone());
|
||||||
|
node.styled(MetaNode::set_data(vec![meta]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Show for FigureNode {
|
||||||
|
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||||
|
let mut realized = self.body();
|
||||||
|
|
||||||
|
if let Some(mut caption) = self.caption(styles) {
|
||||||
|
if let Some(numbering) = self.numbering(styles) {
|
||||||
|
let number = self.number().unwrap();
|
||||||
|
let name = self.local_name(TextNode::lang_in(styles));
|
||||||
|
caption = TextNode::packed(eco_format!("{name}\u{a0}"))
|
||||||
|
+ numbering.apply(vt.world(), &[number])?.display()
|
||||||
|
+ TextNode::packed(": ")
|
||||||
|
+ caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
realized += VNode::weak(self.gap(styles).into()).pack();
|
||||||
|
realized += caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(BlockNode::new()
|
||||||
|
.with_body(Some(realized))
|
||||||
|
.pack()
|
||||||
|
.aligned(Axes::with_x(Some(Align::Center.into()))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalName for FigureNode {
|
||||||
|
fn local_name(&self, lang: Lang) -> &'static str {
|
||||||
|
let body = self.body();
|
||||||
|
if body.is::<TableNode>() {
|
||||||
|
return body.with::<dyn LocalName>().unwrap().local_name(lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
match lang {
|
||||||
|
Lang::GERMAN => "Abbildung",
|
||||||
|
Lang::ENGLISH | _ => "Figure",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use typst::font::FontWeight;
|
use typst::font::FontWeight;
|
||||||
|
|
||||||
use super::Numbering;
|
use super::{LocalName, Numbering};
|
||||||
use crate::layout::{BlockNode, HNode, VNode};
|
use crate::layout::{BlockNode, HNode, VNode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::text::{TextNode, TextSize};
|
use crate::text::{TextNode, TextSize};
|
||||||
@ -40,7 +40,7 @@ use crate::text::{TextNode, TextSize};
|
|||||||
///
|
///
|
||||||
/// Display: Heading
|
/// Display: Heading
|
||||||
/// Category: meta
|
/// Category: meta
|
||||||
#[node(Synthesize, Show, Finalize)]
|
#[node(Synthesize, Show, Finalize, LocalName)]
|
||||||
pub struct HeadingNode {
|
pub struct HeadingNode {
|
||||||
/// The logical nesting depth of the heading, starting from one.
|
/// The logical nesting depth of the heading, starting from one.
|
||||||
#[default(NonZeroUsize::new(1).unwrap())]
|
#[default(NonZeroUsize::new(1).unwrap())]
|
||||||
@ -78,14 +78,6 @@ pub struct HeadingNode {
|
|||||||
pub body: Content,
|
pub body: Content,
|
||||||
|
|
||||||
/// The heading's numbering numbers.
|
/// The heading's numbering numbers.
|
||||||
///
|
|
||||||
/// ```example
|
|
||||||
/// #show heading: it => it.numbers
|
|
||||||
///
|
|
||||||
/// = First
|
|
||||||
/// == Second
|
|
||||||
/// = Third
|
|
||||||
/// ```
|
|
||||||
#[synthesized]
|
#[synthesized]
|
||||||
pub numbers: Option<Vec<NonZeroUsize>>,
|
pub numbers: Option<Vec<NonZeroUsize>>,
|
||||||
}
|
}
|
||||||
@ -93,17 +85,17 @@ pub struct HeadingNode {
|
|||||||
impl Synthesize for HeadingNode {
|
impl Synthesize for HeadingNode {
|
||||||
fn synthesize(&self, vt: &mut Vt, styles: StyleChain) -> Content {
|
fn synthesize(&self, vt: &mut Vt, styles: StyleChain) -> Content {
|
||||||
let my_id = vt.identify(self);
|
let my_id = vt.identify(self);
|
||||||
let numbered = self.numbering(styles).is_some();
|
let numbering = self.numbering(styles);
|
||||||
|
|
||||||
let mut counter = HeadingCounter::new();
|
let mut counter = HeadingCounter::new();
|
||||||
if numbered {
|
if numbering.is_some() {
|
||||||
// Advance passed existing headings.
|
// Advance past existing headings.
|
||||||
for (_, node) in vt
|
for (_, node) in vt
|
||||||
.locate(Selector::node::<HeadingNode>())
|
.locate(Selector::node::<Self>())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.take_while(|&(id, _)| id != my_id)
|
.take_while(|&(id, _)| id != my_id)
|
||||||
{
|
{
|
||||||
let heading = node.to::<HeadingNode>().unwrap();
|
let heading = node.to::<Self>().unwrap();
|
||||||
if heading.numbering(StyleChain::default()).is_some() {
|
if heading.numbering(StyleChain::default()).is_some() {
|
||||||
counter.advance(heading);
|
counter.advance(heading);
|
||||||
}
|
}
|
||||||
@ -116,8 +108,8 @@ impl Synthesize for HeadingNode {
|
|||||||
let node = self
|
let node = self
|
||||||
.clone()
|
.clone()
|
||||||
.with_outlined(self.outlined(styles))
|
.with_outlined(self.outlined(styles))
|
||||||
.with_numbering(self.numbering(styles))
|
.with_numbers(numbering.is_some().then(|| counter.take()))
|
||||||
.with_numbers(numbered.then(|| counter.take()))
|
.with_numbering(numbering)
|
||||||
.pack();
|
.pack();
|
||||||
|
|
||||||
let meta = Meta::Node(my_id, node.clone());
|
let meta = Meta::Node(my_id, node.clone());
|
||||||
@ -196,3 +188,12 @@ cast_from_value! {
|
|||||||
HeadingNode,
|
HeadingNode,
|
||||||
v: Content => v.to::<Self>().ok_or("expected heading")?.clone(),
|
v: Content => v.to::<Self>().ok_or("expected heading")?.clone(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LocalName for HeadingNode {
|
||||||
|
fn local_name(&self, lang: Lang) -> &'static str {
|
||||||
|
match lang {
|
||||||
|
Lang::GERMAN => "Abschnitt",
|
||||||
|
Lang::ENGLISH | _ => "Section",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Interaction between document parts.
|
//! Interaction between document parts.
|
||||||
|
|
||||||
mod document;
|
mod document;
|
||||||
|
mod figure;
|
||||||
mod heading;
|
mod heading;
|
||||||
mod link;
|
mod link;
|
||||||
mod numbering;
|
mod numbering;
|
||||||
@ -8,6 +9,7 @@ mod outline;
|
|||||||
mod reference;
|
mod reference;
|
||||||
|
|
||||||
pub use self::document::*;
|
pub use self::document::*;
|
||||||
|
pub use self::figure::*;
|
||||||
pub use self::heading::*;
|
pub use self::heading::*;
|
||||||
pub use self::link::*;
|
pub use self::link::*;
|
||||||
pub use self::numbering::*;
|
pub use self::numbering::*;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::HeadingNode;
|
use super::{HeadingNode, LocalName};
|
||||||
use crate::layout::{BoxNode, HNode, HideNode, ParbreakNode, RepeatNode};
|
use crate::layout::{BoxNode, HNode, HideNode, ParbreakNode, RepeatNode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::text::{LinebreakNode, SpaceNode, TextNode};
|
use crate::text::{LinebreakNode, SpaceNode, TextNode};
|
||||||
@ -22,7 +22,7 @@ use crate::text::{LinebreakNode, SpaceNode, TextNode};
|
|||||||
///
|
///
|
||||||
/// Display: Outline
|
/// Display: Outline
|
||||||
/// Category: meta
|
/// Category: meta
|
||||||
#[node(Synthesize, Show)]
|
#[node(Synthesize, Show, LocalName)]
|
||||||
pub struct OutlineNode {
|
pub struct OutlineNode {
|
||||||
/// The title of the outline.
|
/// The title of the outline.
|
||||||
///
|
///
|
||||||
@ -91,10 +91,7 @@ impl Show for OutlineNode {
|
|||||||
let mut seq = vec![ParbreakNode::new().pack()];
|
let mut seq = vec![ParbreakNode::new().pack()];
|
||||||
if let Some(title) = self.title(styles) {
|
if let Some(title) = self.title(styles) {
|
||||||
let title = title.clone().unwrap_or_else(|| {
|
let title = title.clone().unwrap_or_else(|| {
|
||||||
TextNode::packed(match TextNode::lang_in(styles) {
|
TextNode::packed(self.local_name(TextNode::lang_in(styles)))
|
||||||
Lang::GERMAN => "Inhaltsverzeichnis",
|
|
||||||
Lang::ENGLISH | _ => "Contents",
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
seq.push(
|
seq.push(
|
||||||
@ -187,3 +184,12 @@ impl Show for OutlineNode {
|
|||||||
Ok(Content::sequence(seq))
|
Ok(Content::sequence(seq))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LocalName for OutlineNode {
|
||||||
|
fn local_name(&self, lang: Lang) -> &'static str {
|
||||||
|
match lang {
|
||||||
|
Lang::GERMAN => "Inhaltsverzeichnis",
|
||||||
|
Lang::ENGLISH | _ => "Contents",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{HeadingNode, Numbering};
|
use super::{FigureNode, HeadingNode, Numbering};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::text::TextNode;
|
use crate::text::TextNode;
|
||||||
|
|
||||||
@ -92,7 +92,9 @@ impl Show for RefNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut prefix = match self.prefix(styles) {
|
let mut prefix = match self.prefix(styles) {
|
||||||
Smart::Auto => prefix(target, TextNode::lang_in(styles))
|
Smart::Auto => target
|
||||||
|
.with::<dyn LocalName>()
|
||||||
|
.map(|node| node.local_name(TextNode::lang_in(styles)))
|
||||||
.map(TextNode::packed)
|
.map(TextNode::packed)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
Smart::Custom(None) => Content::empty(),
|
Smart::Custom(None) => Content::empty(),
|
||||||
@ -113,6 +115,13 @@ impl Show for RefNode {
|
|||||||
} else {
|
} else {
|
||||||
bail!(self.span(), "cannot reference unnumbered heading");
|
bail!(self.span(), "cannot reference unnumbered heading");
|
||||||
}
|
}
|
||||||
|
} else if let Some(figure) = target.to::<FigureNode>() {
|
||||||
|
if let Some(numbering) = figure.numbering(StyleChain::default()) {
|
||||||
|
let number = figure.number().unwrap();
|
||||||
|
numbered(vt, prefix, &numbering, &[number])?
|
||||||
|
} else {
|
||||||
|
bail!(self.span(), "cannot reference unnumbered figure");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bail!(self.span(), "cannot reference {}", target.id().name);
|
bail!(self.span(), "cannot reference {}", target.id().name);
|
||||||
};
|
};
|
||||||
@ -138,15 +147,8 @@ fn numbered(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The default prefix.
|
/// The named with which an element is referenced.
|
||||||
fn prefix(node: &Content, lang: Lang) -> Option<&str> {
|
pub trait LocalName {
|
||||||
if node.is::<HeadingNode>() {
|
/// Get the name in the given language.
|
||||||
match lang {
|
fn local_name(&self, lang: Lang) -> &'static str;
|
||||||
Lang::ENGLISH => Some("Section"),
|
|
||||||
Lang::GERMAN => Some("Abschnitt"),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,13 @@ use crate::prelude::*;
|
|||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```example
|
/// ```example
|
||||||
/// #align(center)[
|
/// #figure(
|
||||||
/// #image("molecular.jpg", width: 80%)
|
/// image("molecular.jpg", width: 80%),
|
||||||
/// *A step in the molecular testing
|
/// caption: [
|
||||||
/// pipeline of our lab*
|
/// A step in the molecular testing
|
||||||
/// ]
|
/// pipeline of our lab.
|
||||||
|
/// ],
|
||||||
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Display: Image
|
/// Display: Image
|
||||||
|
@ -142,6 +142,14 @@ impl Func {
|
|||||||
self.select(Some(fields))
|
self.select(Some(fields))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The node id of this function if it is an element function.
|
||||||
|
pub fn id(&self) -> Option<NodeId> {
|
||||||
|
match **self.0 {
|
||||||
|
Repr::Node(id) => Some(id),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Execute the function's set rule and return the resulting style map.
|
/// Execute the function's set rule and return the resulting style map.
|
||||||
pub fn set(&self, mut args: Args) -> SourceResult<StyleMap> {
|
pub fn set(&self, mut args: Args) -> SourceResult<StyleMap> {
|
||||||
Ok(match &**self.0 {
|
Ok(match &**self.0 {
|
||||||
@ -156,17 +164,16 @@ impl Func {
|
|||||||
|
|
||||||
/// Create a selector for this function's node type.
|
/// Create a selector for this function's node type.
|
||||||
pub fn select(&self, fields: Option<Dict>) -> StrResult<Selector> {
|
pub fn select(&self, fields: Option<Dict>) -> StrResult<Selector> {
|
||||||
match **self.0 {
|
let Some(id) = self.id() else {
|
||||||
Repr::Node(id) => {
|
return Err("this function is not selectable".into());
|
||||||
|
};
|
||||||
|
|
||||||
if id == item!(text_id) {
|
if id == item!(text_id) {
|
||||||
Err("to select text, please use a string or regex instead")?;
|
Err("to select text, please use a string or regex instead")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Selector::Node(id, fields))
|
Ok(Selector::Node(id, fields))
|
||||||
}
|
}
|
||||||
_ => Err("this function is not selectable")?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Func {
|
impl Debug for Func {
|
||||||
@ -196,10 +203,6 @@ impl From<NodeId> for Func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cast_to_value! {
|
|
||||||
v: NodeId => Value::Func(v.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A native Rust function.
|
/// A native Rust function.
|
||||||
pub struct NativeFunc {
|
pub struct NativeFunc {
|
||||||
/// The function's implementation.
|
/// The function's implementation.
|
||||||
|
@ -10,7 +10,9 @@ use once_cell::sync::Lazy;
|
|||||||
|
|
||||||
use super::{node, Guard, Recipe, Style, StyleMap};
|
use super::{node, Guard, Recipe, Style, StyleMap};
|
||||||
use crate::diag::{SourceResult, StrResult};
|
use crate::diag::{SourceResult, StrResult};
|
||||||
use crate::eval::{cast_from_value, Args, Cast, FuncInfo, Str, Value, Vm};
|
use crate::eval::{
|
||||||
|
cast_from_value, cast_to_value, Args, Cast, Func, FuncInfo, Str, Value, Vm,
|
||||||
|
};
|
||||||
use crate::syntax::Span;
|
use crate::syntax::Span;
|
||||||
use crate::util::pretty_array_like;
|
use crate::util::pretty_array_like;
|
||||||
use crate::World;
|
use crate::World;
|
||||||
@ -382,6 +384,15 @@ impl Deref for NodeId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cast_from_value! {
|
||||||
|
NodeId,
|
||||||
|
v: Func => v.id().ok_or("this function is not an element")?
|
||||||
|
}
|
||||||
|
|
||||||
|
cast_to_value! {
|
||||||
|
v: NodeId => Value::Func(v.into())
|
||||||
|
}
|
||||||
|
|
||||||
/// Static node for a node.
|
/// Static node for a node.
|
||||||
pub struct NodeMeta {
|
pub struct NodeMeta {
|
||||||
/// The node's name.
|
/// The node's name.
|
||||||
|
BIN
tests/ref/meta/figure.png
Normal file
BIN
tests/ref/meta/figure.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
24
tests/typ/meta/figure.typ
Normal file
24
tests/typ/meta/figure.typ
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Test figures.
|
||||||
|
|
||||||
|
---
|
||||||
|
#set page(width: 150pt)
|
||||||
|
#set figure(numbering: "I")
|
||||||
|
|
||||||
|
We can clearly see that @fig-cylinder and
|
||||||
|
@tab-complex are relevant in this context.
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
table(columns: 2)[a][b],
|
||||||
|
caption: [The basic table.],
|
||||||
|
) <tab-basic>
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
pad(y: -11pt, image("/cylinder.svg", height: 3cm)),
|
||||||
|
caption: [The basic shapes.],
|
||||||
|
numbering: "I",
|
||||||
|
) <fig-cylinder>
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
table(columns: 3)[a][b][c][d][e][f],
|
||||||
|
caption: [The complex table.],
|
||||||
|
) <tab-complex>
|
Loading…
x
Reference in New Issue
Block a user