diff --git a/packages/preview/bookly/4.0.1/LICENSE b/packages/preview/bookly/4.0.1/LICENSE new file mode 100644 index 0000000000..d54b2b04a1 --- /dev/null +++ b/packages/preview/bookly/4.0.1/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Mathieu Aucejo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/preview/bookly/4.0.1/README.md b/packages/preview/bookly/4.0.1/README.md new file mode 100644 index 0000000000..3d31c86c7a --- /dev/null +++ b/packages/preview/bookly/4.0.1/README.md @@ -0,0 +1,126 @@ +# Book template + +[![Generic badge](https://img.shields.io/badge/Version-4.0.1-cornflowerblue.svg)](https://github.com/maucejo/bookly/releases/tag/4.0.1) +[![MIT License](https://img.shields.io/badge/License-MIT-forestgreen)](https://github.com/maucejo/book_template/blob/708d8ca8ac2262fc77df8756835420d728b0d281/LICENSE) +[![User Manual](https://img.shields.io/badge/doc-.pdf-mediumpurple)](https://github.com/maucejo/bookly/blob/708d8ca8ac2262fc77df8756835420d728b0d281/docs/manual.pdf) + + +The `bookly` template is a Typst package designed for writing academic documents such as theses, French habilitations, or scientific books. It provides a structured format that adheres to academic standards, making it easier for authors to focus on content rather than formatting. + +## Basic usage + +This section provides the minimal amount of information to get started with the template. For more detailed information, see the [manual](https://github.com/maucejo/bookly/blob/708d8ca8ac2262fc77df8756835420d728b0d281/docs/manual.pdf). + +To use the `bookly` template, you need to include the following line at the beginning of your typ file: + +```typ +#import "@preview/bookly:4.0.1": * +``` + +After importing `bookly`, you have to initialize the template by a show rule with the `#bookly()` command. + +**Example** +```typ +#show: bookly.with( + title: "My document", + author: "Author Name", + theme: modern, + lang: "en", + tufte: false, + fonts: ( + body: "Lato", + math: "Lete Sans Math" + ), + title-page: book-title-page( + series: "Typst book series", + institution: "Typst community", + logo: image("images/typst-logo.svg"), + cover: image("images/book-cover.jpg", width: 45%) + ), + config-options: ( + open-right: true, + alt-margins: false + ) +) +``` + +## Main features + +* Themes: `classic`, `modern`, `fancy`, `obook`, `orly`, `pretty` +* Tufte layout powered by `marginalia` package +* Language support: English, Chinese, French, German, Italian, Portuguese, Spanish +* Font customization: Body, math and raw fonts can be customized +* Environments: `front-matter`, `main-matter`, `appendix`, `back-matter` +* Outlines: `tableofcontents`, `listoffigures`, `listoftables`, `minitoc` +* Part and chapter definition: `part`, `chapter`, `chapter-nonum` + +> **_Note:_** The chapters can be also written using the Typst standard markup syntax. + +## Helper functions + +* Subfigures - based on the `subpar` package + ```typ + #subfigure( + figure(image("image1.png"), caption: []), + figure(image("image2.png"), caption: []), , + columns: (1fr, 1fr), + caption: [Figure title], + label: , + ) + ``` + +* Equations + * Boxed equations + ```typ + $ + #boxeq[$p(A|B) prop p(B|A) space p(A)$] + $ + ``` + + * Unnumbered equations + ```typ + $ + integral_0^1 f(x) dif x = F(1) - F(0) + $ + ``` + + * Subequation numbering based on the `equate` package + +* Information boxes + * `#info-box` for remarks + * `#tip-box` for tips + * `#important-box` for important notes + * `proof-box` for proofs + * `question-box` for questions + * `custom-box` for user defined boxes + +* `book-title-page` for defining the title page of a book + +* `thesis-title-page` for defining the title page of a thesis + +* `back-cover` for defining the back cover of a book + +## Dependencies + +`bookly` relies on the following packages: + +* `marginalia:0.3.1`: for tufte layout. + +* `hydra:0.6.2` : for bibliography management. + +* `equate:0.3.2` : for advanced equation numbering. + +* `itemize:0.2.0"`: for lists and enumerations customization. + +* `showybox:2.0.4` : for custom boxes. + +* `suboutline:0.3.0` : for mini tables of contents in chapters. + +* `subpar:0.2.2` : for subfigures. + +## Licence + +MIT licensed + +Copyright © 2026 Mathieu AUCEJO (maucejo) + diff --git a/packages/preview/bookly/4.0.1/src/bookly-components.typ b/packages/preview/bookly/4.0.1/src/bookly-components.typ new file mode 100644 index 0000000000..b84e1754df --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/bookly-components.typ @@ -0,0 +1,92 @@ +#import "@preview/hydra:0.6.2": hydra, anchor +#import "bookly-defaults.typ": * +#import "bookly-helper.typ": * +#import "bookly-themes.typ": * + +// Chapter +#let chapter(title: none, abstract: none, toc: true, numbered: true, label: none, body) = context { + // Is the chapter numbered? + if not numbered { + numbering-heading = none + numbering-eq = "(1a)" + numbering-fig = "1" + + // Heading numbering + set heading(numbering: numbering-heading) + + // Equation numbering + set math.equation(numbering: numbering-eq) + + // Figure numbering + show figure.where(kind: image): set figure( + supplement: fig-supplement, + numbering: numbering-fig, + gap: 1.5em + ) + + // Table numbering + show figure.where(kind: table): set figure( + numbering: numbering-fig, + gap: 1.5em + ) + } + + let toc-header = states.localization.get().toc + if toc { + set page(header: anchor()) + set align(horizon) + [#heading(title)#label] + + if abstract != none { + abstract + } + + minitoc + pagebreak() + } else { + [#heading(title)#label] + } + + body + } +} + +#let chapter-nonum(body) = { + let numbering-heading = none + let numbering-eq = "(1a)" + let numbering-fig = "1" + + // Figure numbering + show figure.where(kind: image): set figure( + supplement: fig-supplement, + numbering: numbering-fig, + gap: 1.5em + ) + + // Table numbering + show figure.where(kind: table): set figure( + numbering: numbering-fig, + gap: 1.5em + ) + + // Heading numbering + set heading(numbering: numbering-heading) + + // Equation numbering + set math.equation(numbering: numbering-eq) + + // Figure numbering + show figure.where(kind: image): set figure( + supplement: fig-supplement, + numbering: numbering-fig, + gap: 1.5em + ) + + // Table numbering + show figure.where(kind: table): set figure( + numbering: numbering-fig, + gap: 1.5em + ) + + body +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/bookly-defaults.typ b/packages/preview/bookly/4.0.1/src/bookly-defaults.typ new file mode 100644 index 0000000000..791fdafcf5 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/bookly-defaults.typ @@ -0,0 +1,63 @@ +#let fig-supplement = [Figure] +#let text-size = 11pt +#let paper-size = "a4" + +#let states = ( + alt-margins: state("alt-margins", false), + author: state("author", none), + colors: state("theme-colors"), + counter-part: counter("part"), + in-outline: state("in-outline", false), + isappendix: state("isappendix", false), + isfrontmatter: state("isfrontmatter", false), + localization: state("localization"), + num-heading: state("num-heading", "1"), + num-pattern: state("num-pattern", "1.1."), + num-pattern-eq: state("num-pattern-eq", "(1.1)"), + num-pattern-fig: state("num-pattern-fig", "1.1"), + num-pattern-subfig: state("num-pattern-subfig", "1.1a"), + open-right: state("open-right", true), + page-numbering: state("page-numbering", "1/1"), + part-numbering: state("part-numbering", "1"), + sidenotecounter: counter("sidenotecounter"), + theme: state("theme"), + title: state("title", none), + tufte: state("tufte", false), +) + +#let default-language = ("en", "de", "fr", "es", "it", "pt", "zh") + +#let default-config-options = ( + part-numbering: "1", + open-right: true, + alt-margins: false +) + +#let default-fonts = ( + body: "New Computer Modern", + math: "New Computer Modern Math", + raw: "Cascadia Code" +) + +#let default-colors = ( + primary: rgb("#c1002a"), + secondary: rgb("#dddddd").darken(15%), + boxeq: rgb("#dddddd"), + header: black, +) + +// Default Title page +#let default-title-page = context { + set page( + paper: paper-size, + header: none, + footer: none, + margin: auto + ) + + align(center + horizon)[ + #text(size: 3em, fill: states.colors.get().primary)[*#states.title.get()*] + #v(1em) + #text(size: 1.5em)[#states.author.get()] + ] +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/bookly-environments.typ b/packages/preview/bookly/4.0.1/src/bookly-environments.typ new file mode 100644 index 0000000000..9502673b1c --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/bookly-environments.typ @@ -0,0 +1,75 @@ +#import "bookly-defaults.typ": * + +#let front-matter(body) = context { + set heading(numbering: none) + set page(numbering: "i") + states.page-numbering.update("i") + states.num-pattern.update(none) + states.isfrontmatter.update(true) + + if states.open-right.get() { + counter(page).update(0) + } else { + counter(page).update(1) + } + + body +} + +// Main matter +#let main-matter(body) = context { + set heading(numbering: "1.1.") + + let numbering = "1/1" + set page(numbering: numbering) + + // states.isfrontmatter.update(false) + states.page-numbering.update("1/1") + states.num-heading.update("1") + states.num-pattern.update("1.1.") + states.num-pattern-fig.update("1.1") + states.num-pattern-subfig.update("1.1a") + states.num-pattern-eq.update("(1.1a)") + + if states.open-right.get() { + counter(page).update(0) + } else { + counter(page).update(1) + } + + // To be checked + if states.isfrontmatter.get() and states.tufte.get() and states.open-right.get() { + counter(page).update(page => page + 1) + } + + body +} + +// Back matter +#let back-matter(body) = { + set page(header: none, footer: none) + + body +} + +// Appendix +#let appendix(body) = context { + set heading(numbering: "A.1.") + + // Reset heading counter + counter(heading.where(level: 1)).update(0) + + // Reset heading counter for the table of contents + counter(heading).update(0) + + // Update states for chapter function + states.isfrontmatter.update(false) + states.num-heading.update("A") + states.num-pattern.update("A.1.") + states.num-pattern-fig.update("A.1") + states.num-pattern-subfig.update("A.1a") + states.num-pattern-eq.update("(A.1a)") + states.isappendix.update(true) + + body +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/bookly-helper.typ b/packages/preview/bookly/4.0.1/src/bookly-helper.typ new file mode 100644 index 0000000000..0b02314ce1 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/bookly-helper.typ @@ -0,0 +1,381 @@ + +#import "@preview/subpar:0.2.2" +#import "@preview/suboutline:0.3.0": * +#import "bookly-defaults.typ": * + +// Reset counters +#let reset-counters = context { + counter(math.equation).update(0) + counter(figure.where(kind: image)).update(0) + counter(figure.where(kind: table)).update(0) + if states.tufte.get(){ + states.sidenotecounter.update(0) + } + counter(footnote).update(0) +} + +// Conditional set-show +#let show-if(cond, func) = body => if cond { func(body) } else { body } + +// Headings +#let headings-on-odd-page(it) = { + show heading.where(level: 1): it => { + { + set page(header: none, footer: none) + pagebreak(to: "odd") + } + it + } + it +} + +// Equations +#let _boxeq(stroke: none, fill: none, radius: 0pt, inset: 0.6em, body) = context { + set align(center) + box( + stroke: stroke, + fill: fill, + radius: radius, + inset: inset + )[#body] +} + +// Subfigure +#let subfigure = subpar.grid.with( + gap: 1em, + numbering: n => {numbering(states.num-pattern-fig.get(), counter(heading).get().first() , n)}, + numbering-sub-ref: (m, n) => {numbering(states.num-pattern-subfig.get(), counter(heading).get().first(), m, n)}, + supplement: fig-supplement, + show-sub: it => {set figure.caption(position: bottom); it} +) + +// Long and short captions for figures or tables +#let ls-caption(long, short) = context if states.in-outline.get() { short } else { long } + +// Book title page +#let book-title-page( + subtitle: "Book subtitle", + edition: "First edition", + institution: "Institution", + series: "Discipline", + year: datetime.today().year(), + cover: none, + logo: none, + version-usage: none +) = context { + let header = { + box(fill: states.colors.get().primary, width: 100%, inset: 1em)[ + #set align(center + horizon) + #text(fill: white, size: 1.5em)[#strong(delta: 400)[#series]] + ] + } + + let footer = { + box(fill: states.colors.get().primary, width: 100%, inset: 1em)[ + #set align(center + horizon) + #text(fill: white, size: 1.5em)[#strong(delta: 400)[#institution]] + ] + } + + set page( + paper: paper-size, + header: header, + footer: footer, + margin: (left: 0em, right:0em, top: 4em, bottom: 4em) + ) + + let title-page = context { + + align(horizon)[ + #move(dx: 2em)[ + #line(stroke: 1.5pt + states.colors.get().primary, length: 90%) + #v(1em) + ] + + #move(dx: 4em)[ + #text(size: 3em)[*#states.title.get()*] + #linebreak() + + #if subtitle != none { + v(0.5em) + text(size: 1.75em)[#subtitle] + linebreak() + v(0.5em) + } + + #if edition != none { + v(0.5em) + text(size: 1.25em)[_ #edition _] + linebreak() + v(0.5em) + } + + #v(0.5em) + #text(size: 1.5em)[#states.author.get()] + ] + + #move(dx: 2em)[ + #v(1em) + #line(stroke: 1.5pt + states.colors.get().primary, length: 90%) + ] + + #if cover != none { + v(1.5em) + align(center)[#cover] + } + ] + + set page( + paper: paper-size, + header: none, + footer: none, + margin: auto + ) + + if states.open-right.get() { + pagebreak(to: "odd") + } + + align(center + horizon)[ + #text(size: 3em)[*#states.title.get()*] + + #if subtitle != none { + v(-1.5em) + text(size: 1.75em)[#subtitle] + linebreak() + v(0.5em) + } + + #if edition != none { + v(0.5em) + text(size: 1.25em)[_ #edition _] + linebreak() + v(0.5em) + } + ] + + let version-info = if version-usage != none {text(size: 0.85em)[#version-usage \ #sym.copyright #states.author.get(), #year.]} else {text(size: 0.85em)[#states.localization.get().version-usage \ #sym.copyright #states.author.get(), #year.]} + + let height-ver = measure(version-info).height + + if logo != none { + set image(width: 35%) + place(bottom + center, dy: -(height-ver + 4em), logo) + } + + place(bottom)[ + #version-info + ] + } + + title-page +} + +// Thesis title page +#let thesis-title-page( + type: "phd", + school: "School name", + doctoral-school: "Name of the doctoral school", + supervisor: ("Supervisor name",), + cosupervisor: none, + laboratory: "Laboratory name", + defense-date: "01 January 1970", + discipline: "Discipline", + specialty: "Specialty", + committee: (:), + logo: none +) = context { + set page( + paper: paper-size, + header: none, + footer: none, + margin: auto + ) + + place(top + left, dx: -16%, dy: -10%, + rect(fill: states.colors.get().primary, height: 121%, width: 20%) + ) + + let title-page = { + if logo != none { + set image(width: 35%) + place(top + right, dx: 0%, dy: -15%, logo) + } + text([#states.localization.get().doctoral-school #h(0.25em) #doctoral-school], size: 1.25em) + v(0.25em) + text(school, size: 1.25em) + + v(0.25em) + text(laboratory, size: 1.25em) + v(2em) + if type.contains("phd") { + text([*#states.localization.get().phd*], size: 1.5em) + } else { + text([*#states.localization.get().habilitation*], size: 1.5em) + } + v(0.25em) + text([_ #states.localization.get().authored _ *#states.author.get()*], size: 1.15em) + v(0.25em) + text([_ #states.localization.get().defended _ *#defense-date*], size: 1.15em) + v(0.25em) + text([_ #states.localization.get().discipline _ *#discipline*], size: 1.1em) + v(0.15em) + text([_ #states.localization.get().specialty _ *#specialty*], size: 1.1em) + v(2em) + line(stroke: 1.75pt + states.colors.get().primary, length: 104%) + align(center)[#text(strong(states.title.get()), size: 2em)] + line(stroke: 1.75pt + states.colors.get().primary, length: 104%) + v(1em) + + if supervisor != none { + let n = supervisor.len() + let dir = none + if n == 1 { + if type.contains("phd") { + dir = states.localization.get().supervisor + } else { + dir = states.localization.get().sponsor + } + } else { + if type.contains("phd") { + dir = states.localization.get().supervisors + } else { + dir = states.localization.get().sponsors + } + } + + let names-dir = () + for director in supervisor { + names-dir.push(director) + } + + text(1.15em)[#dir *#names-dir.join(",", last: states.localization.get().and)*] + v(0.5em) + } + + if cosupervisor != none { + let m = cosupervisor.len() + let codir = none + if m == 1 { + if type.contains("phd") { + codir = states.localization.get().cosupervisor + } else { + codir = states.localization.get().cosponsor + } + } else { + if type.contains("phd") { + codir = states.localization.get().cosupervisors + } else { + codir = states.localization.get().cosponsors + } + } + + let names-codir = () + for codirector in cosupervisor { + names-codir.push(codirector) + } + + text(1.15em)[#codir *#names-codir.join(",", last: states.localization.get().and)*] + v(0.5em) + } + + if committee.len() > 0 { + v(1fr) + align(center)[ + #text([*#states.localization.get().committee*]) + #v(0.5em) + #set text(size: 0.9em) + #grid( + columns: 4, + column-gutter: 1.5em, + row-gutter: 1em, + align: left, + stroke: none, + ..for (name, position, affiliation, role) in committee { + ([*#name*], position, affiliation, role) + }, + ) + ] + + v(1fr) + } + } + + place(dx: 8%, dy: 11%, + block( + height: 100%, + width: 100%, + breakable: false, + title-page + ) + ) +} + +// Back cover +#let back-cover(abstracts: (), logo: none) = context{ + set page(margin: auto, header: none, footer: none) + + if states.open-right.get() { + pagebreak(to: "even", weak: true) + } + + set align(horizon) + + if logo != none { + grid(columns : logo.len(), + column-gutter: 1fr, + ..logo.map((logos) => logos) + ) + } + + context{ + v(2em) + align(center)[ + #text([*#states.author.get()*], size: 1.5em, fill: states.colors.get().primary) + + #text([*#states.title.get()*], size: 1.25em) + + #v(1em) + ] + } + + for abstract in abstracts { + context{ + block( + width: 100%, + stroke: 1pt + states.colors.get().primary, + inset: 1em, + radius: 0.5em, + below: 2em + )[ + #text([*#abstract.title * #abstract.text], size: 0.9em) + ] + } + } +} + +// Boxes - Utility +#let box-title(a, b) = { + grid(columns: 2, column-gutter: 0.5em, align: (horizon), + a, + b + ) +} + +#let colorize(svg, color) = { + let blk = black.to-hex(); + if svg.contains(blk) { + svg.replace(blk, color.to-hex()) + } else { + svg.replace(" context { + if states.tufte.get() { + wideblock(side: "both")[#it] + } else { + it + } + } + outline(title: context states.localization.get().toc, indent: 1em) +} + +// List of figures +#let listoffigures = context { + show outline.entry: it => context { + let entry = context { + let prev-outline-state = states.in-outline.get() + states.in-outline.update(true) + it + states.in-outline.update(prev-outline-state) + } + + if states.tufte.get() { + wideblock(side: "both")[#entry] + } else { + entry + } + } + outline(title: context states.localization.get().lof, target: figure.where(kind: image)) +} + +// List of tables +#let listoftables = context { + show outline.entry: it => context { + let entry = context { + let prev-outline-state = states.in-outline.get() + states.in-outline.update(true) + it + states.in-outline.update(prev-outline-state) + } + + if states.tufte.get() { + wideblock(side: "both")[#entry] + } else { + entry + } + } + outline(title: context states.localization.get().lot, target: figure.where(kind: table)) +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/bookly-themes.typ b/packages/preview/bookly/4.0.1/src/bookly-themes.typ new file mode 100644 index 0000000000..c4693a00bd --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/bookly-themes.typ @@ -0,0 +1,37 @@ +#import "bookly-defaults.typ": * +#import "themes/classic.typ": classic +#import "themes/fancy.typ": fancy +#import "themes/modern.typ": modern +#import "themes/obook.typ": obook +#import "themes/orly.typ": orly +#import "themes/pretty.typ": pretty + +// Part +#let part(title) = context (states.theme.get().part)(title) + +// Mini table of contents +#let minitoc = context states.theme.get().minitoc + +// Boxed equation +#let boxeq(content) = context (states.theme.get().boxeq)(content) + +// Custom box +#let custom-box(title: none, icon: "info", color: rgb(29, 144, 208), body) = context (states.theme.get().box)(title: title, icon: icon, color: color, body) + +// Information box +#let info-box = custom-box.with(title: context states.localization.get().note) + +// Tip box +#let tip-box = custom-box.with(title: context states.localization.get().tip, icon: "tip", color: rgb(0, 166, 81)) + +// Warning box +#let warning-box = custom-box.with(title: context states.localization.get().warning, icon: "alert", color: orange) + +// Important box +#let important-box = custom-box.with(title: "Important", icon: "stop", color: rgb("#f74242")) + +// Proof box +#let proof-box = custom-box.with(title: context states.localization.get().proof, icon: "report", color: eastern) + +// Question box +#let question-box = custom-box.with(title: "Question", icon: "question", color: purple) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/bookly-tufte.typ b/packages/preview/bookly/4.0.1/src/bookly-tufte.typ new file mode 100644 index 0000000000..024c660dac --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/bookly-tufte.typ @@ -0,0 +1,29 @@ +#import "@preview/marginalia:0.3.1" as marginalia: note, notefigure, wideblock +#import "bookly-defaults.typ": * +#import "bookly-helper.typ": * + +#let tufte-content(body) = block(width: 5cm, body) +#let margin-factor = 1.4 + +#let note = note.with( + counter: states.sidenotecounter, + numbering: (..i) => super(numbering("1", ..i)), + keep-order: true +) + +#let notefigure = notefigure.with(keep-order: true) + +#let notecite(key, supplement: none, dy: 0em, alignment: "baseline") = context { + let elems = query(bibliography) + if elems.len() > 0 { + cite(key, supplement: supplement) + note( + counter: none, + dy: dy, + alignment: alignment, + keep-order: true, + cite(key, form: "full", style: "resources/short_ref.csl")) + } else { + panic("No bibliography found. Please add a bibliography to use notecite.") + } +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/bookly.typ b/packages/preview/bookly/4.0.1/src/bookly.typ new file mode 100644 index 0000000000..2e1f5e981e --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/bookly.typ @@ -0,0 +1,162 @@ +// Exported packages +#import "@preview/equate:0.3.3": * +// Internals +#import "bookly-environments.typ": * +#import "bookly-outlines.typ": * +#import "bookly-components.typ": * +#import "bookly-helper.typ": * +#import "bookly-themes.typ": * +#import "bookly-tufte.typ": * + +// Template +#let bookly( + title: "Title", + author: "Author Name", + theme: fancy, + tufte: false, + logo: none, + lang: "en", + fonts: default-fonts, + colors: default-colors, + title-page: default-title-page, + config-options: default-config-options, + body +) = context { + // Document's properties + set document(author: author, title: title) + states.author.update(author) + states.title.update(title) + states.tufte.update(tufte) + + // Book colors + let book-colors = default-colors + colors + states.colors.update(book-colors) + + // Book theme + let bookly-theme = classic + theme + states.theme.update(bookly-theme) + + // Configuration options + let book-options = default-config-options + config-options + states.alt-margins.update(book-options.alt-margins) + states.open-right.update(book-options.open-right) + states.part-numbering.update(book-options.part-numbering) + + // Fonts + set text(font: fonts.body, lang: lang, size: text-size, ligatures: false) + + // Math font + show math.equation: set text(font: fonts.math, stylistic-set: 1) + // Unnumbered equations + show selector(): set math.equation(numbering: none) + + // Equations + show: equate.with(breakable: true, sub-numbering: true) + + // Paragraphs + set par(justify: true) + + // Localization + let bookly-lang = if default-language.contains(lang) { + lang + } else { + "en" + } + states.localization.update(json("resources/i18n/" + bookly-lang + ".json")) + + + // References + set ref(supplement: none) + + // Citations + show cite: it => { + show regex("\[|\]"): it => text(fill: black)[#it] + it + } + + // Footnotes + // show footnote.entry: it => { + // [#h(it.indent) #text(fill: book-colors.primary, it.note) #it.note.body] + // } + + // Outline entries + set outline(depth: 3) + + // Figures + let numbering-fig = n => { + let h1 = counter(heading).get().first() + numbering(states.num-pattern-fig.get(), h1, n) + } + + show figure.where(kind: image): set figure( + supplement: fig-supplement, + numbering: numbering-fig, + gap: 1.5em + ) + + set figure.caption(position: top) if tufte + show: show-if(tufte, it => { + show figure.caption.where(position: top): note.with( + alignment: "top", + counter: none, + shift: "avoid", + keep-order: true, + ) + it + }) + show figure: set figure.caption(separator: [ -- ]) + + // Equations + let numbering-eq = (..n) => { + let h1 = counter(heading).get().first() + numbering(states.num-pattern-eq.get(), h1, ..n) + } + + set math.equation(numbering: numbering-eq) + + // Tables + show figure.where(kind: table): set figure( + numbering: numbering-fig, + ) + + show figure.where(kind: table): it => { + set figure.caption(position: top) + it + } + + // Title page + if title-page != none { + title-page + } else { + default-title-page + } + + show: show-if(tufte, it => { + let marginalia-book = if book-options.alt-margins {true} else {false} + + let m-config = ( + inner: (far: 1.25cm, width: 0cm, sep: 0cm), + outer: (far: 1.25cm, width: 5cm, sep: 0.5cm), + book: marginalia-book + ) + + show: marginalia.setup.with(..m-config) + it + }) + + + // show: marginalia.show-frame.with(footer: false) + + // Headings + show: theme.theme.with(colors: book-colors) + show: show-if(book-options.open-right, it => { + show: headings-on-odd-page + it + }) + + // Unnumbered sections - Thanks to @bluss (Typst universe: How to have headings without numbers in a fluent way?) + show selector(): set heading(numbering: none) + + body +} + diff --git a/packages/preview/bookly/4.0.1/src/resources/i18n/de.json b/packages/preview/bookly/4.0.1/src/resources/i18n/de.json new file mode 100644 index 0000000000..8ead9a5915 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/i18n/de.json @@ -0,0 +1,28 @@ +{ + "and": " und ", + "appendix": "Anhang", + "authored": "vorgelegt von", + "chapter": "Kapitel", + "committee": "Zusammensetzung des Prüfungsausschusses", + "cosupervisor": "Ko-Betreuer:", + "cosupervisors": "Ko-Betreuer:", + "defended": "verteidigt am", + "discipline": "Fachrichtung:", + "doctoral-school": "GRADUIERTENSCHULE", + "habilitation": "Habilitation zur Leitung von Forschungsarbeiten", + "lof": "Abbildungsverzeichnis", + "lot": "Tabellenverzeichnis", + "note": "Hinweis", + "part": "Teil", + "phd": "Doktorarbeit", + "proof": "Beweis", + "specialty": "Spezialisierung:", + "sponsor": "Bürge:", + "sponsors": "Bürgen:", + "supervisor": "Betreuer:", + "supervisors": "Betreuer:", + "tip": "Tipp", + "toc": "Inhaltsverzeichnis", + "version-usage": "Diese Version kann kostenlos für den persönlichen Gebrauch eingesehen und heruntergeladen werden. Sie darf nicht weitergegeben, verkauft oder in abgeleiteten Arbeiten verwendet werden.", + "warning": "Warnung" +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/i18n/en.json b/packages/preview/bookly/4.0.1/src/resources/i18n/en.json new file mode 100644 index 0000000000..625016b9bd --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/i18n/en.json @@ -0,0 +1,28 @@ +{ + "and": " and ", + "appendix": "Appendix", + "authored": "authored by", + "chapter": "Chapter", + "committee": "Defense committee", + "cosupervisor": "Co-supervisor:", + "cosupervisors": "Co-supervisors:", + "defended": "defended on", + "discipline": "Discipline:", + "doctoral-school": "DOCTORAL SCHOOL", + "habilitation": "French Habilitation to supervise research", + "lof": "List of figures", + "lot": "List of tables", + "note": "Note", + "part": "Part", + "phd": "Doctoral thesis", + "proof": "Proof", + "specialty": "Specialty:", + "sponsor": "Sponsor:", + "sponsors": "Sponsors:", + "supervisor": "Supervisor:", + "supervisors": "Supervisors:", + "tip": "Tip", + "toc": "Table of contents", + "version-usage": "This version can be viewed and downloaded free of charge for personal use only. It must not be redistributed, sold, or used in derivative works.", + "warning": "Warning" +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/i18n/es.json b/packages/preview/bookly/4.0.1/src/resources/i18n/es.json new file mode 100644 index 0000000000..794f803529 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/i18n/es.json @@ -0,0 +1,28 @@ +{ + "and": " y ", + "appendix": "Apéndice", + "authored": "realizada por", + "chapter": "Capítulo", + "committee": "Tribunal de tesis", + "cosupervisor": "Codirector de tesis:", + "cosupervisors": "Codirectores de tesis:", + "defended": "defendida en", + "discipline": "Disciplina:", + "doctoral-school": "ESCUELA DE DOCTORADO", + "habilitation": "Habilitación para dirigir investigación", + "lof": "Índice de figuras", + "lot": "Índice de tablas", + "note": "Nota", + "part": "Parte", + "phd": "Tesis doctoral", + "proof": "Prueba", + "sponsor": "Financiado por:", + "sponsors": "Financiado por:", + "specialty": "Especialidad:", + "supervisor": "Director de tesis:", + "supervisors": "Directores de tesis:", + "tip": "Recomendación", + "toc": "Índice general", + "version-usage": "Esta versión puede ser consultada y descargada de forma gratuita exclusivamente para uso personal. Queda prohibida su redistribución, venta o uso en obras derivadas.", + "warning": "Advertencia" +} diff --git a/packages/preview/bookly/4.0.1/src/resources/i18n/fr.json b/packages/preview/bookly/4.0.1/src/resources/i18n/fr.json new file mode 100644 index 0000000000..e9d4e5b026 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/i18n/fr.json @@ -0,0 +1,28 @@ +{ + "and": " et ", + "appendix": "Annexe", + "authored": "présentée par", + "chapter": "Chapitre", + "committee": "Composition du jury", + "cosupervisor": "Co-encadrant :", + "cosupervisors": "Co-encadrants :", + "defended": "soutenue le", + "discipline": "Discipline :", + "doctoral-school": "ÉCOLE DOCTORALE", + "habilitation": "Habilitation à diriger des recherches", + "lof": "Table des figures", + "lot": "Table des tableaux", + "note": "Remarque", + "part": "Partie", + "phd": "Thèse de doctorat", + "proof": "Démonstration", + "specialty": "Spécialité :", + "sponsor": "Garant :", + "sponsors": "Garants :", + "supervisor": "Directeur de thèse :", + "supervisors": "Directeurs de thèse :", + "tip": "Astuce", + "toc": "Table des matières", + "version-usage": "Cette version peut être consultée et téléchargée gratuitement pour un usage personnel uniquement. Elle ne doit pas être redistribuée, vendue ou utilisée dans des travaux dérivés.", + "warning": "Attention" +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/i18n/it.json b/packages/preview/bookly/4.0.1/src/resources/i18n/it.json new file mode 100644 index 0000000000..90151d9f7d --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/i18n/it.json @@ -0,0 +1,28 @@ +{ + "and": " e ", + "appendix": "Appendice", + "authored": "presentata da", + "chapter": "Capitolo", + "committee": "Composizione della commissione", + "cosupervisor": "Co-relatore:", + "cosupervisors": "Co-relatori:", + "defended": "discussa il", + "discipline": "Disciplina:", + "doctoral-school": "SCUOLA DI DOTTORATO", + "habilitation": "Abilitazione alla direzione della ricerca", + "lof": "Elenco delle figure", + "lot": "Elenco delle tabelle", + "note": "Nota", + "part": "Parte", + "phd": "Tesi di dottorato", + "proof": "Dimostrazione", + "specialty": "Specialità:", + "sponsor": "Garante:", + "sponsors": "Garanti:", + "supervisor": "Direttore della tesi:", + "supervisors": "Direttori della tesi:", + "tip": "Suggerimento", + "toc": "Indice", + "version-usage": "Questa versione può essere consultata e scaricata gratuitamente solo per uso personale. Non deve essere ridistribuita, venduta o utilizzata in lavori derivati.", + "warning": "Attenzione" +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/i18n/pt.json b/packages/preview/bookly/4.0.1/src/resources/i18n/pt.json new file mode 100644 index 0000000000..d7f34eef37 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/i18n/pt.json @@ -0,0 +1,28 @@ +{ + "and": " e ", + "appendix": "Apêndice", + "authored": "apresentada por", + "chapter": "Capítulo", + "committee": "Composição da banca", + "cosupervisor": "Co-orientador:", + "cosupervisors": "Co-orientadores:", + "defended": "defendida em", + "discipline": "Disciplina:", + "doctoral-school": "ESCOLA DOUTORAL", + "habilitation": "Habilitação para dirigir pesquisas", + "lof": "Lista de figuras", + "lot": "Lista de tabelas", + "note": "Nota", + "part": "Parte", + "phd": "Tese de doutorado", + "proof": "Demonstração", + "specialty": "Especialidade:", + "sponsor": "Garantidor:", + "sponsors": "Garantidores:", + "supervisor": "Orientador:", + "supervisors": "Orientadores:", + "tip": "Dica", + "toc": "Sumário", + "version-usage": "Esta versão pode ser consultada e baixada gratuitamente apenas para uso pessoal. Não deve ser redistribuída, vendida ou utilizada em trabalhos derivados.", + "warning": "Atenção" +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/i18n/zh.json b/packages/preview/bookly/4.0.1/src/resources/i18n/zh.json new file mode 100644 index 0000000000..d64f0cab69 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/i18n/zh.json @@ -0,0 +1,28 @@ +{ + "and": " 和 ", + "appendix": "附录", + "authored": "作者为", + "chapter": "章节", + "committee": "答辩委员会", + "cosupervisor": "共同导师:", + "cosupervisors": "共同导师:", + "defended": "答辩时间", + "discipline": "学科:", + "doctoral-school": "博士学院", + "habilitation": "资格", + "lof": "图表目录", + "lot": "表格目录", + "note": "注释", + "part": "部分", + "phd": "博士论文", + "proof": "证明", + "specialty": "专业:", + "sponsor": "赞助商:", + "sponsors": "赞助商:", + "supervisor": "导师:", + "supervisors": "导师:", + "tip": "提示", + "toc": "目录", + "version-usage": "本版本可免费查看和下载,仅供个人使用。不得转售、转发或用于衍生作品。", + "warning": "警告" +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/images/icons/alert.svg b/packages/preview/bookly/4.0.1/src/resources/images/icons/alert.svg new file mode 100644 index 0000000000..320217dae0 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/images/icons/alert.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/images/icons/info.svg b/packages/preview/bookly/4.0.1/src/resources/images/icons/info.svg new file mode 100644 index 0000000000..ba409a6815 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/images/icons/info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/images/icons/question.svg b/packages/preview/bookly/4.0.1/src/resources/images/icons/question.svg new file mode 100644 index 0000000000..14942352e4 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/images/icons/question.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/images/icons/report.svg b/packages/preview/bookly/4.0.1/src/resources/images/icons/report.svg new file mode 100644 index 0000000000..66a48dd5a9 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/images/icons/report.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/images/icons/stop.svg b/packages/preview/bookly/4.0.1/src/resources/images/icons/stop.svg new file mode 100644 index 0000000000..670147ea47 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/images/icons/stop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/images/icons/tip.svg b/packages/preview/bookly/4.0.1/src/resources/images/icons/tip.svg new file mode 100644 index 0000000000..61ce790683 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/images/icons/tip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/resources/short_ref.csl b/packages/preview/bookly/4.0.1/src/resources/short_ref.csl new file mode 100644 index 0000000000..1e533b7c18 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/resources/short_ref.csl @@ -0,0 +1,62 @@ + + \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/themes/classic.typ b/packages/preview/bookly/4.0.1/src/themes/classic.typ new file mode 100644 index 0000000000..5053dd040f --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/themes/classic.typ @@ -0,0 +1,221 @@ + +#import "@preview/hydra:0.6.2": hydra +#import "@preview/marginalia:0.3.1" as marginalia: wideblock +#import "@preview/showybox:2.0.4": * +#import "../bookly-helper.typ": * +#import "../bookly-defaults.typ": * + +#let classic-theme(colors: default-colors, it) = { + // Headings + show heading.where(level: 1): it => { + if not states.open-right.get() { + pagebreak(weak: true) + } + + // Reset counters + reset-counters + + // Heading style + let side = auto + if states.tufte.get() { + side = "both" + } + set align(left) + show: wideblock.with(side: side) + let type-chapter = if states.isappendix.get() {states.localization.get().appendix} else {states.localization.get().chapter} + if it.numbering != none { + v(4em) + block[ + #text(size: 1.5em)[#type-chapter #counter(heading).display(states.num-heading.get())] + + #text(2em)[#it.body] + ] + v(3em) + } else { + v(1em) + text(2em)[#it.body] + v(2em) + } + } + + show heading.where(level: 2): it => { + block(above: 2em, below: 1.25em)[ + #it + ] + } + + show heading.where(level: 3): it => { + block(above: 1.25em, below: 1.25em)[ + #it + ] + } + + // Tables + show table.cell.where(y: 0): set text(weight: "bold") + set table( + stroke: (_, y) => ( + top: if y <= 1 {0.75pt} else {0pt}, + bottom: 0.75pt + ), + ) + + // Outline + set outline.entry(fill: box(width: 1fr, repeat(gap: 0.25em)[.])) + show outline.entry: it => { + show linebreak: none + if it.element.func() == heading { + let number = it.prefix() + let section = it.element.body + let item = none + if it.level == 1 { + block(above: 1.25em, below: 0em) + v(0.5em) + item = [*#number #it.inner()*] + } else if it.level == 2 { + block(above: 1em, below: 0em) + item = [#h(1em) #number #it.inner()] + } else { + block(above: 1em, below: 0em) + item = [#h(2em) #number #it.inner()] + } + link(it.element.location(), item) + } else if it.element.func() == figure { + block(above: 1.25em, below: 0em) + v(0.25em) + link(it.element.location(), [#it.prefix(). #h(0.2em) #it.inner()]) + } else { + it + } + } + + // Page style + let page-header = context { + show linebreak: none + + let length = 100% + let dy = 12% + if states.tufte.get() { + dy = 40% + } + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + if calc.odd(here().page()) { + align(left, hydra(2, display: (_, it) => [ + #let head = none + #if it.numbering != none { + head = numbering(it.numbering, ..counter(heading).at(it.location())) + " " + it.body + } else { + head = it.body + } + #head + #place(dx: 0%, dy: dy)[#line(length: length, stroke: 0.75pt)] + ])) + } else { + align(left, hydra(1, display: (_, it) => [ + #let head = counter(heading.where(level:1)).display() + " " + it.body + #if it.numbering == none { + head = it.body + } + #head + #place(dx: 0%, dy: dy)[#line(length: length, stroke: 0.75pt)] + ])) + } + + v(0.5em) + } + + let page-footer = context { + let cp = counter(page).get().first() + let current-page = counter(page).display() + + set align(center) + wideblock(side: "both", current-page) + } + + set page( + paper: paper-size, + header: page-header, + footer: page-footer + ) + + it +} + +// Boxes - Definitions +#let custom-box-classic(title: none, icon: "info", color: rgb(29, 144, 208), body) = { + showybox( + title: box-title(color-svg("resources/images/icons/" + icon + ".svg", white, width: 1em), [*#title*]), + title-style: ( + boxed-style: ( + anchor: (x: left, y: horizon), + offset: (x: -1em, y: 1.15em), + radius: (top-left: 0pt, top-right: 0pt, bottom-left: 0pt, bottom-right: 5pt) + ) + ), + frame: ( + title-color: color, + border-color: color, + body-color: color.lighten(90%), + thickness: 2pt, + body-inset: (top:2em, left: 1em, right: 1em, bottom: 1em) + ), + align: center, + breakable: true + )[#body] +} + +// Part +#let part-classic(title) = context { + states.counter-part.update(i => i + 1) + set page( + header: none, + footer: none, + numbering: none + ) + + set align(center + horizon) + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } + + wideblock(side: "both")[ + #text(size: 2.5em)[#states.localization.get().part #states.counter-part.display(states.part-numbering.get())] + #v(1em) + #text(size: 3em)[*#title*] + ] + + show heading: none + heading(numbering: none)[ + #v(1em) + #box[#states.localization.get().part #states.counter-part.display(states.part-numbering.get()) -- #title] + ] + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } +} + +#let minitoc-classic = context { + let toc-header = states.localization.get().toc + block(above: 3.5em)[ + #text([*#toc-header*]) + #v(-0.5em) + ] + + let miniline = line(stroke: 0.75pt, length: 100%) + + miniline + v(0.5em) + suboutline(target: heading.where(outlined: true, level: 2)) + miniline +} + +#let boxeq-classic(body) = context _boxeq(stroke: 0.75pt, body) + +#let classic = (theme: classic-theme, part: part-classic, minitoc: minitoc-classic, box: custom-box-classic, boxeq: boxeq-classic) + diff --git a/packages/preview/bookly/4.0.1/src/themes/fancy.typ b/packages/preview/bookly/4.0.1/src/themes/fancy.typ new file mode 100644 index 0000000000..facb6c23ab --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/themes/fancy.typ @@ -0,0 +1,248 @@ +#import "@preview/hydra:0.6.2": hydra +#import "@preview/marginalia:0.3.1" as marginalia: wideblock +#import "@preview/showybox:2.0.4": * +#import "@preview/itemize:0.2.0" as el +#import "../bookly-helper.typ": * +#import "../bookly-defaults.typ": * + +#let fancy-theme(colors: default-colors, it) = { + // Headings + show heading.where(level: 1): it => { + if not states.open-right.get() { + pagebreak(weak: true) + } + + // Reset counters + reset-counters + + // Heading style + // place(top)[ + // #rect(fill: white, width: 1%, height: 1%) + // ] + + set align(right) + set underline(stroke: 2pt + colors.secondary, offset: 8pt) + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + if it.numbering != none { + v(5em) + block[ + #text(counter(heading).display(states.num-heading.get()), size: 4em, fill: colors.primary) + #v(-3em) + #text(underline(it.body), size: 1.5em) + ] + v(5em) + } else { + v(1em) + text(underline(it.body), size: 1.5em) + v(2.5em) + } + } + + show heading.where(level: 2): it => { + block(above: 1.5em)[ + #if it.numbering != none { + text(counter(heading).display(), fill: colors.primary) + h(0.25em) + } + #text(it.body) + #v(-0.5em) + #line(stroke: 1.5pt + colors.secondary, length: 100%) + #v(0.75em) + ] + } + + show heading.where(level: 3): it => { + block[ + #if it.numbering != none { + text(counter(heading).display(), fill: colors.primary) + h(0.25em) + } + #text(it.body) + #v(1em) + ] + } + + // Lists + show: el.default-enum-list + set list(marker: [#text(fill:colors.primary, size: 1.1em)[#sym.bullet]]) + set enum(numbering: n => text(fill:colors.primary)[#n.]) + + // Footnotes + set footnote.entry(separator: line(length: 30% + 0pt, stroke: 1pt + colors.secondary)) + + // References + show ref: set text(fill: colors.primary) + + // Tables + show table.cell.where(y: 0): set text(weight: "bold", fill: white) + set table( + fill: (_, y) => if y == 0 {colors.primary} else if calc.odd(y) { colors.secondary.lighten(60%)}, + stroke: (x, y) => ( + left: if x == 0 or y > 0 { (thickness: 1pt, paint: colors.secondary) } else { (thickness: 1pt, paint: colors.primary) }, + right: (thickness: 1pt, paint: colors.secondary), + top: if y <= 1 { (thickness: 1pt, paint: colors.secondary) } else { 0pt }, + bottom: (thickness: 1pt, paint: colors.secondary), + ) + ) + + // Outline + set outline.entry(fill: box(width: 1fr, repeat(gap: 0.25em)[.])) + show outline.entry: it => { + show linebreak: none + if it.element.func() == heading { + let number = it.prefix() + let section = it.element.body + let item = none + if it.level == 1 { + block(above: 1.25em, below: 0em) + v(0.5em) + item = [#text([*#number*], fill: colors.primary) *#it.inner()*] + } else if it.level == 2{ + block(above: 1em, below: 0em) + item = [#h(1em) #text([#number], fill: colors.primary) #it.inner()] + } else { + block(above: 1em, below: 0em) + item = [#h(2em) #text([#number], fill: colors.primary) #it.inner()] + } + link(it.element.location(), item) + } else if it.element.func() == figure { + block(above: 1.25em, below: 0em) + v(0.25em) + link(it.element.location(), [#text([#it.prefix().], fill: colors.primary) #h(0.2em) #it.inner()]) + } else { + it + } + } + + // Page style + let page-header = context { + // Pas de header sur les pages d'ouverture de chapitre + let h1-on-page = query(heading.where(level: 1)).filter(h => h.location().page() == here().page()) + if h1-on-page.len() > 0 { return } + + show linebreak: none + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + set text(style: "italic", fill: colors.header) + if calc.odd(here().page()) { + align(right, hydra(2)) + } else { + align(left, hydra(1)) + } + } + + let page-footer = context { + let current-page = counter(page).display() + let page-final = counter(page).final().first() + + set align(center) + show: wideblock.with(side: "both") + if states.isfrontmatter.get() { + [#current-page] + } else { + [#current-page/#page-final] + } + } + + set page( + paper: paper-size, + header: page-header, + footer: page-footer + ) + + it +} + +// Boxes - Definitions +#let custom-box-fancy(title: none, icon: "info", color: rgb(29, 144, 208), body) = showybox( + title: grid( + columns: 2, + align: (left + horizon, right + horizon), + column-gutter: 0.5em, + [#color-svg("resources/images/icons/" + icon + ".svg", white)], + [#title] + ), + title-style: ( + boxed-style: ( + anchor: (x: left, y: horizon) + ) + ), + frame: ( + title-color: color, + border-color: color, + body-color: color.lighten(90%), + thickness: 1pt + ), + align: center +)[ + #body + #v(0.5em) +] + +// Part +#let part-fancy(title) = context { + states.counter-part.update(i => i + 1) + set page( + header: none, + footer: none, + numbering: none + ) + + set align(center + horizon) + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } + + let top-length = 80% + let mid-length = 35% + if states.tufte.get() { + top-length = 86.5% + mid-length = 38% + } + + wideblock(side: "both")[ + #line(stroke: 1.75pt + states.colors.get().primary, length: top-length) + #text(size: 2.5em)[#states.localization.get().part #states.counter-part.display(states.part-numbering.get())] + #line(stroke: 1.75pt + states.colors.get().primary, length: mid-length) + #text(size: 3em)[*#title*] + #line(stroke: 1.75pt + states.colors.get().primary, length: top-length) + ] + + show heading: none + heading(numbering: none)[ + #v(1em) + #box[#text(fill:states.colors.get().primary)[#states.localization.get().part #states.counter-part.display(states.part-numbering.get()) -- #title]] + ] + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } +} + +// Minitoc +#let minitoc-fancy = context { + let toc-header = states.localization.get().toc + block(above: 3.5em)[ + #text([*#toc-header*]) + #v(-0.5em) + ] + + let miniline = line(stroke: 1.5pt + states.colors.get().secondary, length: 100%) + + miniline + v(0.5em) + suboutline(target: heading.where(outlined: true, level: 2)) + miniline +} + +#let boxeq-fancy(body) = context _boxeq(stroke: 1pt + states.colors.get().boxeq.darken(35%), fill: states.colors.get().boxeq, radius: 5pt, body) + +#let fancy = (theme: fancy-theme, part: part-fancy, minitoc: minitoc-fancy, box: custom-box-fancy, boxeq: boxeq-fancy) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/themes/modern.typ b/packages/preview/bookly/4.0.1/src/themes/modern.typ new file mode 100644 index 0000000000..06a89c7b7f --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/themes/modern.typ @@ -0,0 +1,325 @@ +#import "@preview/hydra:0.6.2": hydra +#import "@preview/marginalia:0.3.1" as marginalia: wideblock +#import "@preview/itemize:0.2.0" as el +#import "../bookly-helper.typ": * +#import "../bookly-defaults.typ": * + +#let modern-theme(colors: default-colors, it) = { + // Headings + show heading.where(level: 1): it => context { + if not states.open-right.get() { + pagebreak(weak: true) + } + + // Reset counters + reset-counters + + // Heading style + let type-chapter = if states.isappendix.get() {states.localization.get().appendix} else {states.localization.get().chapter} + + let right-margin = marginalia.get-right() + let dxc = -right-margin.far + if it.numbering != none { + place(top, dx: dxc, dy: -11%)[ + #show: wideblock.with(side: "both") + #rect(fill: gradient.linear(colors.primary, colors.primary.transparentize(65%), dir: ltr), width: 114%, height: 35%) + ] + + place(top, dy: 10%)[ + #show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + #text(size: 2.5em, fill: white)[#type-chapter #counter(heading).display(states.num-heading.get())] + ] + + let chapter-pill = box(outset: 0.9em, radius: 50%, stroke: none, fill: states.colors.get().primary)[#text(size: 1.5em, fill: white)[#it.body]] + + let chapter-pill-height = measure(chapter-pill).height + let banner-bottom = 24% + + place(top + right, dy: banner-bottom - chapter-pill-height / 2)[ + #show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + #chapter-pill + ] + + v(15em) + } else { + place(top, dx: dxc, dy: -11%)[ + #show: wideblock.with(side: "both") + #rect(fill: gradient.linear(colors.primary, colors.primary.transparentize(65%), dir: ltr), width: 114%, height: 10%) + ] + + let chapter-pill-unnumbered = box(outset: 0.9em, radius: 50%, stroke: none,fill: colors.primary)[#text(size: 1.5em, fill: white)[#it.body]] + + let chapter-pill-unnumbered-height = measure(chapter-pill-unnumbered).height + let banner-bottom-unnumbered = -1% + + place(top + right, dy: banner-bottom-unnumbered - chapter-pill-unnumbered-height / 2)[ + #show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + #chapter-pill-unnumbered + ] + + v(3em) + } + } + + show heading.where(level: 2): it => { + block(above: 1.5em)[ + #if it.numbering != none { + text(counter(heading).display(), fill: colors.primary) + h(0.25em) + } + #text(it.body) + #v(-0.75em) + #line(stroke: 0.75pt + colors.primary, length: 100%) + #v(0.75em) + ] + } + + show heading.where(level: 3): it => { + block[ + #if it.numbering != none { + text(counter(heading).display(), fill: colors.primary) + h(0.25em) + } + #text(it.body) + #v(1em) + ] + } + + // Tables + show table.cell.where(y: 0): set text(weight: "bold", fill: white) + set table( + fill: (_, y) => if y == 0 {colors.primary} else if calc.odd(y) {colors.secondary.lighten(60%)}, + stroke: none + ) + + // Lists + show: el.default-enum-list + set list(marker: [#text(fill:colors.primary, size: 1.1em)[#sym.bullet]]) + set enum(numbering: n => text(fill:colors.primary)[#n.]) + + // Footnotes + set footnote.entry(separator: line(length: 30% + 0pt, stroke: 0.75pt + colors.primary)) + + // References + show ref: set text(fill: colors.primary) + + // Outline + set outline.entry(fill: box(width: 1fr, repeat(gap: 0.25em)[.])) + show outline.entry: it => { + show linebreak: none + if it.element.func() == heading { + let number = it.prefix() + let item = none + if it.level == 1 { + block(above: 1.25em, below: 0em) + v(0.5em) + item = [#text([*#number*], fill: colors.primary) *#it.inner()*] + } else if it.level == 2{ + block(above: 1em, below: 0em) + item = [#h(1em) #text([#number], fill: colors.primary) #it.inner()] + } else { + block(above: 1em, below: 0em) + item = [#h(2em) #text([#number], fill: colors.primary) #it.inner()] + } + link(it.element.location(), item) + } else if it.element.func() == figure { + block(above: 1.25em, below: 0em) + v(0.25em) + link(it.element.location(), [#text([#it.prefix().], fill: colors.primary) #h(0.2em) #it.inner()]) + } else { + it + } + } + + // Page style + let page-header = context { + show linebreak: none + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + set text(style: "italic", fill: colors.header) + if calc.odd(here().page()) { + align(right)[ + #hydra(2, display: (_, it) => [ + #let head = if it.numbering != none { + numbering(it.numbering, ..counter(heading).at(it.location())) + " " + it.body + } else { + it.body + } + + #grid( + columns: (1fr, auto), + column-gutter: 0.5em, + align: horizon, + [ + #stack( + dir: ltr, + line(length: 100% - 0.5em, stroke: 0.5pt + colors.primary), + circle(fill: colors.primary, stroke: none, radius: 0.25em) + ) + ], + [ + #align(right)[#head] + ] + ) + ]) + ] + } else { + align(left)[ + #hydra(1, display: (_, it) => [ + #let head = if it.numbering != none { + counter(heading.where(level:1)).display() + " " + it.body + } else { + it.body + } + + #grid( + columns: (auto, 1fr), + column-gutter: 0.5em, + align: horizon, + [ + #align(left)[#head] + ], + [ + #stack( + dir: rtl, + line(length: 100% - 0.5em, stroke: 0.5pt + colors.primary), + circle(fill: colors.primary, stroke: none, radius: 0.25em) + ) + ] + ) + ]) + ] + } + } + + let page-footer = context { + let cp = counter(page).get().first() + let current-page = counter(page).display() + set text(fill: white, weight: "bold") + v(1.5em) + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + if calc.odd(cp) { + set align(right) + box(outset: 6pt, fill: colors.primary, width: 1.5em, height: 100%)[ + #set align(center) + #current-page + ] + } else { + set align(left) + box(outset: 6pt, fill: colors.primary, width: 1.5em, height: 100%)[ + #set align(center) + #current-page + ] + } + } + + set page( + paper: paper-size, + header: page-header, + footer: page-footer + ) + + it +} + +// Boxes - Definitions +#let custom-box-modern(title: none, icon: "info", color: rgb(29, 144, 208), body) = { + grid( + columns: (auto, 1fr), + column-gutter: 0.75em, + align: top + left, + [ + #v(0.5em) + #color-svg("resources/images/icons/" + icon + ".svg", color, width: 1.5em) + ], + [ + #box( + stroke: (left: 1.25pt + color), + fill: color.lighten(90%), + inset: 1em, + width: 100% + )[#body] + ] + ) +} + +// Part +#let part-modern(title) = context { + states.counter-part.update(i => i + 1) + set page( + header: none, + footer: none, + numbering: none + ) + + set align(center + horizon) + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } + + place(top + center, dy: -11%)[ + #show: wideblock.with(side: "both") + #rect(fill: gradient.linear(states.colors.get().primary, states.colors.get().primary.transparentize(55%), dir: ttb), height: 61%, width: 114%)[ + #set align(center + horizon) + + #text(size: 5em, fill: white)[*#states.localization.get().part #states.counter-part.display(states.part-numbering.get())*] + ] + ] + + place(center + horizon)[ + #show: wideblock.with(side: "both") + #box(outset: 1.25em, stroke: none, radius: 50%, fill: states.colors.get().primary)[ + #set text(fill: white, weight: "bold", size: 3em) + #title + ] + ] + + show heading: none + heading(numbering: none)[ + #v(1em) + #box[#states.localization.get().part #states.counter-part.display(states.part-numbering.get()) -- #title] + ] + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } +} + +#let minitoc-modern = context { + let toc-header = states.localization.get().toc + block(above: 3.5em)[ + #text([*#toc-header*]) + #v(-0.5em) + ] + + let miniline = line(stroke: 0.75pt + states.colors.get().primary, length: 100%) + + miniline + v(0.5em) + suboutline(target: heading.where(outlined: true, level: 2)) + miniline +} + +#let boxeq-modern(body) = context _boxeq(stroke: 1pt + states.colors.get().primary, fill: states.colors.get().primary.lighten(90%), radius: 5pt, body) + +#let modern = (theme: modern-theme, part: part-modern, minitoc: minitoc-modern, box: custom-box-modern, boxeq: boxeq-modern) + diff --git a/packages/preview/bookly/4.0.1/src/themes/obook.typ b/packages/preview/bookly/4.0.1/src/themes/obook.typ new file mode 100644 index 0000000000..f4921584a1 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/themes/obook.typ @@ -0,0 +1,338 @@ +#import "@preview/hydra:0.6.2": hydra +#import "@preview/marginalia:0.3.1" as marginalia: wideblock +#import "@preview/itemize:0.2.0" as el +#import "../bookly-helper.typ": * +#import "../bookly-defaults.typ": * + +#let partial-outline = context { + let cur-loc = here() + + // Find the next part phantom heading (level 1 with in-outline == true) + let future-h1 = query(selector(heading.where(level: 1)).after(cur-loc, inclusive: false)) + let next-parts = future-h1.filter(h => states.in-outline.at(h.location())) + + // Build target: all outlined headings in this part, depth 2 max + let target = if next-parts.len() > 0 { + selector(heading.where(outlined: true)) + .after(cur-loc, inclusive: false) + .before(next-parts.first().location(), inclusive: false) + } else { + selector(heading.where(outlined: true)).after(cur-loc, inclusive: false) + } + + box(width: 52%, stroke: (left: 1.5pt + states.colors.get().primary), outset: 0.5em)[#outline(title: none, target: target, depth: 2)] +} + +#let obook-theme(colors: default-colors, it) = { + show heading.where(level: 1): it => context { + if not states.open-right.get() { + pagebreak(weak: true) + } + + // Reset counters + reset-counters + + // Heading style + let chap-id = if it.numbering != none {counter(heading).display(states.num-heading.get()) + ". "} else {none} + let content = grid( + columns: (auto, 1fr), + align: top + left, + [#chap-id], [#it.body] + ) + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + // Heading content + set text(size: 1.25em) + box(stroke: (right: none, rest:1.5pt + colors.primary), width: 116%, inset: 0.5em, radius: (top-right: 0pt, bottom-right: 0pt, rest: 0.5em))[#content] + + v(1em) + } + + show heading.where(level: 2): it => { + block(above: 1.5em)[ + #let text-counter = none + #let dx = 0pt + #if it.numbering != none { + text-counter = text(counter(heading).display(), fill: colors.primary) + sym.space + if not states.tufte.get() { + dx = measure(text-counter + sym.space).width + } + } + + #move(dx: -dx)[ + #text-counter + #it.body + ] + + #v(0.5em) + ] + } + + show heading.where(level: 3): it => { + block[ + #let text-counter = none + #let dx = 0pt + #if it.numbering != none { + text-counter = text(counter(heading).display(), fill: colors.primary) + sym.space + if not states.tufte.get() { + dx = measure(text-counter + sym.space).width + } + } + + #move(dx: -dx)[ + #text-counter + #it.body + ] + + #v(0.5em) + ] + } + + // Lists + show: el.default-enum-list + set list(marker: [#text(fill:colors.primary, size: 1.1em)[#sym.bullet]]) + set enum(numbering: n => text(fill:colors.primary)[#n.]) + + // References + show ref: set text(fill: colors.primary) + + // Tables + show table.cell.where(y: 0): set text(weight: "bold") + set table( + stroke: (_, y) => if y == 0 {(top: 1pt, bottom: 1pt)} else {none} + ) + show table: it => block( + stroke: (x: none, bottom: 1pt), + )[#it] + + // Outline + set outline.entry(fill: repeat([.], gap: 0.6em)) + show outline.entry: it => { + show linebreak: none + if it.element.func() == heading { + let number = it.prefix() + let is-part = states.in-outline.at(it.element.location()) + let item = none + if it.level == 1 { + block(above: 1.25em, below: 0em) + v(0.5em) + if is-part { + text([*#it.element.body*], fill: colors.primary) + } else { + item = [#text([*#number #it.inner()*], fill: colors.primary)] + } + } else if it.level == 2{ + block(above: 1em, below: 0em) + item = [#text([*#number #it.inner()*])] + } else { + block(above: 1em, below: 0em) + item = [#text([#number]) #it.inner()] + } + link(it.element.location(), item) + } else if it.element.func() == figure { + block(above: 1.25em, below: 0em) + v(0.25em) + link(it.element.location(), [#text([#it.prefix().], fill: colors.primary) #h(0.2em) #it.inner()]) + } else { + it + } + } + + show outline.entry.where(level: 2): it => { + show repeat: none + it + } + + // Page header +let page-header = context { + // Pas de header sur les pages d'ouverture de chapitre + let h1-on-page = query(heading.where(level: 1)).filter(h => h.location().page() == here().page()) + if h1-on-page.len() > 0 { return } + + show linebreak: none + + let length = 100% + let dy = 12% + if states.tufte.get() { + dy = 40% + } + + let current-page = counter(page).display() + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + if calc.odd(here().page()) { + let head = hydra(2, display: (_, it) => [ + #if it.numbering != none { + numbering(it.numbering, ..counter(heading).at(it.location())) + " " + it.body + } else { + it.body + } + ]) + grid( + columns: (1fr, 1fr), + align: (left, right), + [#head], + [#current-page] + ) + place(dx: 0%, dy: dy)[#line(length: length, stroke: 0.75pt)] + } else { + let head = hydra(1, display: (_, it) => [ + #if it.numbering != none { + counter(heading.where(level:1)).display() + " " + it.body + } else { + it.body + } + ]) + + grid( + columns: (1fr, 1fr), + align: (left, right), + [#current-page], + [*#head*] + ) + place(dx: 0%, dy: dy)[#line(length: length, stroke: 0.75pt)] + } + + v(0.5em) + } + + let page-footer = context { + let chapter-heading = query(heading.where(level: 1).before(here())).last() + + if chapter-heading.location().page() == here().page() { + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + align(center)[#counter(page).display()] + } + } + + set page( + header: page-header, + footer: page-footer + ) + it +} + +// Part +#let part-obook(title) = context { + states.counter-part.update(i => i + 1) + set page( + header: none, + footer: none, + numbering: none + ) + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } + + let part-num = text(fill: states.colors.get().primary, size: 10em, weight: "bold")[#states.counter-part.display(states.part-numbering.get())] + let part-title = text(size: 3em)[*#title*] + + align(top)[ + #show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + #grid( + columns: (1fr,)*2, + align: (top + left, top + right), + [#part-num], + [#part-title] + ) + ] + + show heading: none + states.in-outline.update(true) + heading(numbering: none)[ + #set text(size: 1.25em) + #grid( + columns: (auto, 1fr), + align: center, + column-gutter: 0.2em, + [#box(fill: states.colors.get().primary.lighten(75%), inset: 0.5em)[#states.counter-part.display(states.part-numbering.get())]], + [ + #set text(fill: white) + #box(fill: states.colors.get().primary, inset: 0.5em, width: 1fr)[*#title*] + ] + ) + ] + states.in-outline.update(false) + + align(bottom + right)[ + #show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + #partial-outline + ] + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } +} + +// Minitoc +#let minitoc-obook = context { + let toc-header = states.localization.get().toc + + let miniline = line(stroke: 1pt + states.colors.get().primary, length: 100%) + + let header = align(right)[ + #set text(fill: states.colors.get().primary) + #box(fill: states.colors.get().primary.lighten(85%),stroke: states.colors.get().primary, inset: 0.5em, radius: (top: 0.25em))[*#toc-header*] + ] + + let body = block[ + #miniline + #v(0.5em) + #suboutline(target: heading.where(outlined: true, level: 2)) + #miniline + ] + + v(3.5em) + stack( + dir: ttb, + header, + body + ) +} + +#let custom-box-obook(title: none, icon: "info", color: rgb(29, 144, 208), body) = context { + // let box-tcontent = box(fill: color.lighten(85%), inset: 0.5em, radius: (top: 0.5em), stroke: (bottom: none, rest: 1pt + color))[ + // #box-title(color-svg("resources/images/icons/" + icon + ".svg", color, width: 1em), text(fill: color)[*#title*])] + + // let box-tw = measure(box-tcontent).width + + // let box-title = align(right)[ + // #stack( + // dir: ttb, + // box-tcontent, + // move(dx: -0.5pt, line(length: box-tw - 1pt, stroke: 2pt + color.lighten(85%))) + // ) + // ] + + let box-title = move(dy: -0.5em)[#box-title(color-svg("resources/images/icons/" + icon + ".svg", color, width: 1em), text(fill: color)[*#title*])] + + let box-content = block(breakable: true, box(fill: color.lighten(85%), stroke: 1pt + color, width: 100%, inset: (top: 1em, bottom: 1em, rest: 0.5em), radius: 0.5em)[#body]) + + stack( + dir: btt, + box-content, + box-title, + ) +} + +#let boxeq-obook(body) = context _boxeq(stroke: 1pt + states.colors.get().primary, fill: states.colors.get().boxeq.lighten(30%), radius: 5pt, body) + +#let obook = (theme: obook-theme, part: part-obook, minitoc: minitoc-obook, box: custom-box-obook, boxeq: boxeq-obook) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/src/themes/orly.typ b/packages/preview/bookly/4.0.1/src/themes/orly.typ new file mode 100644 index 0000000000..819aca67d8 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/themes/orly.typ @@ -0,0 +1,196 @@ +#import "@preview/showybox:2.0.4": * +#import "@preview/hydra:0.6.2": hydra, anchor +#import "@preview/marginalia:0.3.1" as marginalia: wideblock +#import "../bookly-helper.typ": * +#import "../bookly-defaults.typ": * + +#let orly-theme(colors: default-colors, it) = { + show heading.where(level:1): it => { + if not states.open-right.get() { + pagebreak(weak: true) + } + + // Reset counters + reset-counters + + // Heading style + let type-chapter = if states.isappendix.get() {states.localization.get().appendix} else {states.localization.get().chapter} + + set align(right) + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + if it.numbering != none { + v(1em) + [ + #text(size: 1em)[#upper[#type-chapter] #counter(heading).display(states.num-heading.get())] + #v(-0.75em) + #line(length: 100%, stroke: 0.5pt) + #v(-0.1em) + #text(2em)[#it.body] + ] + } else { + [ + #line(length: 100%, stroke: 0.5pt) + #v(-0.1em) + #text(2em)[#it.body] + ] + } + v(5em) + } + + // Tables + show table.cell.where(y: 0): set text(weight: "bold", fill: white) + set table( + fill: (_, y) => if y == 0 {black} , + stroke: (_, y) => ( + top: 0pt, + bottom: 0.75pt + ), + ) + + // Outline + set outline.entry(fill: box(width: 1fr, repeat(gap: 0.25em)[.])) + show outline.entry: it => { + show linebreak: none + if it.element.func() == heading { + let number = it.prefix() + let section = it.element.body + let item = none + if it.level == 1 { + v(1em) + item = [*#number #it.inner()*] + } else if it.level == 2 { + block(above: 1em, below: 0em) + item = [#h(1em) #number #it.inner()] + } else { + block(above: 1em, below: 0em) + item = [#h(2em) #number #it.inner()] + } + link(it.element.location(), item) + } else if it.element.func() == figure { + block(above: 1.25em, below: 0em) + link(it.element.location(), [#it.prefix(). #h(0.2em) #it.inner()]) + } else { + it + } + } + + // Page style + let page-footer = context { + let cp = counter(page).get().first() + let current-page = counter(page).display() + let chapter-heading = query(heading.where(level: 1).before(here())).last() + let hcontent = none + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + set text(0.85em, weight: "bold") + line(length: 100%, stroke: 0.5pt) + v(-0.5em) + + let inset = 0.5em + if calc.odd(cp) { + let curr-box = box(stroke: (left: 0.5pt), inset: inset)[#current-page] + let hcontent = if chapter-heading.location().page() != here().page() {box(inset: inset, hydra(2))} + align(right)[#move(dy: -0.7em)[#hcontent #curr-box]] + } else { + let curr-box = box(stroke: (right: 0.5pt), inset: inset)[#current-page] + let hcontent = if chapter-heading.location().page() != here().page() {box(inset: inset, hydra(1))} + align(left)[#move(dy: -0.7em)[#curr-box #hcontent]] + } + } + + set page( + header: anchor(), + footer: page-footer, + ) + + it +} + +// Boxes - Definitions +#let custom-box-orly(title: none, icon: "info", color: rgb(29, 144, 208), body) = { + showybox( + title: box-title(color-svg("resources/images/icons/" + icon + ".svg", color, width: 1em), [*#title*]), + title-style: ( + color: color, + sep-thickness: 0pt, + ), + frame: ( + title-color: color.lighten(85%), + border-color: color, + body-color: none, + thickness: (left: 1.25pt), + radius: 0pt, + ), + breakable: true + )[#body] +} + +// Part +#let part-orly(title) = context { + states.counter-part.update(i => i + 1) + set page( + header: none, + footer: none, + numbering: none + ) + + set align(top + right) + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } + + let part = [ + #text(size: 1.75em)[*#upper[#states.localization.get().part] #states.counter-part.display(states.part-numbering.get())*] + #v(-0.75em) + #line(length: 100%, stroke: 0.5pt) + #v(-2.5em) + #text(size: 3em)[*#title*] + ] + + if states.tufte.get() {wideblock(side: "both")[#part]} else {part} + + show heading: none + heading(numbering: none)[ + #set text(1.15em) + #v(1em) + #line(length: 100%, stroke: 0.5pt) + #v(-0.5em) + #box[*#upper[#states.localization.get().part] #states.counter-part.display(states.part-numbering.get()) -- #title*] + ] + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } +} + +#let minitoc-orly = context { + let miniline = line(stroke: 0.5pt, length: 100%) + let toc-header = states.localization.get().toc + + block(above: 3.5em)[ + #set align(right) + #miniline + #v(-0.5em) + #text([*#toc-header*]) + #v(0.5em) + ] + + // miniline + v(0.5em) + suboutline(target: heading.where(outlined: true, level: 2)) + miniline +} + +#let boxeq-orly(body) = context _boxeq(stroke: 1pt, radius: 5pt, body) + +#let orly = (theme: orly-theme, part: part-orly, minitoc: minitoc-orly, box: custom-box-orly, boxeq: boxeq-orly) diff --git a/packages/preview/bookly/4.0.1/src/themes/pretty.typ b/packages/preview/bookly/4.0.1/src/themes/pretty.typ new file mode 100644 index 0000000000..8a6666f502 --- /dev/null +++ b/packages/preview/bookly/4.0.1/src/themes/pretty.typ @@ -0,0 +1,342 @@ +#import "@preview/showybox:2.0.4": * +#import "@preview/hydra:0.6.2": hydra +#import "@preview/marginalia:0.3.1" as marginalia: wideblock +#import "@preview/itemize:0.2.0" as el +#import "../bookly-helper.typ": * +#import "../bookly-defaults.typ": * + +#let pretty-theme(colors: default-colors, it) = { + // Headings + show heading.where(level: 1): it => { + if not states.open-right.get() { + pagebreak(weak: true) + } + + // Reset counters + reset-counters + + // Heading style + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + // Ugly hack + // let dy = if states.tufte.get() {-75%} else {-6%} + // place(top, dy: dy, rect(stroke: none, fill: white, width: 116%)) + + let text-size = 1.6em + set align(left) + let type-chapter = if states.isappendix.get() {states.localization.get().appendix} else {states.localization.get().chapter} + + let chapter-title = text(size: text-size)[#it.body] + if it.numbering != none { + v(2em) + + block[ + #text(size: 1.25em)[#type-chapter] + #v(-1em) + #box(stroke: (top: 1.5pt + colors.primary))[ + #context layout(area => { + let num-str = text(size: text-size, fill: white)[#counter(heading).display(states.num-heading.get())] + + // Actual width of the left column (number + inset) + let num-w = measure(box(inset: 0.5em)[#num-str]).width + + // Height of the title rendered at the effective width of the right column (total width - number column width) + let title-inset = 0.5em + let title-h = measure(block(width: area.width - num-w)[#chapter-title]).height + + // Total height of the row = title height + top inset + bottom inset + let row-h = title-h + 2 * title-inset + + // set text(1.6em) + grid( + columns: (auto, 1fr), + align: top + left, + inset: (0pt, title-inset), + box(fill: colors.primary, width: num-w, height: row-h, radius: (bottom: 0.4em))[ + #set align(center + horizon) + #text(fill: white)[#num-str] + ], + chapter-title + ) + }) + ] + ] + v(3em) + } else { + box(stroke: (top: 1.5pt + states.colors.get().primary))[ + #context layout(area => { + let bar-w = 1em // width of the decorative bar (1em content + 2x0.5em inset) + let title-inset = 0.5em + + // Height of the title rendered at the effective width of the title column (total width - bar width) + let title-h = measure(block(width: area.width - bar-w)[#chapter-title]).height + + // Total height of the row = title height + top inset + bottom inset + let row-h = title-h + 2 * title-inset + + grid( + columns: (auto, 1fr), + align: (center, left), + inset: (0pt, title-inset), + box( + fill: colors.primary, + width: bar-w, + height: row-h, + radius: (bottom: 0.4em) + ), + chapter-title + ) + }) + ] + v(1em) + } + } + + show heading.where(level: 2): it => { + block(above: 1.5em)[ + #if it.numbering != none { + text(counter(heading).display(), fill: colors.primary) + sym.space + } + #text(it.body) + #v(-0.75em) + #line(stroke: 0.75pt + colors.primary, length: 100%) + #v(0.75em) + ] + } + + show heading.where(level: 3): it => { + block[ + #if it.numbering != none { + text(counter(heading).display(), fill: colors.primary) + sym.space + } + #text(it.body) + #v(1em) + ] + } + + // Lists + show: el.default-enum-list + set list(marker: [#text(fill:colors.primary, size: 1.1em)[#sym.bullet]]) + set enum(numbering: n => text(fill:colors.primary)[#n.]) + + // Footnotes + set footnote.entry(separator: none) + show footnote.entry: it => { + box(width: 100%, stroke: (top: 0.5pt + colors.primary, left: 0.5pt + colors.primary), inset: 0.5em, radius: (top-left: 0.5em))[#it] + } + + // References + show ref: set text(fill: colors.primary) + + // Tables + show table.cell.where(y: 0): set text(weight: "bold", fill: white) + set table( + fill: (_, y) => if y == 0 {colors.primary} , + stroke: (_, y) => if y == 0 {(bottom: 0pt)} else {(bottom: 01pt + colors.secondary)} + ) + show table: it => block( + stroke: 01pt + colors.primary, + radius: 1em, + clip: true + )[#it] + + // Outline + set outline.entry(fill: none) + show outline.entry: it => { + show linebreak: none + if it.element.func() == heading { + let number = it.prefix() + let section = it.element.body + let item = none + if it.level == 1 { + block(above: 1.25em, below: 0em) + v(0.5em) + item = [#text([*#number*], fill: colors.primary) *#it.inner()*] + } else if it.level == 2{ + block(above: 1em, below: 0em) + item = [#h(1em) #text([#number], fill: colors.primary) #it.inner()] + } else { + block(above: 1em, below: 0em) + item = [#h(2em) #text([#number], fill: colors.primary) #it.inner()] + } + link(it.element.location(), item) + } else if it.element.func() == figure { + block(above: 1.25em, below: 0em) + v(0.25em) + link(it.element.location(), [#text([#it.prefix().], fill: colors.primary) #h(0.2em) #it.inner()]) + } else { + it + } + } + + // Page style + let page-header = context { + let h1-on-page = query(heading.where(level: 1)).filter(h => h.location().page() == here().page()) + if h1-on-page.len() > 0 { return } + + show linebreak: none + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + set text(style: "italic", fill: white) + if calc.odd(here().page()) { + align(right)[ + #hydra(2, display: (_, it) => [ + #let head = none + #if it.numbering != none { + head = numbering(it.numbering, ..counter(heading).at(it.location())) + " " + it.body + } else { + head = it.body + } + #box(fill: states.colors.get().primary, inset: 0.5em, radius: (top-left: 2em, bottom-right: 2em))[#head] + ]) + ] + } else { + align(left)[ + #hydra(1, display: (_, it) => [ + #let head = none + #if it.numbering != none { + head = numbering(it.numbering, ..counter(heading).at(it.location())) + " " + it.body + } else { + head = it.body + } + #box(fill: states.colors.get().primary, inset: 0.5em, radius: (bottom-left: 2em, top-right: 2em))[#head] + ]) + ] + } + } + + let page-footer = context { + let cp = counter(page).get().first() + let current-page = counter(page).display() + let dx = 0% + if states.tufte.get() { + dx = 15.04% + if states.alt-margins.get() and calc.odd(here().page()) { + dx = page.margin.outside + page.margin.inside/1.18 + } + } + set align(center) + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + grid( + columns: (1fr, auto, 1fr), + align: center + horizon, + [#line(length: 100%, stroke: 0.75pt + states.colors.get().primary)], + [#box(stroke: 1pt + states.colors.get().primary, inset: 0.3em, radius: 0.25em)[#current-page]], + [#line(length: 100%, stroke: 0.75pt + states.colors.get().primary)] + ) + // ] + } + + set page( + paper: paper-size, + header: page-header, + footer: page-footer + ) + + it +} + +// Boxes - Definitions +#let custom-box-pretty(title: none, icon: "info", color: rgb(29, 144, 208), body) = { + showybox( + title: box-title(color-svg("resources/images/icons/" + icon + ".svg", color, width: 1em), [*#title*]), + title-style: ( + color: color, + sep-thickness: 0pt, + ), + frame: ( + title-color: color.lighten(85%), + border-color: color, + body-color: none, + thickness: 0.75pt, + radius: (top-left: 2em, bottom-right: 2em, rest: 0em), + ), + breakable: true + )[#body] +} + +// Part +#let part-pretty(title) = context { + states.counter-part.update(i => i + 1) + set page( + header: none, + footer: none, + numbering: none + ) + + set align(center + horizon) + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } + + show: show-if(states.tufte.get(), it => { + show: wideblock.with(side: "both") + it + }) + + let width = if states.tufte.get() {77.9%} else {90%} + + stack( + dir: ttb, + box(fill: states.colors.get().primary, inset: 1em, radius: (top: 2em))[ + #set text(size: 4.5em, fill: white, weight: "bold") + #states.localization.get().part #states.counter-part.display(states.part-numbering.get()) + ], + box(width: width, inset: 5em, stroke: 2pt + states.colors.get().primary, radius: 2em)[ + #set text(size: 3em) + + *#title* + ]) + + show heading: none + heading(numbering: none)[ + #v(1em) + #box(width: 95%, stroke: (top: 0.5pt + states.colors.get().primary, left: 0.5pt + states.colors.get().primary), inset: 00.5em, radius: (top-left: 0.5em))[#text(fill:states.colors.get().primary)[#states.localization.get().part #states.counter-part.display(states.part-numbering.get()) -- #title]] + ] + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } +} + +// Minitoc +#let minitoc-pretty = context { + let toc-header = states.localization.get().toc + + let miniline = line(stroke: 1pt + states.colors.get().primary, length: 100%) + + let header = block[ + #set text(fill: white) + #box(fill: states.colors.get().primary, inset: 0.5em, radius: (top: 0.25em))[*#toc-header*] + ] + + let body = block[ + #miniline + #v(0.5em) + #suboutline(target: heading.where(outlined: true, level: 2)) + #miniline + ] + + v(3.5em) + stack( + dir: ttb, + header, + body + ) +} + +#let boxeq-pretty(body) = context _boxeq(stroke: 1pt + states.colors.get().primary, fill: states.colors.get().boxeq.lighten(35%), radius: (top-left: 2em, bottom-right: 2em, rest: 0em), body) + +#let pretty = (theme: pretty-theme, part: part-pretty, minitoc: minitoc-pretty, box: custom-box-pretty, boxeq: boxeq-pretty) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/appendix/app1.typ b/packages/preview/bookly/4.0.1/template/appendix/app1.typ new file mode 100644 index 0000000000..6f6f2718e3 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/appendix/app1.typ @@ -0,0 +1,39 @@ +#import "@preview/bookly:4.0.1": * +// #import "../../src/bookly.typ": * + +// #show: chapter.with( +// title: "Algorithms", +// toc: false +// ) + += Algorithms + +#lorem(100) + +Figure @fig:A is a beautiful typst logo. + +#figure( +image("../images/typst-logo.svg", width: 75%), +caption: [#lorem(10)], +) + +#figure( +table( + columns: 3, + table.header( + [Substance], + [Subcritical °C], + [Supercritical °C], + ), + [Hydrochloric Acid], + [12.0], [92.1], + [Sodium Myreth Sulfate], + [16.6], [104], + [Potassium Hydroxide], + table.cell(colspan: 2)[24.7], +), caption: [#lorem(2)] +) + +== Test + +#lorem(100) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/appendix/app2.typ b/packages/preview/bookly/4.0.1/template/appendix/app2.typ new file mode 100644 index 0000000000..58c59ceacb --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/appendix/app2.typ @@ -0,0 +1,36 @@ +#import "@preview/bookly:4.0.1": * +// #import "../../src/bookly.typ": * + +// #show: chapter.with( +// title: "Foundations", +// toc: false +// ) + += Foundations + +#lorem(100) + +$ + #boxeq($bold(y)_(k + 1) = bold(C) space.thin bold(x)_(k + 1)$) +$ + +$ +y(x) = f(x) +$ + +Figure @fig:B is an example of a figure with a caption. + +#figure( +image("../images/typst-logo.svg", width: 75%), +caption: [#lorem(10)], +) + +Figure @b3 is an example of a subfigure. + +#subfigure( +figure(image("../images/typst-logo.svg"), caption: []), +figure(image("../images/typst-logo.svg"), caption: []), , +columns: (1fr, 1fr), +caption: [(a) Left image and (b) Right image], +label: , +) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/appendix/app_main.typ b/packages/preview/bookly/4.0.1/template/appendix/app_main.typ new file mode 100644 index 0000000000..1414f92690 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/appendix/app_main.typ @@ -0,0 +1,2 @@ +#include "app1.typ" +#include "app2.typ" \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/bibliography/sample.bib b/packages/preview/bookly/4.0.1/template/bibliography/sample.bib new file mode 100644 index 0000000000..2bcdad5136 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/bibliography/sample.bib @@ -0,0 +1,20 @@ +@book{Smi21, + title = {{B}ook {T}itle}, + publisher = {Publisher}, + author = {J. M. Smith and A. B. Jones}, + year = {2021}, + edition = {7th}, +} + +@article{Jon22, + author = {A. B. Jones and J. M. Smith}, + title = {{A}rticle {T}itle}, + journal = {Journal title}, + year = {2022}, + volume = {13}, + pages = {123-456}, + number = {52}, + month = {3}, + publisher = {Publisher}, + doi = {10.1038/s41586-021-03616-x}, +} \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/bibliography/sample.yml b/packages/preview/bookly/4.0.1/template/bibliography/sample.yml new file mode 100644 index 0000000000..52af7cad0b --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/bibliography/sample.yml @@ -0,0 +1,21 @@ +Smi21: + type: Book + title: Book Title + author: ["Smith, J. M.", "Jones, A. B."] + date: 2021 + edition: 7th + publisher: Publisher + +Jon22: + type: Article + author: ["Jones, A. B.", "Smith, J. M."] + title: Article Title + page-range: 123-456 + serial-number: + doi: "10.1038/s41586-021-03616-x" + parent: + type: Periodical + title: Journal title + volume: 13 + issue: 52 + date: 2022 \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/chapters/ch1.typ b/packages/preview/bookly/4.0.1/template/chapters/ch1.typ new file mode 100644 index 0000000000..137483b053 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/chapters/ch1.typ @@ -0,0 +1,91 @@ +#import "@preview/bookly:4.0.1": * +// #import "../../src/bookly.typ": * + +// #show: chapter.with(title: "First chapter", abstract: lorem(100), label: ) + += First chapter + +#lorem(100) +#minitoc +#pagebreak() + +== Goals +#lorem(100) + +Equations @eq:1 and @eq:2 are very important. +$ +integral_0^1 f(x) dif x = F(1) - F(0) "et voilà" +$ + +$ +integral_0^1 f(x) dif x = F(1) - F(0) "et voilà" +$ + +#lorem(20) +== Code + +Figure @fig:1 is a beautiful typst logo. + +#figure( +image("../images/typst-logo.svg", width: 75%), +caption: [#ls-caption([#lorem(10)], [#lorem(2)])], +) + +Figure @fig:subfig the Typst logo. Figure @b is a Typst logo @Smi21. + +#subfigure( +figure(image("../images/typst-logo.svg"), caption: []), +figure(image("../images/typst-logo.svg"), caption: []), , +columns: (1fr, 1fr), +caption: [(a) Left image and (b) Right image], +label: , +) + +#figure( + table( + columns: 3, + table.header( + [Substance], + [Subcritical °C], + [Supercritical °C], + ), + [Hydrochloric Acid], + [12.0], [92.1], + [Sodium Myreth Sulfate], + [16.6], [104], + [Potassium Hydroxide], + table.cell(colspan: 2)[24.7], + ), caption: [#lorem(4)] +) + +== Boxes + +#lorem(10) + +=== Informations + +#info-box[ + #lorem(10) +] + +#tip-box[ + #lorem(10) +] + +#warning-box[ + #lorem(10) +] + +#important-box[ + #lorem(10) +] + +#proof-box[ + #lorem(10) +] + +#question-box[ + #lorem(10) +] + +#lorem(1000)#footnote("This is a footnote") \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/chapters/ch2.typ b/packages/preview/bookly/4.0.1/template/chapters/ch2.typ new file mode 100644 index 0000000000..15023164a1 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/chapters/ch2.typ @@ -0,0 +1,25 @@ +#import "@preview/bookly:4.0.1": * +// #import "../../src/bookly.typ": * + +// #show: chapter.with(title: "Second chapter") + += Second chapter +#minitoc +#pagebreak() + +== Goals +#lorem(100) + +$ +arrow(V)(M slash R_0) = lr((d arrow(O M))/(d t)|)_(R_0) + theta +$ + +Figure @b2 is an example of a figure with a caption @Jon22. + +#subfigure( +figure(image("../images/typst-logo.svg"), caption: []), +figure(image("../images/typst-logo.svg"), caption: []), , +columns: (1fr, 1fr), +caption: [(a) Left image and (b) Right image], +label: , +) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/chapters/ch_main.typ b/packages/preview/bookly/4.0.1/template/chapters/ch_main.typ new file mode 100644 index 0000000000..d9b462192e --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/chapters/ch_main.typ @@ -0,0 +1,4 @@ +#include "intro.typ" +#include "ch1.typ" +#include "ch2.typ" +#include "conclusion.typ" \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/chapters/conclusion.typ b/packages/preview/bookly/4.0.1/template/chapters/conclusion.typ new file mode 100644 index 0000000000..4dd8f72cea --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/chapters/conclusion.typ @@ -0,0 +1,8 @@ +#import "@preview/bookly:4.0.1": * +// #import "../../src/bookly.typ": * + +// #show: chapter.with(title: "Conclusions et perspectives", toc: false) + += Conclusions and outlooks + +#lorem(100) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/chapters/intro.typ b/packages/preview/bookly/4.0.1/template/chapters/intro.typ new file mode 100644 index 0000000000..7c194bf1cf --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/chapters/intro.typ @@ -0,0 +1,40 @@ +#import "@preview/bookly:4.0.1": * +// #import "../../src/bookly.typ": * + +// #show: chapter.with( +// title: "Introduction", +// abstract: [#lorem(50)], +// numbered: false +// ) + +#show: chapter-nonum += Introduction + +== Goals +#lorem(100) + +#lorem(25) + +$ +y = f(x) \ +g = h(x) +$ + +#v(1.25em) +=== Sub-goals + +#figure( +image("../images/typst-logo.svg", width: 75%), +caption: [#ls-caption([#lorem(10)], [#lorem(2)])], +) + +#lorem(50) (cf. Figure @fig:intro) + +#pagebreak() +== Methodology + +#lorem(1000)#footnote[#lorem(10)] + +- #lorem(20) + +- #lorem(20) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/custom-theme.typ b/packages/preview/bookly/4.0.1/template/custom-theme.typ new file mode 100644 index 0000000000..1320649f62 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/custom-theme.typ @@ -0,0 +1,187 @@ +#import "@preview/bookly:4.0.1": * +// #import "../src/bookly.typ": * +#import "@preview/marginalia:0.3.1": * +#import "@preview/suboutline:0.3.0": * + +#let custom-theme(colors: default-colors, it) = { + // Headings + show heading.where(level: 1): it => { + if not states.open-right.get() { + pagebreak(weak: true) + } + + // Reset counters + reset-counters + + // Heading style + place(top)[ + #rect(fill: white, width: 1%, height: 1%) + ] + set align(left) + let type-chapter = if states.isappendix.get() {states.localization.get().appendix} else {states.localization.get().chapter} + if it.numbering != none { + v(4em) + block[ + #text(size: 1.5em)[#type-chapter #counter(heading).display(states.num-heading.get())] + + #text(2em)[#it.body] + ] + v(3em) + } else { + v(1em) + text(2em)[#it.body] + v(2em) + } + } + + show heading.where(level: 2): it => { + block(above: 2em, below: 1.25em)[ + #it + ] + } + + show heading.where(level: 3): it => { + block(above: 1.25em, below: 1.25em)[ + #it + ] + } + + // Tables + show table.cell.where(y: 0): set text(weight: "bold") + set table( + stroke: (_, y) => ( + top: if y <= 1 {0.75pt} else {0pt}, + bottom: 0.75pt + ), + ) + + // Outline + set outline.entry(fill: box(width: 1fr, repeat(gap: 0.25em)[.])) + show outline.entry: it => { + show linebreak: none + if it.element.func() == heading { + let number = it.prefix() + let section = it.element.body + let item = none + if it.level == 1 { + block(above: 1.25em, below: 0em) + v(0.5em) + item = [*#number #it.inner()*] + } else if it.level == 2 { + block(above: 1em, below: 0em) + item = [#h(1em) #number #it.inner()] + } else { + block(above: 1em, below: 0em) + item = [#h(2em) #number #it.inner()] + } + link(it.element.location(), item) + } else if it.element.func() == figure { + block(above: 1.25em, below: 0em) + v(0.25em) + link(it.element.location(), [#it.prefix(). #h(0.2em) #it.inner()]) + } else { + it + } + } + + // Page style + let page-header = context { + show linebreak: none + show: wideblock.with(side: "both") + if calc.odd(here().page()) { + align(left, hydra(2, display: (_, it) => [ + #let head = none + #if it.numbering != none { + head = numbering(it.numbering, ..counter(heading).at(it.location())) + " " + it.body + } else { + head = it.body + } + #head + #place(dx: 0%, dy: 52%)[#line(length: 100%, stroke: 0.75pt)] + ])) + } else { + align(left, hydra(1, display: (_, it) => [ + #let head = counter(heading.where(level:1)).display() + " " + it.body + #if it.numbering == none { + head = it.body + } + #head + #place(dx: 0%, dy: 50%)[#line(length: 100%, stroke: 0.75pt)] + ])) + } + } + + let page-footer = context { + let cp = counter(page).get().first() + let current-page = counter(page).display() + let dx = 0% + if states.tufte.get() { + dx = 21.65% + } + set align(center) + move(dx: dx, current-page) + } + + set page( + paper: paper-size, + header: page-header, + footer: page-footer + ) + + it +} + + +// Part +#let custom-part(title) = context { + states.counter-part.update(i => i + 1) + set page( + header: none, + footer: none, + numbering: none + ) + + set align(center + horizon) + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } + + let dx = 0% + if states.tufte.get() { + dx = 21.68% + } + + move(dx: dx)[ + #text(size: 2.5em)[#states.localization.get().part #states.counter-part.display(states.part-numbering.get())] + #v(1em) + #text(size: 3em)[*#title*] + ] + + show heading: none + heading(numbering: none)[ + #v(1em) + #box[#states.localization.get().part #states.counter-part.display(states.part-numbering.get()) -- #title] + ] + + if states.open-right.get() { + pagebreak(weak: true, to:"odd") + } +} + +#let custom-minitoc = context { + let toc-header = states.localization.get().toc + block(above: 3.5em)[ + #text([*#toc-header*]) + #v(-0.5em) + ] + + let miniline = line(stroke: 0.75pt, length: 100%) + + miniline + v(0.5em) + suboutline(target: heading.where(outlined: true, level: 2)) + miniline +} + +#let custom = (theme: custom-theme, part: custom-part, minitoc: custom-minitoc) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/front_matter/abstract.typ b/packages/preview/bookly/4.0.1/template/front_matter/abstract.typ new file mode 100644 index 0000000000..ca23aea565 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/front_matter/abstract.typ @@ -0,0 +1,9 @@ +#import "@preview/bookly:4.0.1": * +// #import "../../src/bookly.typ": * + +// #show: chapter.with(title: "Abstract", toc: false) +#show: chapter-nonum.with() + += Abstract + +#lorem(500) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/front_matter/acknowledgments.typ b/packages/preview/bookly/4.0.1/template/front_matter/acknowledgments.typ new file mode 100644 index 0000000000..1e152c7555 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/front_matter/acknowledgments.typ @@ -0,0 +1,10 @@ +#import "@preview/bookly:4.0.1": * +// #import "../../src/bookly.typ": * + +// #show: chapter.with(title: "Acknowledgments", toc: false) +#show: chapter-nonum += Acknowledgments + +#lorem(50) + + diff --git a/packages/preview/bookly/4.0.1/template/front_matter/front_main.typ b/packages/preview/bookly/4.0.1/template/front_matter/front_main.typ new file mode 100644 index 0000000000..6e7a96abcf --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/front_matter/front_main.typ @@ -0,0 +1,2 @@ +#include "acknowledgments.typ" +#include "abstract.typ" \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/template/images/book-cover.jpg b/packages/preview/bookly/4.0.1/template/images/book-cover.jpg new file mode 100644 index 0000000000..9f913ac9c2 Binary files /dev/null and b/packages/preview/bookly/4.0.1/template/images/book-cover.jpg differ diff --git a/packages/preview/bookly/4.0.1/template/images/typst-logo.svg b/packages/preview/bookly/4.0.1/template/images/typst-logo.svg new file mode 100644 index 0000000000..055a3aa9ad --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/images/typst-logo.svg @@ -0,0 +1,227 @@ + + + + diff --git a/packages/preview/bookly/4.0.1/template/main.typ b/packages/preview/bookly/4.0.1/template/main.typ new file mode 100644 index 0000000000..734aa307c6 --- /dev/null +++ b/packages/preview/bookly/4.0.1/template/main.typ @@ -0,0 +1,81 @@ +#import "@preview/bookly:4.0.1": * +// #import "../src/bookly.typ": * +// #import "custom-theme.typ": custom + +#let config-colors = ( + primary: rgb("#1d90d0"), + secondary: rgb("#dddddd").darken(15%) +) + +#show: bookly.with( + author: "Author Name", + fonts: ( + body: "Lato", + math: "Lete Sans Math" + ), + // theme: custom, + // theme: classic, + // theme: fancy, + // theme: modern, + // theme: obook, + // theme: orly, + // theme: pretty, + // tufte: true, + lang: "en", + // colors: config-colors, + title-page: book-title-page( + series: "Typst book series", + institution: "Typst community", + logo: image("images/typst-logo.svg"), + cover: image("images/book-cover.jpg", width: 45%), + version-usage: "This is a template for writing books with Typst. It is part of the Bookly project, which provides tools and themes for book production. The template includes features such as a title page, table of contents, list of figures and tables, and support for chapters and appendices. It also includes a bibliography section for citing sources." + ), + config-options: ( + open-right: true, + // alt-margins: true, + // part-numbering: "A" + ) +) + +#show: front-matter + +#include "front_matter/front_main.typ" + +#show: main-matter + +#tableofcontents + +#listoffigures + +#listoftables + +#part([First part]) + +#include "chapters/ch_main.typ" + +#part("Second part") + +#show: appendix + +#include "appendix/app_main.typ" + +// #bibliography("bibliography/sample.yml") +#bibliography("bibliography/sample.bib") + +#let abstracts-fr-en = ( + ( + title: [#set text(lang: "fr"); Résumé :], + text: [#lorem(100)] + ), + ( + title: [#set text(lang: "en", region: "gb"); Abstract:], + text: [#lorem(100)] + ), +) + +#let logos = ( + align(left)[#image("images/typst-logo.svg", width: 50%)], + align(right)[#image("images/typst-logo.svg", width: 50%)] +) + +#back-cover(abstracts: abstracts-fr-en, logo: logos) \ No newline at end of file diff --git a/packages/preview/bookly/4.0.1/thumbnails/main.png b/packages/preview/bookly/4.0.1/thumbnails/main.png new file mode 100644 index 0000000000..f272c2d560 Binary files /dev/null and b/packages/preview/bookly/4.0.1/thumbnails/main.png differ diff --git a/packages/preview/bookly/4.0.1/typst.toml b/packages/preview/bookly/4.0.1/typst.toml new file mode 100644 index 0000000000..ea841af1cc --- /dev/null +++ b/packages/preview/bookly/4.0.1/typst.toml @@ -0,0 +1,15 @@ +[package] +name = "bookly" +version = "4.0.1" +authors = ["Mathieu Aucejo"] +license = "MIT" +description = "A clean, customizable template for writing and publishing structured books with front matter, chapters, and consistent styling." +entrypoint = "src/bookly.typ" +categories = ["book", "model"] +repository = "https://github.com/maucejo/bookly" +exclude = ["docs/manual.pdf"] + +[template] +path = "template" +entrypoint = "main.typ" +thumbnail = "thumbnails/main.png" \ No newline at end of file