Repository: typst/typst
File: crates/typst-library/src/model/quote.rs (Rust)

Code before:
                SmartQuoteElem::quotes_in(styles),
                TextElem::lang_in(styles),
                TextElem::region_in(styles),
                SmartQuoteElem::alternative_in(styles),
            );

            // Alternate between single and double quotes.
            let Depth(depth) = QuoteElem::depth_in(styles);
            let double = depth % 2 == 0;

            if !html {
                // Add zero-width weak spacing to make the quotes "sticky".
                let hole = HElem::hole().pack();
                realized = Content::sequence([hole.clone(), realized, hole]);
            }
            realized = Content::sequence([
                TextElem::packed(quotes.open(double)),
                realized,
                TextElem::packed(quotes.close(double)),
            ])
            .styled(QuoteElem::set_depth(Depth(1)));
        }

        if block {
            realized = if html {
                HtmlElem::new(tag::blockquote).with_body(Some(realized)).pack()
            } else {
                BlockElem::new().with_body(Some(BlockBody::Content(realized))).pack()
            }
            .spanned(self.span());

            if let Some(attribution) = self.attribution(styles).as_ref() {
                let attribution = match attribution {
                    Attribution::Content(content) => content.clone(),
                    Attribution::Label(label) => CiteElem::new(*label)
                        .with_form(Some(CitationForm::Prose))
                        .pack()
                        .spanned(self.span()),
                };
                let attribution =
                    [TextElem::packed('—'), SpaceElem::shared().clone(), attribution];

                if !html {
                    // Use v(0.9em, weak: true) to bring the attribution closer
                    // to the quote.
                    let gap = Spacing::Rel(Em::new(0.9).into());
                    let v = VElem::new(gap).with_weak(true).pack();
                    realized += v;
                }
                realized += Content::sequence(attribution).aligned(Alignment::END);
            }

Review comment (suggestion):
The `blockquote` element's `cite` attribute should be set if the value of `attribution` is a single link. 

Code after:
                SmartQuoteElem::quotes_in(styles),
                TextElem::lang_in(styles),
                TextElem::region_in(styles),
                SmartQuoteElem::alternative_in(styles),
            );

            // Alternate between single and double quotes.
            let Depth(depth) = QuoteElem::depth_in(styles);
            let double = depth % 2 == 0;

            if !html {
                // Add zero-width weak spacing to make the quotes "sticky".
                let hole = HElem::hole().pack();
                realized = Content::sequence([hole.clone(), realized, hole]);
            }
            realized = Content::sequence([
                TextElem::packed(quotes.open(double)),
                realized,
                TextElem::packed(quotes.close(double)),
            ])
            .styled(QuoteElem::set_depth(Depth(1)));
        }

        let attribution = self.attribution(styles);

        if block {
            realized = if html {
                let mut elem = HtmlElem::new(tag::blockquote).with_body(Some(realized));
                if let Some(Attribution::Content(attribution)) = attribution {
                    if let Some(link) = attribution.to_packed::<LinkElem>() {
                        if let LinkTarget::Dest(Destination::Url(url)) = &link.dest {
                            elem = elem.with_attr(
                                HtmlAttr::constant("cite"),
                                url.clone().into_inner(),
                            );
                        }
                    }
                }
                elem.pack()
            } else {
                BlockElem::new().with_body(Some(BlockBody::Content(realized))).pack()
            }
            .spanned(self.span());

            if let Some(attribution) = attribution.as_ref() {
                let attribution = match attribution {
                    Attribution::Content(content) => content.clone(),
                    Attribution::Label(label) => CiteElem::new(*label)
                        .with_form(Some(CitationForm::Prose))
                        .pack()
                        .spanned(self.span()),