mirror of
https://github.com/JustAnyones/ktu-paper.git
synced 2026-11-04 00:30:18 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efa3f8bcb0
|
||
|
|
62bf11a63f
|
||
|
|
099408aaaa
|
||
|
|
e1709a9ac5
|
||
|
|
60156860e5
|
||
|
|
eb8ea2616d
|
||
|
|
f94d6207e8
|
||
|
|
ed5a62c659
|
||
|
|
f078b8ae00
|
||
|
|
321703ddbc
|
||
|
|
c15747ce98
|
||
|
|
ada5bc3f63
|
||
|
|
e5c774f96c
|
||
|
|
b803a906ea
|
||
|
|
71b83ab97f
|
||
|
|
f8a747e6b3
|
||
|
|
dfac289590
|
||
|
|
1740adfc5a
|
||
|
|
55a236fe8b
|
No files matched your search
@@ -1,12 +1,14 @@
|
|||||||
# ktu-paper
|
# ktu-paper
|
||||||
|
|
||||||
This repository contains a Typst template for academic papers at the Kaunas University of Technology, Faculty of Informatics. A final Bachelor's thesis written with this template has successfully passed the formal review.
|
This repository contains a Typst template for academic papers at the Kaunas University of Technology, Faculty of Informatics.
|
||||||
|
|
||||||
|
I successfully wrote and defended a final Bachelor's thesis written with this template and continue to use for writing other reports.
|
||||||
|
|
||||||
## Initiating the template
|
## Initiating the template
|
||||||
Install the downloaded template under the following directory:
|
Install the downloaded template under the following directory:
|
||||||
- LINUX: `~/.local/share/typst/packages/local/ktu-paper/0.3.1/`
|
- Linux: `~/.local/share/typst/packages/local/ktu-paper/0.5.1/`
|
||||||
|
|
||||||
And then initiate a new project:
|
And then initiate a new project:
|
||||||
```sh
|
```sh
|
||||||
typst init @local/ktu-paper:0.3.1
|
typst init @local/ktu-paper:0.5.1
|
||||||
```
|
```
|
||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
/// Whether to number figures per section or not.
|
/// Whether to number figures per section or not.
|
||||||
/// If true, figures will be numbered like "1.1", "1.2", "2.1", etc.
|
/// If true, figures will be numbered like "1.1", "1.2", "2.1", etc.
|
||||||
/// If false, figures will be numbered like "1", "2", "3", etc.
|
/// If false, figures will be numbered like "1", "2", "3", etc.
|
||||||
///
|
///
|
||||||
/// TODO: figure out how to deal with numbering on sections such as
|
/// TODO: figure out how to deal with numbering on sections such as
|
||||||
/// Appendix and other non-standard sections.
|
/// Appendix and other non-standard sections.
|
||||||
#let __FIG_PER_SECTION = state("svetikas.lt/ktu-paper/figure-numbering-per-section", false)
|
#let __FIG_PER_SECTION = state("svetikas.lt/ktu-paper/figure-numbering-per-section", false)
|
||||||
@@ -13,10 +13,10 @@
|
|||||||
|
|
||||||
#let __DEBUG_AUTHOR_TABLE = state("$ktu-template-DEBUG_AUTHOR_TABLE", false)
|
#let __DEBUG_AUTHOR_TABLE = state("$ktu-template-DEBUG_AUTHOR_TABLE", false)
|
||||||
#let debug-author-table() = {
|
#let debug-author-table() = {
|
||||||
__DEBUG_AUTHOR_TABLE.update(true)
|
__DEBUG_AUTHOR_TABLE.update(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let __HEADING_EXPERIMENT = state("$ktu-template-HEADING_EXPERIMENT", false)
|
#let __HEADING_EXPERIMENT = state("$ktu-template-HEADING_EXPERIMENT", false)
|
||||||
#let enable-heading-experiment() = {
|
#let enable-heading-experiment() = {
|
||||||
__HEADING_EXPERIMENT.update(true)
|
__HEADING_EXPERIMENT.update(true)
|
||||||
}
|
}
|
||||||
+451
-107
@@ -1,137 +1,481 @@
|
|||||||
// This file includes logic for displaying figures in the document, including numbering, captions, and references. It also includes logic for handling figure numbering per section or globally, based on the configuration set in `config.typ`.
|
// This file includes logic for displaying figures in the document, including numbering, captions, and references. It also includes logic for handling figure numbering per section or globally, based on the configuration set in `config.typ`.
|
||||||
#import "config.typ": __FIG_PER_SECTION
|
#import "config.typ": __FIG_PER_SECTION
|
||||||
|
|
||||||
/// Localizations for various recognized referenceable figure types.
|
// ---------------------------------------------------------------------------
|
||||||
/// This is used to provide the correct supplement text for each type of figure
|
// Figure kinds
|
||||||
/// when generating references, captions and outlines.
|
// ---------------------------------------------------------------------------
|
||||||
#let __figureNames = (
|
|
||||||
table: (
|
/// Localizations for the recognized referenceable figure kinds, keyed by `repr(func)`.
|
||||||
supplement: "lentelė",
|
/// - supplement: used in captions (the caption adds the separator, e.g. "1 pav.").
|
||||||
),
|
/// - ref-name: used in references, e.g. "(žr. 1 pav.)". Either a string or a
|
||||||
image: (
|
/// function `count => string`, called with the number of elements mentioned
|
||||||
supplement: "pav",
|
/// together, e.g. "(žr. 1 priedą)" vs "(žr. 1, 2 priedus)".
|
||||||
),
|
/// - single-name: full word used when the figure is the only one of its kind and
|
||||||
raw: (
|
/// therefore unnumbered, e.g. "Paveikslas. ..." and "(žr. paveikslas)".
|
||||||
supplement: "kodo frag",
|
#let __figure-kinds = (
|
||||||
),
|
table: (supplement: "lentelė", ref-name: "lentelė", single-name: "lentelė"),
|
||||||
equation: (
|
image: (supplement: "pav", ref-name: "pav.", single-name: "paveikslas"),
|
||||||
supplement: "lygtis",
|
raw: (supplement: "kodo frag", ref-name: "kodo frag.", single-name: "kodo fragmentas"),
|
||||||
),
|
equation: (supplement: "lygtis", ref-name: "formulė", single-name: "lygtis"),
|
||||||
|
// Appendices are headings, not figures, but they use the same referencing
|
||||||
|
appendix: (
|
||||||
|
supplement: "priedas",
|
||||||
|
ref-name: count => if count == 1 { "priedą" } else { "priedus" },
|
||||||
|
single-name: "priedas",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
/// Helper function to get the supplement text for a given figure type.
|
/// Figure kinds registered by the document author via `ktu-paper(figureKinds: ...)`.
|
||||||
#let __fig-supplement(func) = {
|
#let __USER_FIGURE_KINDS = state("ktu-user-figure-kinds", (:))
|
||||||
return __figureNames.at(repr(func)).supplement
|
|
||||||
|
/// Validates author-supplied kinds and fills in defaults (`ref-name` falls back
|
||||||
|
/// to `supplement`).
|
||||||
|
#let __normalize-figure-kinds(kinds) = {
|
||||||
|
let normalized = (:)
|
||||||
|
for (key, spec) in kinds {
|
||||||
|
assert(
|
||||||
|
"supplement" in spec,
|
||||||
|
message: "figure kind `" + key + "` needs a `supplement`",
|
||||||
|
)
|
||||||
|
normalized.insert(key, (
|
||||||
|
supplement: spec.supplement,
|
||||||
|
ref-name: spec.at("ref-name", default: spec.supplement),
|
||||||
|
single-name: spec.at("single-name", default: spec.supplement),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
normalized
|
||||||
}
|
}
|
||||||
|
|
||||||
#let __fig-func-to-name(func) = {
|
/// Recognized kinds merged with the author's. Must be called in a context.
|
||||||
if func == table {
|
#let __all-figure-kinds() = __figure-kinds + __USER_FIGURE_KINDS.get()
|
||||||
return "lentelė"
|
|
||||||
}
|
/// Resets all figure and equation counters (used when numbering per section).
|
||||||
if func == image {
|
/// Must be called in a context.
|
||||||
return "pav."
|
#let __reset-figure-counters() = {
|
||||||
}
|
let custom = (..__USER_FIGURE_KINDS.get().keys(),)
|
||||||
if func == grid {
|
for kind in (image, table, raw, ..custom) {
|
||||||
return "pav."
|
counter(figure.where(kind: kind)).update(0)
|
||||||
}
|
}
|
||||||
return func
|
counter(math.equation).update(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to resolve figure numbers (either global "1" or section-based "1.1").
|
/// Returns the caption supplement text for a figure kind (e.g. `table`, `math.equation`).
|
||||||
/// It takes a figure item and referenced location and returns the appropriate number as a string.
|
#let __fig-supplement(func) = __figure-kinds.at(repr(func)).supplement
|
||||||
|
|
||||||
|
/// Finds the first recognized kind ("table", "image", "raw" or "equation") inside
|
||||||
|
/// `node`, descending through wrappers (align, block, grid, stack, ...).
|
||||||
|
/// Returns the key into `__figure-kinds`, or `none` if nothing is recognized.
|
||||||
|
#let __find-figure-kind(node) = {
|
||||||
|
if type(node) != content { return none }
|
||||||
|
|
||||||
|
let key = repr(node.func())
|
||||||
|
if key in __figure-kinds { return key }
|
||||||
|
|
||||||
|
// Single-child wrappers
|
||||||
|
for field in ("body", "child") {
|
||||||
|
if node.has(field) {
|
||||||
|
let found = __find-figure-kind(node.at(field))
|
||||||
|
if found != none { return found }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-child containers
|
||||||
|
if node.has("children") {
|
||||||
|
for child in node.children {
|
||||||
|
let found = __find-figure-kind(child)
|
||||||
|
if found != none { return found }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
none
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the `__figure-kinds` key of a figure element. An explicit custom
|
||||||
|
/// (string) kind always wins; otherwise the kind is detected from the body.
|
||||||
|
#let __figure-key(fig) = {
|
||||||
|
if type(fig.kind) == str { return fig.kind }
|
||||||
|
let found = __find-figure-kind(fig.body)
|
||||||
|
if found != none { found } else { repr(fig.kind) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the caption supplement of a figure element.
|
||||||
|
#let __figure-supplement-of(fig) = {
|
||||||
|
let key = __figure-key(fig)
|
||||||
|
let kinds = __all-figure-kinds()
|
||||||
|
assert(
|
||||||
|
key in kinds,
|
||||||
|
message: "unregistered figure kind `" + key + "`: register it with ktu-paper(figureKinds: ...)",
|
||||||
|
)
|
||||||
|
kinds.at(key).supplement
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Numbering
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Resolves a figure's number (global "1" or section-based "1.1") at `loc`,
|
||||||
|
/// returned as a string.
|
||||||
#let __get-figure-number(fig-item, loc) = {
|
#let __get-figure-number(fig-item, loc) = {
|
||||||
if type(fig-item) != content {
|
assert(
|
||||||
panic("can only get figure number for content elements")
|
type(fig-item) == content and fig-item.func() == figure,
|
||||||
}
|
message: "can only get figure number for figure elements",
|
||||||
|
)
|
||||||
|
|
||||||
if fig-item.func() != figure {
|
let fig-counter = counter(figure.where(kind: fig-item.kind))
|
||||||
panic("can only get figure number for figure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
let perSection = __FIG_PER_SECTION.at(loc)
|
if __FIG_PER_SECTION.at(loc) {
|
||||||
if perSection {
|
let chapter = counter(heading).at(loc).at(0, default: 0)
|
||||||
let chapter = counter(heading).at(loc).at(0, default: 0)
|
let fig-num = fig-counter.at(loc).at(0, default: 1)
|
||||||
let figNum = counter(figure.where(kind: fig-item.kind)).at(loc).at(0, default: 1)
|
str(chapter) + "." + str(fig-num)
|
||||||
str(chapter) + "." + str(figNum)
|
} else {
|
||||||
} else {
|
str(fig-counter.at(loc).at(0))
|
||||||
let caption = fig-item.caption
|
}
|
||||||
if caption != none and caption.numbering != none {
|
|
||||||
str(caption.counter.at(loc).at(0))
|
|
||||||
} else {
|
|
||||||
str(counter(figure.where(kind: fig-item.kind)).at(loc).at(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to get the number of a locatable element (figure, table, etc.)
|
/// Resolves an equation's number (global "2" or section-based "1.2") at `loc` without parentheses.
|
||||||
/// based on its location in the document. It returns the number as a string, formatted according to the current numbering scheme.
|
/// `loc` is the location of the equation.
|
||||||
|
#let __get-equation-number(loc) = {
|
||||||
|
let number = counter(math.equation).at(loc).at(0)
|
||||||
|
if __FIG_PER_SECTION.at(loc) {
|
||||||
|
let chapter = counter(heading).at(loc).at(0, default: 0)
|
||||||
|
str(chapter) + "." + str(number)
|
||||||
|
} else {
|
||||||
|
str(number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Numbering function for `math.equation`: "(2)" or, when numbering per
|
||||||
|
/// section, "(1.2)".
|
||||||
|
#let __equation-numbering(..nums) = context {
|
||||||
|
let number = nums.pos().first()
|
||||||
|
if __FIG_PER_SECTION.get() {
|
||||||
|
let chapter = counter(heading).get().at(0, default: 0)
|
||||||
|
// TODO: this is a hack to prevent the numbers from being completely
|
||||||
|
// part of a regex match against math.equation.
|
||||||
|
// It would be better to render math equation numbers as a separate element, so that regexes don't see them at all.
|
||||||
|
[(#box[#chapter].#box[#number])]
|
||||||
|
} else {
|
||||||
|
[(#number)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of a located figure element as a string, formatted
|
||||||
|
/// according to the current numbering scheme.
|
||||||
#let __get-locatable-element-number(element) = context {
|
#let __get-locatable-element-number(element) = context {
|
||||||
if type(element) != content {
|
assert(type(element) == content, message: "can only reference elements of type content")
|
||||||
panic("can only reference elements of type content")
|
assert(element.func() == figure, message: "referenced element does not have a figure function")
|
||||||
}
|
__get-figure-number(element, element.location())
|
||||||
let loc = element.location()
|
|
||||||
let elem = query(loc)
|
|
||||||
let fig = elem.at(0)
|
|
||||||
if fig.func() != figure {
|
|
||||||
panic("referenced element does not have a figure function")
|
|
||||||
}
|
|
||||||
__get-figure-number(fig, loc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats a reference to a figure, table, or other numbered element.
|
/// Appendix headings carry an "appendix-heading" metadata marker as their
|
||||||
#let __format-ref(it) = {
|
/// first child (or as their whole body, when the appendix has no title) and
|
||||||
let el = it.element
|
/// are numbered separately from normal headings.
|
||||||
if el == none {
|
#let __is-appendix-heading(item) = {
|
||||||
return it
|
let body = item.body
|
||||||
|
if body.has("children") {
|
||||||
|
body.children.at(0, default: none) == metadata("appendix-heading")
|
||||||
|
} else {
|
||||||
|
body == metadata("appendix-heading")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the title of an appendix heading element (everything after the
|
||||||
|
/// marker), or `none` if the appendix has no title.
|
||||||
|
#let __appendix-title(item) = {
|
||||||
|
let body = item.body
|
||||||
|
if not body.has("children") { return none }
|
||||||
|
let rest = body.children.slice(1)
|
||||||
|
if rest.len() == 0 { none } else { rest.join() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number (int) of an appendix heading element: its position among
|
||||||
|
/// all appendices, in document order. Must be called in a context.
|
||||||
|
#let __appendix-number(item) = {
|
||||||
|
query(selector(heading).before(item.location(), inclusive: true))
|
||||||
|
.filter(h => __is-appendix-heading(h))
|
||||||
|
.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a dotted number such as "12" or "1.12.5" into an array of ints.
|
||||||
|
/// Returns `none` if any part is not purely numeric.
|
||||||
|
#let __parse-number(value) = {
|
||||||
|
let parts = value.split(".")
|
||||||
|
if parts.all(p => p.match(regex("^\\d+$")) != none) {
|
||||||
|
parts.map(int)
|
||||||
|
} else {
|
||||||
|
none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sorts `(location, number)` entries. If every number is numeric (optionally
|
||||||
|
/// dotted, e.g. "1.12.5"), sorts component-wise numerically; otherwise falls
|
||||||
|
/// back to plain string ordering.
|
||||||
|
#let __sort-entries(entries) = {
|
||||||
|
let keys = entries.map(e => __parse-number(e.at(1)))
|
||||||
|
if keys.all(k => k != none) {
|
||||||
|
entries.zip(keys).sorted(key: pair => pair.at(1)).map(pair => pair.at(0))
|
||||||
|
} else {
|
||||||
|
entries.sorted(key: e => e.at(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Single-figure handling
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Figure kinds that are left unnumbered when the document contains only one
|
||||||
|
/// captioned figure of that kind: "Lentelė. Aprašas" and "(žr. lentelė)"
|
||||||
|
/// instead of "1 lentelė. Aprašas" and "(žr. 1 lentelė)". The word used comes
|
||||||
|
/// from the kind's `single-name`.
|
||||||
|
/// Keys are `__figure-key` values.
|
||||||
|
#let __UNNUMBERED_WHEN_SINGLE = ("table", "image")
|
||||||
|
|
||||||
|
/// Whether `fig` is the only captioned figure of its kind in the document and
|
||||||
|
/// its kind is listed in `__UNNUMBERED_WHEN_SINGLE`. Must be called in a context.
|
||||||
|
#let __is-single-unnumbered(fig) = {
|
||||||
|
if __figure-key(fig) not in __UNNUMBERED_WHEN_SINGLE { return false }
|
||||||
|
query(figure.where(kind: fig.kind)).filter(f => f.caption != none).len() == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Capitalizes the first letter of `value` ("lentelė" -> "Lentelė").
|
||||||
|
#let __capitalize(value) = {
|
||||||
|
let first = value.first()
|
||||||
|
upper(first) + value.slice(first.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Caption label of a figure element: "1 lentelė." normally, or
|
||||||
|
/// "Lentelė." for a single unnumbered figure.
|
||||||
|
#let __caption-label(fig) = context {
|
||||||
|
let supplement = __figure-supplement-of(fig)
|
||||||
|
if __is-single-unnumbered(fig) {
|
||||||
|
let name = __all-figure-kinds().at(__figure-key(fig)).single-name
|
||||||
|
[#__capitalize(name).]
|
||||||
|
} else {
|
||||||
|
[#__get-figure-number(fig, fig.location()) #supplement.]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// References
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns a number for the given reference target.
|
||||||
|
/// Panics for a figure that is the only one of its kind,
|
||||||
|
/// since such figures have no number.
|
||||||
|
/// - target (label): Label to get the reference number for.
|
||||||
|
#let ref-no(target) = context {
|
||||||
|
if type(target) != label {
|
||||||
|
panic("ref-no expects a label as input")
|
||||||
|
}
|
||||||
|
|
||||||
|
let item = query(target).first()
|
||||||
|
let loc = item.location()
|
||||||
|
let kind = item.func()
|
||||||
|
|
||||||
|
let number = if kind == figure {
|
||||||
|
if __is-single-unnumbered(item) {
|
||||||
|
panic(
|
||||||
|
"ref-no: "
|
||||||
|
+ str(target)
|
||||||
|
+ " is the only "
|
||||||
|
+ __figure-key(item)
|
||||||
|
+ " in the document and is therefore unnumbered; "
|
||||||
|
+ "refer to it with @"
|
||||||
|
+ str(target)
|
||||||
|
+ " (or custom-ref) instead",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
__get-figure-number(item, loc)
|
||||||
|
} else if kind == math.equation {
|
||||||
|
"(" + __get-equation-number(loc) + ")"
|
||||||
|
} else if kind == heading {
|
||||||
|
if __is-appendix-heading(item) {
|
||||||
|
str(__appendix-number(item))
|
||||||
|
} else {
|
||||||
|
counter(heading).at(loc).map(str).join(".")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic("referencing unknown type: " + repr(kind))
|
||||||
|
}
|
||||||
|
|
||||||
|
link(loc, number)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a custom reference for multiple targets of the same type.
|
||||||
|
/// - targets (label...): Labels to create a custom reference for.
|
||||||
|
#let custom-ref(..targets) = context {
|
||||||
|
let group-key = none
|
||||||
|
let group-name = none // a string, or a function of the number of mentions
|
||||||
|
let single-name = none // set when the target is a lone, unnumbered figure
|
||||||
|
let entries = () // (location, number) pairs
|
||||||
|
|
||||||
|
for target in targets.pos() {
|
||||||
|
let item = query(target).first()
|
||||||
|
let loc = item.location()
|
||||||
|
|
||||||
|
// (kind key used for grouping, ref-name spec, number)
|
||||||
|
let (key, name, number) = if item.func() == math.equation {
|
||||||
|
("equation", __figure-kinds.equation.ref-name, __get-equation-number(loc))
|
||||||
|
} else if item.func() == figure {
|
||||||
|
let kind = __figure-key(item)
|
||||||
|
let kinds = __all-figure-kinds()
|
||||||
|
if kind not in kinds {
|
||||||
|
panic("unregistered figure kind `" + kind + "`: register it with ktu-paper(figureKinds: ...)")
|
||||||
|
}
|
||||||
|
if __is-single-unnumbered(item) { single-name = kinds.at(kind).single-name }
|
||||||
|
(kind, kinds.at(kind).ref-name, __get-figure-number(item, loc))
|
||||||
|
} else if item.func() == heading and __is-appendix-heading(item) {
|
||||||
|
("appendix", __figure-kinds.appendix.ref-name, str(__appendix-number(item)))
|
||||||
|
} else {
|
||||||
|
panic("referencing unknown type: " + repr(item.func()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override equation references
|
if group-key != none and group-key != key {
|
||||||
if el.func() == math.equation {
|
panic("custom-ref does not support grouping different elements together")
|
||||||
link(
|
|
||||||
el.location(),
|
|
||||||
numbering(el.numbering, ..counter(math.equation).at(el.location()))
|
|
||||||
)
|
|
||||||
// Override references to figures
|
|
||||||
} else if el.func() == figure {
|
|
||||||
let fig = el.body
|
|
||||||
let figType = fig.func()
|
|
||||||
let numStr = __get-figure-number(el, el.location())
|
|
||||||
link(el.location(), [
|
|
||||||
(žr. #numStr #__fig-func-to-name(figType))
|
|
||||||
])
|
|
||||||
} else {
|
|
||||||
it
|
|
||||||
}
|
}
|
||||||
|
group-key = key
|
||||||
|
group-name = name
|
||||||
|
entries.push((loc, number))
|
||||||
|
}
|
||||||
|
|
||||||
|
if entries.len() > 0 {
|
||||||
|
if single-name != none {
|
||||||
|
// The only figure of its kind: no number, e.g. "(žr. lentelė)"
|
||||||
|
[(žr. #link(entries.first().at(0), single-name))]
|
||||||
|
} else {
|
||||||
|
let links = __sort-entries(entries).map(e => link(e.at(0), e.at(1)))
|
||||||
|
let name = if type(group-name) == function { group-name(entries.len()) } else { group-name }
|
||||||
|
[(žr. #links.join(", ") #name)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show rule for `@label` references. Equations render as a bare "(1.2)";
|
||||||
|
/// figures delegate to `custom-ref`, so "(žr. 1 pav.)" is built in one place.
|
||||||
|
/// Anything else (headings, citations, unregistered figure kinds) keeps
|
||||||
|
/// Typst's default rendering.
|
||||||
|
#let __format-ref(it) = {
|
||||||
|
let el = it.element
|
||||||
|
if el == none { return it }
|
||||||
|
|
||||||
|
if el.func() == math.equation {
|
||||||
|
let loc = el.location()
|
||||||
|
link(loc, "(" + __get-equation-number(loc) + ")")
|
||||||
|
} else if el.func() == figure and __figure-key(el) in __all-figure-kinds() {
|
||||||
|
custom-ref(it.target)
|
||||||
|
} else if el.func() == heading and __is-appendix-heading(el) {
|
||||||
|
custom-ref(it.target)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Figure layout
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Default layout per figure kind (keyed like `__figure-kinds`; custom kinds
|
||||||
|
/// and unlisted ones use `__FALLBACK_FIGURE_LAYOUT`).
|
||||||
|
/// - breakable: whether the body may be split across pages. The caption is then
|
||||||
|
/// attached to the start of the body (sticky), so it is never left alone at
|
||||||
|
/// the bottom of a page. If `false`, body and caption form one unbreakable
|
||||||
|
/// block that moves to the next page as a whole.
|
||||||
|
/// - caption: `top` or `bottom`.
|
||||||
|
#let __DEFAULT_FIGURE_LAYOUT = (
|
||||||
|
table: (breakable: true, caption: top),
|
||||||
|
raw: (breakable: true, caption: bottom),
|
||||||
|
)
|
||||||
|
#let __FALLBACK_FIGURE_LAYOUT = (breakable: false, caption: bottom)
|
||||||
|
|
||||||
|
/// Author overrides, set via `ktu-paper(figureLayout: ...)`.
|
||||||
|
#let __USER_FIGURE_LAYOUT = state("ktu-user-figure-layout", (:))
|
||||||
|
|
||||||
|
/// Stack of local overrides set by `breakable-figures` / `unbreakable-figures`.
|
||||||
|
#let __FIGURE_BREAK_OVERRIDE = state("ktu-figure-break-override", ())
|
||||||
|
|
||||||
|
/// Validates author-supplied layouts: `(kind: (breakable: bool, caption: top | bottom))`,
|
||||||
|
/// every field optional.
|
||||||
|
#let __normalize-figure-layout(layouts) = {
|
||||||
|
for (key, spec) in layouts {
|
||||||
|
for (field, value) in spec {
|
||||||
|
assert(
|
||||||
|
field in ("breakable", "caption"),
|
||||||
|
message: "figureLayout." + key + ": unknown option `" + field + "`, expected `breakable` or `caption`",
|
||||||
|
)
|
||||||
|
if field == "breakable" {
|
||||||
|
assert(type(value) == bool, message: "figureLayout." + key + ".breakable must be a bool")
|
||||||
|
} else {
|
||||||
|
assert(
|
||||||
|
value == top or value == bottom,
|
||||||
|
message: "figureLayout." + key + ".caption must be `top` or `bottom`",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layouts
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the layout of a figure kind key. Must be called in a context.
|
||||||
|
#let __figure-layout(key) = {
|
||||||
|
let layout = __FALLBACK_FIGURE_LAYOUT + __DEFAULT_FIGURE_LAYOUT.at(key, default: (:))
|
||||||
|
layout = layout + __USER_FIGURE_LAYOUT.get().at(key, default: (:))
|
||||||
|
let overrides = __FIGURE_BREAK_OVERRIDE.get()
|
||||||
|
if overrides.len() > 0 {
|
||||||
|
layout.breakable = overrides.last()
|
||||||
|
}
|
||||||
|
layout
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs `body` with every figure's `breakable` setting forced to `mode`.
|
||||||
|
#let __with-break-override(mode, body) = {
|
||||||
|
__FIGURE_BREAK_OVERRIDE.update(stack => stack + (mode,))
|
||||||
|
body
|
||||||
|
__FIGURE_BREAK_OVERRIDE.update(stack => stack.slice(0, -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats a figure with a caption and number.
|
/// Formats a figure with a caption and number.
|
||||||
#let __format-figure(it) = {
|
#let __format-figure(it) = {
|
||||||
let separator = [.]
|
let caption = it.caption
|
||||||
let caption = it.caption
|
|
||||||
|
|
||||||
// If caption is not provided, just show the figure body
|
// If caption is not provided, just show the figure body
|
||||||
if caption == none {
|
if caption == none { return it.body }
|
||||||
return it.body
|
|
||||||
}
|
|
||||||
|
|
||||||
let counter = caption.counter
|
set text(size: 11pt)
|
||||||
let supplement = caption.supplement
|
|
||||||
|
|
||||||
if it.body.func() == math.equation {
|
let caption-line = [*#__caption-label(it)* #caption.body]
|
||||||
supplement = __fig-supplement("equation")
|
let key = __figure-key(it)
|
||||||
|
|
||||||
|
context {
|
||||||
|
let layout = __figure-layout(key)
|
||||||
|
let on-top = layout.caption == top
|
||||||
|
// Entire table is by default left aligned, unlike other figures which are centered
|
||||||
|
let body = if key == "table" { align(left, it.body) } else { it.body }
|
||||||
|
let caption-block = block(
|
||||||
|
sticky: on-top and layout.breakable,
|
||||||
|
width: 100%,
|
||||||
|
align(if on-top { left } else { center }, caption-line),
|
||||||
|
)
|
||||||
|
if layout.breakable {
|
||||||
|
// The body may split across pages. A caption on top is sticky and stays
|
||||||
|
// with the first rows; a caption at the bottom cannot be glued to the end
|
||||||
|
// of a splittable body, so it may end up alone on the next page.
|
||||||
|
if on-top {
|
||||||
|
caption-block
|
||||||
|
body
|
||||||
|
} else {
|
||||||
|
body
|
||||||
|
caption-block
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
supplement = __fig-supplement(it.kind)
|
block(breakable: false, width: 100%, {
|
||||||
}
|
if on-top {
|
||||||
set text(size: 11pt)
|
caption-block
|
||||||
|
body
|
||||||
let fig-num = context __get-figure-number(it, here())
|
} else {
|
||||||
|
body
|
||||||
// Tables have captions at the top
|
caption-block
|
||||||
if it.kind == table {
|
}
|
||||||
align(left)[*#fig-num #supplement#separator* #caption.body]
|
})
|
||||||
it.body
|
|
||||||
} else {
|
|
||||||
it.body
|
|
||||||
align(center)[*#fig-num #supplement#separator* #caption.body]
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+333
-191
@@ -3,211 +3,231 @@
|
|||||||
/// Wrapper around the table function that returns a KTU style conformant table.
|
/// Wrapper around the table function that returns a KTU style conformant table.
|
||||||
/// This includes setting text size to 10 pt.
|
/// This includes setting text size to 10 pt.
|
||||||
#let ktu-table(..args) = {
|
#let ktu-table(..args) = {
|
||||||
show table: it => {
|
show table: it => {
|
||||||
set text(size: 10pt)
|
set text(size: 10pt)
|
||||||
// TODO: FIXME line spacing is defined differently
|
// TODO: FIXME line spacing is defined differently
|
||||||
set par(leading: 1em - 0.75em) // intervalas tarp eilučių -- 1
|
set par(leading: 1em - 0.75em) // intervalas tarp eilučių -- 1
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
table(
|
table(
|
||||||
..args
|
..args
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let ktu-author-table(
|
#let ktu-author-table(
|
||||||
authors: (),
|
authors: (),
|
||||||
alignment: right,
|
alignment: right,
|
||||||
|
namesFirst: true, // if false, roles will be displayed first
|
||||||
) = context {
|
) = context {
|
||||||
// The layout should be a list of lists whose elements are (name, role) pairs.
|
// The layout should be a list of lists whose elements are (name, role) pairs.
|
||||||
assert(authors.len() > 0, message: "author table must have at least one author")
|
assert(authors.len() > 0, message: "author table must have at least one author")
|
||||||
assert(authors.all(it => it.len() == 2), message: "each author entry must be a pair of name and role")
|
assert(authors.all(it => it.len() == 2), message: "each author entry must be a pair of name and role")
|
||||||
|
|
||||||
let frame(color) = (x, y) => (
|
let frame(color) = (x, y) => (
|
||||||
left: 0pt,
|
left: 0pt,
|
||||||
right: 0pt,
|
right: 0pt,
|
||||||
top: if y == 0 { 0.5pt + color } else { 0pt },
|
top: if y == 0 { 0.5pt + color } else { 0pt },
|
||||||
bottom: 0.5pt + color,
|
bottom: 0.5pt + color,
|
||||||
)
|
)
|
||||||
set table(
|
set table(
|
||||||
inset: 5.4pt,
|
inset: 5.4pt,
|
||||||
stroke: if __DEBUG_AUTHOR_TABLE.get() {
|
stroke: if __DEBUG_AUTHOR_TABLE.get() {
|
||||||
0.5pt + rgb("D4AF37")
|
0.5pt + rgb("D4AF37")
|
||||||
} else {
|
|
||||||
frame(rgb("D4AF37"))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
show table.cell: it => context {
|
|
||||||
[#it]
|
|
||||||
if it.body == [] {
|
|
||||||
v(10pt)
|
|
||||||
} else {
|
|
||||||
v(0pt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if alignment == center {
|
|
||||||
align(center, table(
|
|
||||||
columns: (198.5pt + 56.7pt),
|
|
||||||
table.header([]),
|
|
||||||
..for author in authors {
|
|
||||||
let (name, role) = author
|
|
||||||
(align(center)[
|
|
||||||
#set block(below: 8pt)
|
|
||||||
#block[*#name*]
|
|
||||||
#block[#role]
|
|
||||||
|
|
||||||
], [])
|
|
||||||
}
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
align(alignment, table(
|
frame(rgb("D4AF37"))
|
||||||
columns: (198.5pt, 56.7pt),
|
},
|
||||||
table.header(
|
)
|
||||||
[], [],
|
show table.cell: it => context {
|
||||||
),
|
[#it]
|
||||||
..for author in authors {
|
if it.body == [] {
|
||||||
let (name, role) = author
|
v(10pt)
|
||||||
(align(left)[
|
} else {
|
||||||
#set block(below: 8pt)
|
v(0pt)
|
||||||
#block[*#name*]
|
|
||||||
#block[#role]
|
|
||||||
|
|
||||||
], [], [], [])
|
|
||||||
}
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if alignment == center {
|
||||||
|
align(center, table(
|
||||||
|
columns: (198.5pt + 56.7pt),
|
||||||
|
table.header([]),
|
||||||
|
..for author in authors {
|
||||||
|
let (name, role) = author
|
||||||
|
name = [*#name*]
|
||||||
|
if not namesFirst {
|
||||||
|
(role, name) = (name, role)
|
||||||
|
}
|
||||||
|
(
|
||||||
|
align(center)[
|
||||||
|
#set block(below: 8pt)
|
||||||
|
#block[#name]
|
||||||
|
#block[#role]
|
||||||
|
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
align(alignment, table(
|
||||||
|
columns: (198.5pt, 56.7pt),
|
||||||
|
table.header([], []),
|
||||||
|
..for author in authors {
|
||||||
|
let (name, role) = author
|
||||||
|
name = [*#name*]
|
||||||
|
if not namesFirst {
|
||||||
|
(role, name) = (name, role)
|
||||||
|
}
|
||||||
|
(
|
||||||
|
align(left)[
|
||||||
|
#set block(below: 8pt)
|
||||||
|
#block[#name]
|
||||||
|
#block[#role]
|
||||||
|
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function constructs the title page header block for KTU reports. It includes the university logo, name, subheaders, the main and sub titles of the report.
|
/// This function constructs the title page header block for KTU reports. It includes the university logo, name, subheaders, the main and sub titles of the report.
|
||||||
///
|
///
|
||||||
/// - bigTitle (content): The main title of the report, usually the name of the work. Displayed in 18 pt font.
|
/// - bigTitle (content): The main title of the report, usually the name of the work. Displayed in 18 pt font.
|
||||||
/// - subTitles (): Additional titles or information to be displayed under the main title, such as the type of work. Displayed in 14 pt font. If not provided, defaults to "Rašto darbo tipas".
|
/// - subTitles (): Additional titles or information to be displayed under the main title, such as the type of work. Displayed in 14 pt font. If not provided, defaults to "Rašto darbo tipas".
|
||||||
/// - subHeaders (): Additional header information to be displayed under the university name, such as the faculty. If not provided, defaults to "Fakulteto pavadinimas".
|
/// - subHeaders (): Additional header information to be displayed under the university name, such as the faculty. If not provided, defaults to "Fakulteto pavadinimas".
|
||||||
/// ->
|
/// ->
|
||||||
#let ktu-title-header-block(
|
#let ktu-title-header-block(
|
||||||
bigTitle: highlight[Didelis pavadinimas],
|
bigTitle: highlight[Didelis pavadinimas],
|
||||||
subTitles: (),
|
subTitles: (),
|
||||||
subHeaders: (),
|
subHeaders: (),
|
||||||
) = {
|
) = {
|
||||||
let parsedSubtext = if subHeaders.len() > 0 {
|
let parsedSubtext = if subHeaders.len() > 0 {
|
||||||
subHeaders
|
subHeaders
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
highlight[Fakulteto pavadinimas],
|
highlight[Fakulteto pavadinimas],
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let subTitles = if subTitles.len() > 0 {
|
||||||
|
subTitles
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
highlight[Rašto darbo tipas],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top of the title page
|
||||||
|
v(20pt)
|
||||||
|
align(center)[
|
||||||
|
#image("assets/ktu-logo.png", width: 2.46cm, height: 2.69cm)
|
||||||
|
#v(25pt)
|
||||||
|
#block[*Kauno technologijos universitetas*]
|
||||||
|
#for value in parsedSubtext {
|
||||||
|
block[#value]
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
|
||||||
let subTitles = if subTitles.len() > 0 {
|
// The title page information
|
||||||
subTitles
|
v(91pt)
|
||||||
} else {
|
align(center)[
|
||||||
(
|
#set par(justify: false)
|
||||||
highlight[Rašto darbo tipas],
|
#set linebreak(justify: false)
|
||||||
)
|
#block(text(size: 18pt, hyphenate: false)[*#bigTitle*])
|
||||||
|
#for value in subTitles {
|
||||||
|
block(text(size: 14pt)[#value])
|
||||||
}
|
}
|
||||||
|
]
|
||||||
// Top of the title page
|
|
||||||
v(20pt)
|
|
||||||
align(center)[
|
|
||||||
#image("assets/ktu-logo.png", width: 2.46cm, height: 2.69cm)
|
|
||||||
#v(25pt)
|
|
||||||
#block[*Kauno technologijos universitetas*]
|
|
||||||
#for value in parsedSubtext {
|
|
||||||
block[#value]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// The title page information
|
|
||||||
v(91pt)
|
|
||||||
align(center)[
|
|
||||||
#set par(justify: false)
|
|
||||||
#set linebreak(justify: false)
|
|
||||||
#block(text(size: 18pt, hyphenate: false)[*#bigTitle*])
|
|
||||||
#for value in subTitles {
|
|
||||||
block(text(size: 14pt)[#value])
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#let ktu-heading-page(
|
#let ktu-heading-page(
|
||||||
faculty: highlight[Fakulteto pavadinimas],
|
faculty: highlight[Fakulteto pavadinimas],
|
||||||
department: none, // optional
|
department: none, // optional
|
||||||
title: highlight[Rašto darbo pavadinimas],
|
title: highlight[Rašto darbo pavadinimas],
|
||||||
subtitles: highlight[Praktikos ataskaita / referatas ir pan. (įrašyti rašto darbo tipą)],
|
subtitles: highlight[Praktikos ataskaita / referatas ir pan. (įrašyti rašto darbo tipą)],
|
||||||
authors: (
|
authors: (
|
||||||
(highlight[Vardenis Pavardenis], highlight[Projekto autorius]),
|
(highlight[Vardenis Pavardenis], highlight[Projekto autorius]),
|
||||||
(highlight[Vardenis Pavardenis], highlight[Vadovas]),
|
(highlight[Vardenis Pavardenis], highlight[Vadovas]),
|
||||||
),
|
),
|
||||||
place: highlight[Kaunas],
|
place: highlight[Kaunas],
|
||||||
year: highlight[#datetime.today().year()],
|
year: highlight[#datetime.today().year()],
|
||||||
centerAuthors: false,
|
centerAuthors: false,
|
||||||
|
authorNamesFirst: true, // if false, roles will be displayed first
|
||||||
) = {
|
) = {
|
||||||
let subHeaders = (faculty,)
|
let subHeaders = (faculty,)
|
||||||
if department != none {
|
if department != none {
|
||||||
subHeaders = (faculty, department)
|
subHeaders = (faculty, department)
|
||||||
}
|
}
|
||||||
if type(subtitles) != array {
|
if type(subtitles) != array {
|
||||||
subtitles = (subtitles,)
|
subtitles = (subtitles,)
|
||||||
}
|
}
|
||||||
ktu-title-header-block(
|
ktu-title-header-block(
|
||||||
subHeaders: subHeaders,
|
subHeaders: subHeaders,
|
||||||
bigTitle: title,
|
bigTitle: title,
|
||||||
subTitles: subtitles,
|
subTitles: subtitles,
|
||||||
)
|
)
|
||||||
v(94pt)
|
v(94pt)
|
||||||
if centerAuthors {
|
if centerAuthors {
|
||||||
ktu-author-table(authors: authors, alignment: center)
|
ktu-author-table(authors: authors, namesFirst: authorNamesFirst, alignment: center)
|
||||||
} else {
|
} else {
|
||||||
ktu-author-table(authors: authors)
|
ktu-author-table(authors: authors, namesFirst: authorNamesFirst)
|
||||||
}
|
}
|
||||||
align(center+bottom, block([*#place, #year*]))
|
align(center + bottom, block([*#place, #year*]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#let ktu-heading-page-centered(
|
#let ktu-heading-page-centered(
|
||||||
faculty: highlight[Fakulteto pavadinimas],
|
faculty: highlight[Fakulteto pavadinimas],
|
||||||
department: none, // optional
|
department: none, // optional
|
||||||
title: highlight[Rašto darbo pavadinimas],
|
title: highlight[Rašto darbo pavadinimas],
|
||||||
subtitles: highlight[Praktikos ataskaita / referatas ir pan. (įrašyti rašto darbo tipą)],
|
subtitles: highlight[Praktikos ataskaita / referatas ir pan. (įrašyti rašto darbo tipą)],
|
||||||
authors: (
|
authors: (
|
||||||
(highlight[Vardenis Pavardenis], highlight[Projekto autorius]),
|
(highlight[Vardenis Pavardenis], highlight[Projekto autorius]),
|
||||||
(highlight[Vardenis Pavardenis], highlight[Vadovas]),
|
(highlight[Vardenis Pavardenis], highlight[Vadovas]),
|
||||||
),
|
),
|
||||||
place: highlight[Kaunas],
|
authorNamesFirst: true, // if false, roles will be displayed first
|
||||||
year: highlight[#datetime.today().year()],
|
place: highlight[Kaunas],
|
||||||
|
year: highlight[#datetime.today().year()],
|
||||||
) = {
|
) = {
|
||||||
ktu-heading-page(
|
ktu-heading-page(
|
||||||
faculty: faculty,
|
faculty: faculty,
|
||||||
department: department,
|
department: department,
|
||||||
title: title,
|
title: title,
|
||||||
subtitles: subtitles,
|
subtitles: subtitles,
|
||||||
authors: authors,
|
authors: authors,
|
||||||
place: place,
|
place: place,
|
||||||
year: year,
|
year: year,
|
||||||
centerAuthors: true,
|
centerAuthors: true,
|
||||||
)
|
authorNamesFirst: authorNamesFirst,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let ktu-heading-page-normal(
|
#let ktu-heading-page-normal(
|
||||||
faculty: highlight[Fakulteto pavadinimas],
|
faculty: highlight[Fakulteto pavadinimas],
|
||||||
department: none, // optional
|
department: none, // optional
|
||||||
title: highlight[Rašto darbo pavadinimas],
|
title: highlight[Rašto darbo pavadinimas],
|
||||||
subtitles: highlight[Praktikos ataskaita / referatas ir pan. (įrašyti rašto darbo tipą)],
|
subtitles: highlight[Praktikos ataskaita / referatas ir pan. (įrašyti rašto darbo tipą)],
|
||||||
authors: (
|
authors: (
|
||||||
(highlight[Vardenis Pavardenis], highlight[Projekto autorius]),
|
(highlight[Vardenis Pavardenis], highlight[Projekto autorius]),
|
||||||
(highlight[Vardenis Pavardenis], highlight[Vadovas]),
|
(highlight[Vardenis Pavardenis], highlight[Vadovas]),
|
||||||
),
|
),
|
||||||
place: highlight[Kaunas],
|
authorNamesFirst: true, // if false, roles will be displayed first
|
||||||
year: highlight[#datetime.today().year()],
|
place: highlight[Kaunas],
|
||||||
|
year: highlight[#datetime.today().year()],
|
||||||
) = {
|
) = {
|
||||||
ktu-heading-page(
|
ktu-heading-page(
|
||||||
faculty: faculty,
|
faculty: faculty,
|
||||||
department: department,
|
department: department,
|
||||||
title: title,
|
title: title,
|
||||||
subtitles: subtitles,
|
subtitles: subtitles,
|
||||||
authors: authors,
|
authors: authors,
|
||||||
place: place,
|
place: place,
|
||||||
year: year,
|
year: year,
|
||||||
centerAuthors: false,
|
centerAuthors: false,
|
||||||
)
|
authorNamesFirst: authorNamesFirst,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let ktu-academic-honestly-declaration-page(
|
#let ktu-academic-honestly-declaration-page(
|
||||||
@@ -215,22 +235,144 @@
|
|||||||
author: highlight[Vardenis Pavardenis],
|
author: highlight[Vardenis Pavardenis],
|
||||||
projectTitle: highlight[Projekto pavadinimas],
|
projectTitle: highlight[Projekto pavadinimas],
|
||||||
) = {
|
) = {
|
||||||
ktu-title-header-block(
|
ktu-title-header-block(
|
||||||
subHeaders: (faculty, author),
|
subHeaders: (faculty, author),
|
||||||
bigTitle: projectTitle,
|
bigTitle: projectTitle,
|
||||||
subTitles: ("Akademinio sąžiningumo deklaracija",)
|
subTitles: ("Akademinio sąžiningumo deklaracija",),
|
||||||
)
|
)
|
||||||
v(20pt)
|
v(20pt)
|
||||||
[
|
[
|
||||||
Patvirtinu, kad:
|
Patvirtinu, kad:
|
||||||
+ baigiamąjį projektą parengiau savarankiškai ir sąžiningai, nepažeisdama(s) kitų asmenų autoriaus ar kitų teisių, laikydamasi(s) Lietuvos Respublikos autorių teisių ir gretutinių teisių įstatymo nuostatų, Kauno technologijos universiteto (toliau -- Universitetas) intelektinės nuosavybės valdymo ir perdavimo nuostatų bei Universiteto akademinės etikos kodekse nustatytų etikos reikalavimų;
|
+ baigiamąjį projektą parengiau savarankiškai ir sąžiningai, nepažeisdama(s) kitų asmenų autoriaus ar kitų teisių, laikydamasi(s) Lietuvos Respublikos autorių teisių ir gretutinių teisių įstatymo nuostatų, Kauno technologijos universiteto (toliau -- Universitetas) intelektinės nuosavybės valdymo ir perdavimo nuostatų bei Universiteto akademinės etikos kodekse nustatytų etikos reikalavimų;
|
||||||
+ baigiamajame projekte visi pateikti duomenys ir tyrimų rezultatai yra teisingi ir gauti teisėtai, nei viena šio projekto dalis nėra plagijuota nuo jokių spausdintinių ar elektroninių šaltinių, visos baigiamojo projekto tekste pateiktos citatos ir nuorodos yra nurodytos literatūros sąraše;
|
+ baigiamajame projekte visi pateikti duomenys ir tyrimų rezultatai yra teisingi ir gauti teisėtai, nei viena šio projekto dalis nėra plagijuota nuo jokių spausdintinių ar elektroninių šaltinių, visos baigiamojo projekto tekste pateiktos citatos ir nuorodos yra nurodytos literatūros sąraše;
|
||||||
+ įstatymų nenumatytų piniginių sumų už baigiamąjį projektą ar jo dalis niekam nesu mokėjęs (-usi);
|
+ įstatymų nenumatytų piniginių sumų už baigiamąjį projektą ar jo dalis niekam nesu mokėjęs (-usi);
|
||||||
+ suprantu, kad išaiškėjus nesąžiningumo ar kitų asmenų teisių pažeidimo faktui, man bus taikomos akademinės nuobaudos pagal Universitete galiojančią tvarką ir būsiu pašalinta(s) iš Universiteto, o baigiamasis projektas gali būti pateiktas Akademinės etikos ir procedūrų kontrolieriaus tarnybai nagrinėjant galimą akademinės etikos pažeidimą.
|
+ suprantu, kad išaiškėjus nesąžiningumo ar kitų asmenų teisių pažeidimo faktui, man bus taikomos akademinės nuobaudos pagal Universitete galiojančią tvarką ir būsiu pašalinta(s) iš Universiteto, o baigiamasis projektas gali būti pateiktas Akademinės etikos ir procedūrų kontrolieriaus tarnybai nagrinėjant galimą akademinės etikos pažeidimą.
|
||||||
|
|
||||||
#v(10pt)
|
#v(10pt)
|
||||||
#h(58%) #author
|
#h(58%) #author
|
||||||
|
|
||||||
#h(58%) _Patvirtinta elektroniniu būdu_
|
#h(58%) _Patvirtinta elektroniniu būdu_
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
#let ktu-gen-ai-usage-declaration-page(
|
||||||
|
author: highlight[Vardenis Pavardenis],
|
||||||
|
faculty: highlight[Informatikos fakultetas],
|
||||||
|
module: highlight[Studijų modulio pavadinimas (kodas)],
|
||||||
|
title: highlight[Studijų darbo pavadinimas],
|
||||||
|
type: highlight[Studijų darbo rūšis],
|
||||||
|
usageInformation: (
|
||||||
|
(highlight[...], highlight[...], highlight[...], highlight[...]),
|
||||||
|
),
|
||||||
|
showPhysicalSignature: true,
|
||||||
|
) = {
|
||||||
|
set text(size: 12pt)
|
||||||
|
|
||||||
|
align(center)[
|
||||||
|
#block([*GENERATYVINIO DIRBTINIO INTELEKTO (GenDI) NAUDOJIMO DEKLARACIJA*])
|
||||||
|
#block[\_\_\_ \_\_\_ \_\_\_]
|
||||||
|
]
|
||||||
|
|
||||||
|
[*1. Studento duomenys*]
|
||||||
|
table(
|
||||||
|
columns: (155pt, 1fr),
|
||||||
|
align: (x, y) => { horizon + left },
|
||||||
|
[*Studento vardas, pavardė*], [#author],
|
||||||
|
[*Studento fakultetas*], [#faculty],
|
||||||
|
[*Studijų modulis*], [#module],
|
||||||
|
[*Studijų darbo pavadinimas*], [#title],
|
||||||
|
[*Studijų darbo rūšis*], [#type],
|
||||||
|
)
|
||||||
|
|
||||||
|
[
|
||||||
|
#set linebreak(justify: false)
|
||||||
|
*2. GenDI naudojimo patvirtinimas*\
|
||||||
|
_Pažymėkite vieną variantą:_
|
||||||
|
]
|
||||||
|
let usedAi = usageInformation != none and usageInformation.len() > 0
|
||||||
|
let checkbox(checked: false) = {
|
||||||
|
box(
|
||||||
|
width: 0.8em,
|
||||||
|
height: 0.8em,
|
||||||
|
stroke: 0.08em + black,
|
||||||
|
radius: 0.15em,
|
||||||
|
if checked {
|
||||||
|
let size = 0.4em
|
||||||
|
let margin = 0.2em
|
||||||
|
// Top-left to bottom-right line
|
||||||
|
place(top + left, dx: margin, dy: margin, line(end: (size, size), stroke: 0.08em + black))
|
||||||
|
// Bottom-left to top-right line
|
||||||
|
place(top + left, dx: margin, dy: margin + size, line(end: (size, -size), stroke: 0.08em + black))
|
||||||
|
} else {
|
||||||
|
none
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
table(
|
||||||
|
columns: (28pt, 1fr),
|
||||||
|
align: (x, y) => { horizon + left },
|
||||||
|
table.cell(rowspan: 2)[#align(top, checkbox(checked: not usedAi))],
|
||||||
|
[*Rengdamas (-a) šį studijų darbą nenaudojau generatyvinio dirbtinio intelekto įrankių*],
|
||||||
|
[Patvirtinu, kad studijų darbe pateiktas turinys yra mano autentiškas intelektinis darbas, o naudoti šaltiniai nurodyti pagal citavimo reikalavimus.],
|
||||||
|
|
||||||
|
table.cell(rowspan: 2)[#align(top, checkbox(checked: usedAi))],
|
||||||
|
[*Rengdamas (-a) šį studijų darbą naudojau generatyvinio dirbtinio intelekto įrankius*],
|
||||||
|
[Patvirtinu, kad GenDI įrankiai buvo naudojami laikantis studijų modulyje nustatytų GenDI naudojimo reikalavimų bei naudojimas yra skaidriai ir sąžiningai deklaruotas.],
|
||||||
|
)
|
||||||
|
|
||||||
|
[
|
||||||
|
#set linebreak(justify: false)
|
||||||
|
*3. GenDI naudojimo informacija*\
|
||||||
|
_Užpildykite, jei rengiant studijų darbą naudojote generatyvinio dirbtinio intelekto įrankius:_
|
||||||
|
]
|
||||||
|
let rows = if usedAi {
|
||||||
|
usageInformation.flatten()
|
||||||
|
} else {
|
||||||
|
// hide[x] gives each empty cell the height of one regular line of text
|
||||||
|
range(3).map(_ => range(4).map(_ => hide[x])).flatten()
|
||||||
|
}
|
||||||
|
set par(justify: false)
|
||||||
|
table(
|
||||||
|
columns: (91pt, 127pt, 139pt, 1fr),
|
||||||
|
align: (x, y) => if y == 0 { top + left } else { horizon + left },
|
||||||
|
table.header(
|
||||||
|
[
|
||||||
|
#set linebreak(justify: false)
|
||||||
|
*Darbo dalis*\
|
||||||
|
_(pvz., skyrius, visas darbas)_
|
||||||
|
],
|
||||||
|
[*GenDI įrankio naudojimo tikslas*],
|
||||||
|
[*GenDI įrankio pavadinimas, versija / internetinė nuoroda*],
|
||||||
|
[
|
||||||
|
#set linebreak(justify: false)
|
||||||
|
*Studento indėlis* \
|
||||||
|
_(kaip GenDI rezultatas buvo patikrintas, redaguotas ar papildytas studento)_
|
||||||
|
],
|
||||||
|
),
|
||||||
|
..rows,
|
||||||
|
)
|
||||||
|
|
||||||
|
let field(size: 12pt, body) = {
|
||||||
|
set text(size: size)
|
||||||
|
align(center, body)
|
||||||
|
}
|
||||||
|
let underlined-field(min-width: 92pt, body) = context {
|
||||||
|
let w = calc.max(min-width, measure(body).width)
|
||||||
|
align(center, box(
|
||||||
|
width: w,
|
||||||
|
height: 1.4em,
|
||||||
|
stroke: (bottom: 0.5pt + black),
|
||||||
|
inset: (bottom: 2pt),
|
||||||
|
align(center + bottom, body),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
let maybe(show-it, body) = if show-it { body } else { hide(body) }
|
||||||
|
align(bottom, table(
|
||||||
|
stroke: 0pt,
|
||||||
|
inset: 2pt,
|
||||||
|
columns: (120pt, 177pt, 1fr),
|
||||||
|
align: (x, y) => { horizon + left },
|
||||||
|
[Studentas], [#maybe(showPhysicalSignature, [#underlined-field[]])], [#underlined-field[#author]],
|
||||||
|
[], [#maybe(showPhysicalSignature, [#field(size: 10pt)[_(parašas)_]])], [#field(size: 10pt)[(_vardas, pavardė_)]],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
+432
-412
@@ -1,57 +1,91 @@
|
|||||||
#import "@preview/codly:1.3.0": codly, codly-init
|
#import "@preview/codly:2.0.0" as codly
|
||||||
#import "config.typ": debug-author-table, enable-heading-experiment, __HEADING_EXPERIMENT, __FIG_PER_SECTION, __UPPERCASE_SECTION_TITLES
|
#import "config.typ": debug-author-table, enable-heading-experiment, __HEADING_EXPERIMENT, __FIG_PER_SECTION, __UPPERCASE_SECTION_TITLES
|
||||||
#import "fragments.typ": (
|
#import "fragments.typ": (
|
||||||
ktu-table,
|
ktu-table,
|
||||||
ktu-heading-page, ktu-heading-page-centered, ktu-heading-page-normal,
|
|
||||||
ktu-academic-honestly-declaration-page
|
// building blocks
|
||||||
|
ktu-author-table, ktu-title-header-block,
|
||||||
|
|
||||||
|
ktu-heading-page, ktu-heading-page-centered, ktu-heading-page-normal,
|
||||||
|
ktu-academic-honestly-declaration-page, ktu-gen-ai-usage-declaration-page
|
||||||
)
|
)
|
||||||
#import "figures.typ": (
|
#import "figures.typ": (
|
||||||
__fig-supplement,
|
ref-no, custom-ref,
|
||||||
|
|
||||||
__get-figure-number,
|
__caption-label,
|
||||||
__get-locatable-element-number,
|
__reset-figure-counters,
|
||||||
|
__equation-numbering,
|
||||||
|
__normalize-figure-kinds,
|
||||||
|
__USER_FIGURE_KINDS,
|
||||||
|
__USER_FIGURE_LAYOUT,
|
||||||
|
__normalize-figure-layout,
|
||||||
|
__with-break-override,
|
||||||
|
|
||||||
__format-ref,
|
__format-ref,
|
||||||
__format-figure,
|
__format-figure,
|
||||||
|
__figure-kinds,
|
||||||
|
|
||||||
|
__is-appendix-heading,
|
||||||
|
__appendix-title,
|
||||||
|
__appendix-number,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paruošta pagal "Rašto ..."
|
* Paruošta pagal "Rašto ..."
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Further reading required:
|
* Further reading required:
|
||||||
* - Double line spacing | https://github.com/typst/typst/issues/106
|
* - Double line spacing | https://github.com/typst/typst/issues/106
|
||||||
* - Proposal: change `leading` option to `line-height` | https://github.com/typst/typst/issues/4224
|
* - Proposal: change `leading` option to `line-height` | https://github.com/typst/typst/issues/4224
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#let __METADATA_HEADING_ALIGN_LEFT = metadata("heading-align-left");
|
#let __METADATA_HEADING_ALIGN_LEFT = metadata("heading-align-left");
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Insert a heading without a number.
|
/// Insert a heading without a number.
|
||||||
///
|
///
|
||||||
/// Usually used for introductory or summary sections at the start and end.
|
/// Usually used for introductory or summary sections at the start and end.
|
||||||
/// - headingElement (heading): The heading's title.
|
/// - headingElement (heading): The heading's title.
|
||||||
/// - alignLeft (bool): Whether the heading should be left-aligned or centered.
|
/// - alignLeft (bool): Whether the heading should be left-aligned or centered.
|
||||||
/// ->
|
/// ->
|
||||||
#let unnumbered-heading(headingElement, alignLeft: false) = {
|
#let unnumbered-heading(headingElement, alignLeft: false) = {
|
||||||
let fields = headingElement.fields()
|
let fields = headingElement.fields()
|
||||||
let body = fields.body
|
let body = fields.body
|
||||||
let level = fields.at("level", default: 1)
|
let level = fields.at("level", default: 1)
|
||||||
|
|
||||||
if alignLeft {
|
if alignLeft {
|
||||||
body = body + __METADATA_HEADING_ALIGN_LEFT
|
body = body + __METADATA_HEADING_ALIGN_LEFT
|
||||||
}
|
}
|
||||||
|
|
||||||
heading(level: level, numbering: none, body)
|
heading(level: level, numbering: none, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let appendix-item(body) = {
|
/// Insert an appendix (priedas).
|
||||||
heading(
|
///
|
||||||
metadata("appendix-heading") + "priedas. " + body,
|
/// Appendices are numbered 1, 2, 3, ... in the order they appear in the
|
||||||
level: 2,
|
/// document, so place them in the order they are first mentioned in the text.
|
||||||
numbering: (..any) => {str(any.at(1))}
|
/// Each appendix should start on a new page: put a `#pagebreak()` before it.
|
||||||
)
|
/// "N priedas" is written in the top right
|
||||||
|
/// corner. The optional title is written below it like a chapter title (bold),
|
||||||
|
/// exactly as given: start it with a capital letter, the rest in lowercase.
|
||||||
|
/// Appendices are included in the table of contents.
|
||||||
|
///
|
||||||
|
/// Give it a label to refer to it from the text: `#appendix-item[Pavadinimas] <pr-konfig>`
|
||||||
|
/// and then `@pr-konfig` or `#custom-ref(<pr-konfig>)` gives "(žr. 1 priedą)".
|
||||||
|
/// - title (content | none): Optional appendix title.
|
||||||
|
/// -> heading
|
||||||
|
#let appendix-item(..title) = {
|
||||||
|
assert(
|
||||||
|
title.named().len() == 0 and title.pos().len() <= 1,
|
||||||
|
message: "appendix-item takes at most one argument: the appendix title",
|
||||||
|
)
|
||||||
|
let title = title.pos().at(0, default: none)
|
||||||
|
heading(
|
||||||
|
if title == none { metadata("appendix-heading") } else { metadata("appendix-heading") + title },
|
||||||
|
level: 2,
|
||||||
|
numbering: none,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility function to round numbers with padded zeros
|
// Utility function to round numbers with padded zeros
|
||||||
@@ -60,8 +94,7 @@
|
|||||||
let s = str(rounded)
|
let s = str(rounded)
|
||||||
let parts = s.split(".")
|
let parts = s.split(".")
|
||||||
let integer-part = parts.at(0)
|
let integer-part = parts.at(0)
|
||||||
let decimal-part = if parts.len() == 2 { parts.at(1) } else { ""}
|
let decimal-part = if parts.len() == 2 { parts.at(1) } else { "" }
|
||||||
|
|
||||||
|
|
||||||
let padded-decimal = if decimals > 0 {
|
let padded-decimal = if decimals > 0 {
|
||||||
let current-decimal-length = decimal-part.len()
|
let current-decimal-length = decimal-part.len()
|
||||||
@@ -81,109 +114,6 @@
|
|||||||
integer-part + padded-decimal
|
integer-part + padded-decimal
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a number for the given reference target.
|
|
||||||
/// - target (label): Label to get the reference number for.
|
|
||||||
#let ref-no(target) = context {
|
|
||||||
if type(target) != label {
|
|
||||||
panic("ref-no expects a label as input")
|
|
||||||
}
|
|
||||||
|
|
||||||
let loc = locate(target)
|
|
||||||
let elem = query(target)
|
|
||||||
let item = elem.at(0)
|
|
||||||
|
|
||||||
// If it's a figure, return the figure number
|
|
||||||
if item.func() == figure {
|
|
||||||
link(loc, [#__get-figure-number(item, loc)])
|
|
||||||
} else if item.func() == heading {
|
|
||||||
let fullValue = counter(heading).at(loc)
|
|
||||||
|
|
||||||
// If the heading has the "appendix-heading" metadata attached,
|
|
||||||
// it means that it's an appendix heading and should be numbered differently
|
|
||||||
if item.body.has("children") and item.body.children.at(0) == metadata("appendix-heading") {
|
|
||||||
link(loc, [#fullValue.at(1)])
|
|
||||||
// Otherwise, show the fully qualified heading numbering
|
|
||||||
} else {
|
|
||||||
link(loc, [#fullValue.map((x) => str(x)).join(".")])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic("referencing unknown type: ", item.func())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs a reference from multiple targets
|
|
||||||
#let custom-ref(..targets) = context {
|
|
||||||
let collected = (:)
|
|
||||||
|
|
||||||
for target in targets.pos() {
|
|
||||||
let loc = locate(target)
|
|
||||||
let elem = query(target)
|
|
||||||
|
|
||||||
let fig = elem.at(0)
|
|
||||||
if fig.func() != figure {
|
|
||||||
panic("referencing unknown type")
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine what we...
|
|
||||||
let element = fig.body;
|
|
||||||
let elementName = "unknown";
|
|
||||||
let found = false;
|
|
||||||
while not found {
|
|
||||||
|
|
||||||
// If it's a grid
|
|
||||||
if (element.func() == grid) {
|
|
||||||
for cell in element.children {
|
|
||||||
if cell.body.func() == image {
|
|
||||||
elementName = "pav."
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.func() == table) {
|
|
||||||
elementName = "lentelė"
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.func() == raw) {
|
|
||||||
elementName = "kodo frag."
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.func() == image) {
|
|
||||||
elementName = "pav."
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("unknown element", element.func())
|
|
||||||
}
|
|
||||||
|
|
||||||
if elementName not in collected {
|
|
||||||
collected.insert(elementName, ())
|
|
||||||
}
|
|
||||||
|
|
||||||
collected.at(elementName).push(
|
|
||||||
(loc, __get-figure-number(fig, loc))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if collected.len() > 1 {
|
|
||||||
panic("multiple types detected")
|
|
||||||
}
|
|
||||||
|
|
||||||
for type in collected {
|
|
||||||
let name = type.at(0)
|
|
||||||
let arr = type.at(1).sorted(key: k => k.at(1))
|
|
||||||
|
|
||||||
[(žr. #arr.map(x =>link(x.at(0), [#x.at(1)])).join(", ") #name)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns a KTU template-conformant outline.
|
/// Returns a KTU template-conformant outline.
|
||||||
/// - depth (int | none): Same as outline depth.
|
/// - depth (int | none): Same as outline depth.
|
||||||
@@ -192,123 +122,131 @@
|
|||||||
/// - title (auto | content | none): Same as outline title.
|
/// - title (auto | content | none): Same as outline title.
|
||||||
/// -> outline
|
/// -> outline
|
||||||
#let __ktu_outline(
|
#let __ktu_outline(
|
||||||
depth: none,
|
depth: none,
|
||||||
indent: 0em, // Disable the default outline indenting
|
indent: 0em, // Disable the default outline indenting
|
||||||
target: heading,
|
target: heading,
|
||||||
title: auto
|
title: auto,
|
||||||
) = {
|
) = {
|
||||||
// TODO: įtrauka
|
// TODO: įtrauka
|
||||||
set block(spacing: 0em)
|
set block(spacing: 0em)
|
||||||
// genius solution by @two_horus on Discord (364397430059302912)
|
// genius solution by @two_horus on Discord (364397430059302912)
|
||||||
show outline: o => context {
|
show outline: o => context {
|
||||||
// If it's a heading, show the default outline with bold text
|
// If it's a heading, show the default outline with bold text
|
||||||
if (o.target == selector(heading)) {
|
if (o.target == selector(heading)) {
|
||||||
// Determine whether to uppercase section titles based on the global setting
|
// Determine whether to uppercase section titles based on the global setting
|
||||||
let isUpper = __UPPERCASE_SECTION_TITLES.get()
|
let isUpper = __UPPERCASE_SECTION_TITLES.get()
|
||||||
|
|
||||||
// Define known target widths based on KTU template
|
// Define known target widths based on KTU template
|
||||||
let targets = (0.64cm, 0.96cm, 1.28cm, 1.6cm, 1.92cm)
|
let targets = (0.64cm, 0.96cm, 1.28cm, 1.6cm, 1.92cm)
|
||||||
|
|
||||||
// Apply custom outline entry formatting
|
|
||||||
show outline.entry: it => {
|
|
||||||
// Recompute the gap based on the prefix content, so that the outline entry is indented
|
|
||||||
// from the left regardless of the length of the prefix (based on the requirement)
|
|
||||||
let prefixContent = it.prefix()
|
|
||||||
let measurement = measure(prefixContent)
|
|
||||||
let target = targets.at(it.level - 1, default: 0.64cm)
|
|
||||||
let newGap = target - measurement.width
|
|
||||||
if it.element.body.has("children") and it.element.body.children.at(0) == metadata("appendix-heading") {
|
|
||||||
target = 0.64cm
|
|
||||||
}
|
|
||||||
let newGap = target - measurement.width
|
|
||||||
|
|
||||||
// Uppercase body if need be
|
// Apply custom outline entry formatting
|
||||||
let bodyContent = it.element.body
|
show outline.entry: it => {
|
||||||
if isUpper and (it.level == 1 or it.element.numbering == none) {
|
// Recompute the gap based on the prefix content, so that the outline entry is indented
|
||||||
bodyContent = upper(bodyContent)
|
// from the left regardless of the length of the prefix (based on the requirement)
|
||||||
}
|
let isAppendix = __is-appendix-heading(it.element)
|
||||||
|
|
||||||
// Reconstruct the it.inner content with the new body
|
// Appendices are listed as "N priedas. Pavadinimas", the number being the prefix
|
||||||
let formattedInner = {
|
let prefixContent = if isAppendix {
|
||||||
bodyContent
|
context [#__appendix-number(it.element)]
|
||||||
[ ] // whitespace is required for backwards compat
|
|
||||||
box(width: 1fr, it.fill)
|
|
||||||
[ ] // whitespace is required for backwards compat
|
|
||||||
it.page()
|
|
||||||
}
|
|
||||||
|
|
||||||
link(
|
|
||||||
it.element.location(),
|
|
||||||
it.indented(prefixContent, formattedInner, gap: newGap),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
show outline.entry.where(level: 1): e => {
|
|
||||||
strong(e)
|
|
||||||
}
|
|
||||||
o
|
|
||||||
|
|
||||||
// If it's an image
|
|
||||||
} else if (o.target == figure.where(kind: image)) {
|
|
||||||
show outline.entry: it => link(
|
|
||||||
it.element.location(),
|
|
||||||
it.indented(
|
|
||||||
[*#__get-locatable-element-number(it.element) #__fig-supplement(image).*],
|
|
||||||
[ #it.inner()], gap: 0pt
|
|
||||||
),
|
|
||||||
)
|
|
||||||
o
|
|
||||||
|
|
||||||
// If it is a table, show table formatting
|
|
||||||
} else if (o.target == figure.where(kind: table)) {
|
|
||||||
show outline.entry: it => link(
|
|
||||||
it.element.location(),
|
|
||||||
it.indented(
|
|
||||||
[*#__get-locatable-element-number(it.element) #__fig-supplement(table).*],
|
|
||||||
[ #it.inner()], gap: 0pt
|
|
||||||
),
|
|
||||||
)
|
|
||||||
o
|
|
||||||
|
|
||||||
// If it is a table, show table formatting
|
|
||||||
} else if (o.target == figure.where(kind: raw)) {
|
|
||||||
show outline.entry: it => link(
|
|
||||||
it.element.location(),
|
|
||||||
it.indented(
|
|
||||||
[*#__get-locatable-element-number(it.element) #__fig-supplement(raw).*],
|
|
||||||
[ #it.inner()], gap: 0pt
|
|
||||||
),
|
|
||||||
)
|
|
||||||
o
|
|
||||||
|
|
||||||
// Otherwise, try to determine what kind of outline it is
|
|
||||||
} else {
|
} else {
|
||||||
|
it.prefix()
|
||||||
/*[
|
|
||||||
#o.target #type(o.target),
|
|
||||||
#(o.target == "heading")
|
|
||||||
#(o.target == heading)
|
|
||||||
#(o.target == figure.where(kind: heading))
|
|
||||||
#(o.target == heading.where())
|
|
||||||
#(o.target == selector(heading))
|
|
||||||
]*/
|
|
||||||
|
|
||||||
show outline.entry: it => link(
|
|
||||||
it.element.location(),
|
|
||||||
it.indented(
|
|
||||||
[*#__get-locatable-element-number(it.element) unknown.*],
|
|
||||||
it.inner(), gap: 0pt
|
|
||||||
),
|
|
||||||
)
|
|
||||||
o
|
|
||||||
}
|
}
|
||||||
|
let measurement = measure(prefixContent)
|
||||||
|
let target = if isAppendix { 0.64cm } else { targets.at(it.level - 1, default: 0.64cm) }
|
||||||
|
let newGap = target - measurement.width
|
||||||
|
|
||||||
|
// Uppercase body if need be
|
||||||
|
let bodyContent = it.element.body
|
||||||
|
if isAppendix {
|
||||||
|
let title = __appendix-title(it.element)
|
||||||
|
let name = __figure-kinds.appendix.supplement
|
||||||
|
bodyContent = if title == none { [#name] } else { [#name. #title] }
|
||||||
|
} else if isUpper and (it.level == 1 or it.element.numbering == none) {
|
||||||
|
bodyContent = upper(bodyContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconstruct the it.inner content with the new body
|
||||||
|
let formattedInner = {
|
||||||
|
bodyContent
|
||||||
|
[ ] // whitespace is required for backwards compat
|
||||||
|
box(width: 1fr, it.fill)
|
||||||
|
[ ] // whitespace is required for backwards compat
|
||||||
|
it.page()
|
||||||
|
}
|
||||||
|
|
||||||
|
link(
|
||||||
|
it.element.location(),
|
||||||
|
it.indented(prefixContent, formattedInner, gap: newGap),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
show outline.entry.where(level: 1): e => {
|
||||||
|
strong(e)
|
||||||
|
}
|
||||||
|
o
|
||||||
|
|
||||||
|
// If it's an image
|
||||||
|
} else if (o.target == figure.where(kind: image)) {
|
||||||
|
show outline.entry: it => link(
|
||||||
|
it.element.location(),
|
||||||
|
it.indented(
|
||||||
|
[*#__caption-label(it.element)*],
|
||||||
|
[ #it.inner()], gap: 0pt
|
||||||
|
),
|
||||||
|
)
|
||||||
|
o
|
||||||
|
|
||||||
|
// If it is a table, show table formatting
|
||||||
|
} else if (o.target == figure.where(kind: table)) {
|
||||||
|
show outline.entry: it => link(
|
||||||
|
it.element.location(),
|
||||||
|
it.indented(
|
||||||
|
[*#__caption-label(it.element)*],
|
||||||
|
[ #it.inner()], gap: 0pt
|
||||||
|
),
|
||||||
|
)
|
||||||
|
o
|
||||||
|
|
||||||
|
// If it is a table, show table formatting
|
||||||
|
} else if (o.target == figure.where(kind: raw)) {
|
||||||
|
show outline.entry: it => link(
|
||||||
|
it.element.location(),
|
||||||
|
it.indented(
|
||||||
|
[*#__caption-label(it.element)*],
|
||||||
|
[ #it.inner()], gap: 0pt
|
||||||
|
),
|
||||||
|
)
|
||||||
|
o
|
||||||
|
|
||||||
|
// Otherwise, try to determine what kind of outline it is
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/*[
|
||||||
|
#o.target #type(o.target),
|
||||||
|
#(o.target == "heading")
|
||||||
|
#(o.target == heading)
|
||||||
|
#(o.target == figure.where(kind: heading))
|
||||||
|
#(o.target == heading.where())
|
||||||
|
#(o.target == selector(heading))
|
||||||
|
]*/
|
||||||
|
|
||||||
|
// Any other figure kind (generally, user defined kinds)
|
||||||
|
show outline.entry: it => link(
|
||||||
|
it.element.location(),
|
||||||
|
it.indented(
|
||||||
|
[*#__caption-label(it.element)*],
|
||||||
|
[ #it.inner()], gap: 0pt
|
||||||
|
),
|
||||||
|
)
|
||||||
|
o
|
||||||
}
|
}
|
||||||
outline(depth: depth, indent: indent, target: target, title: title)
|
}
|
||||||
|
outline(depth: depth, indent: indent, target: target, title: title)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doesn't work in Typst 0.12.0 due to relative paths
|
// Doesn't work in Typst 0.12.0 due to relative paths
|
||||||
#let bibliography-list(path) = {
|
#let bibliography-list(path) = {
|
||||||
bibliography(path, title: "Literatūros sąrašas", full: true)
|
bibliography(path, title: "Literatūros sąrašas", full: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a KTU style conformant outline.
|
/// Returns a KTU style conformant outline.
|
||||||
@@ -318,24 +256,28 @@
|
|||||||
/// - title (auto | content | none): Same as outline title.
|
/// - title (auto | content | none): Same as outline title.
|
||||||
/// -> outline
|
/// -> outline
|
||||||
#let ktu-outline(
|
#let ktu-outline(
|
||||||
depth: none,
|
depth: none,
|
||||||
indent: 0em, // Disable the default outline indenting
|
indent: 0em, // Disable the default outline indenting
|
||||||
target: heading,
|
target: heading,
|
||||||
title: auto
|
title: auto,
|
||||||
) = {
|
) = {
|
||||||
__ktu_outline(depth: depth, indent: indent, target: target, title: title)
|
__ktu_outline(depth: depth, indent: indent, target: target, title: title)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let ktu-table-of-contents(depth: 3) = {
|
#let ktu-table-of-contents(depth: 3) = {
|
||||||
ktu-outline(target: heading, title: "Turinys", depth: depth)
|
ktu-outline(target: heading, title: "Turinys", depth: depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let ktu-table-list() = {
|
#let ktu-table-list() = {
|
||||||
ktu-outline(title: heading("Lentelių sąrašas", outlined: true), target: figure.where(kind: table))
|
ktu-outline(title: heading("Lentelių sąrašas", outlined: true), target: figure.where(kind: table))
|
||||||
}
|
}
|
||||||
|
|
||||||
#let ktu-picture-list() = {
|
#let ktu-picture-list() = {
|
||||||
ktu-outline(title: heading("Paveikslų sąrašas", outlined: true), target: figure.where(kind: image))
|
ktu-outline(title: heading("Paveikslų sąrašas", outlined: true), target: figure.where(kind: image))
|
||||||
|
}
|
||||||
|
|
||||||
|
#let ktu-code-list() = {
|
||||||
|
ktu-outline(title: heading("Kodo fragmentų sąrašas", outlined: true), target: figure.where(kind: raw))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define a custom outline for a specific figure type.
|
/// Define a custom outline for a specific figure type.
|
||||||
@@ -344,187 +286,234 @@
|
|||||||
/// - title (str): Title of the outline
|
/// - title (str): Title of the outline
|
||||||
/// - kind (str): Type of the figure
|
/// - kind (str): Type of the figure
|
||||||
#let custom-list(title, kind) = {
|
#let custom-list(title, kind) = {
|
||||||
__ktu_outline(title: heading(title, outlined: true), target: figure.where(kind: kind))
|
__ktu_outline(title: heading(title, outlined: true), target: figure.where(kind: kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
#let setup-code(body) = {
|
/// Lets figures in `body` split across pages: the body may break, the caption stays
|
||||||
show: codly-init.with()
|
/// attached to its start (a caption at the bottom may end up alone, see `figureLayout`).
|
||||||
codly(
|
/// Use it to opt out of keeping a figure on one page, e.g. for a long code listing.
|
||||||
fill: white,
|
/// - body (content): Content containing figures.
|
||||||
zebra-fill: none,
|
/// -> content
|
||||||
stroke: none,
|
#let breakable-figures(body) = __with-break-override(true, body)
|
||||||
display-name: false,
|
|
||||||
display-icon: false,
|
/// Keeps every figure in `body` on one page: body and caption move to the next
|
||||||
|
/// page together. Use it to opt out of splitting, e.g. for a short table.
|
||||||
|
/// - body (content): Content containing figures.
|
||||||
|
/// -> content
|
||||||
|
#let unbreakable-figures(body) = __with-break-override(false, body)
|
||||||
|
|
||||||
|
/// `code` option defaults for the library entrypoint.
|
||||||
|
#let __CODE_DEFAULTS = (
|
||||||
|
font: "Hack",
|
||||||
|
spacing: 80%,
|
||||||
|
fill: white,
|
||||||
|
stroke: 0.5pt + black,
|
||||||
|
numbers: true,
|
||||||
|
radius: 0pt,
|
||||||
|
display-name: false,
|
||||||
|
display-icon: false,
|
||||||
|
)
|
||||||
|
|
||||||
|
/// Applies the code block styling to the body.
|
||||||
|
/// - code (dictionary | none): Options, merged over `__CODE_DEFAULTS`.
|
||||||
|
/// `none` leaves raw blocks untouched.
|
||||||
|
#let __setup-code(code, body) = {
|
||||||
|
if code == none {
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
let opts = __CODE_DEFAULTS + code
|
||||||
|
let known = __CODE_DEFAULTS.keys()
|
||||||
|
for key in opts.keys() {
|
||||||
|
assert(
|
||||||
|
key in known,
|
||||||
|
message: "ktu-paper: unknown `code` option \"" + key + "\", expected one of: " + known.join(", "),
|
||||||
)
|
)
|
||||||
show raw: set text(font: "Hack", spacing: 80%)
|
}
|
||||||
body
|
|
||||||
|
show raw.where(block: true): codly.new
|
||||||
|
show: codly.set_(number-enabled: opts.numbers, radius: opts.radius)
|
||||||
|
show: codly.line-set_(fill: opts.fill, stroke: opts.stroke)
|
||||||
|
show: codly.lang-set_(
|
||||||
|
display-name: opts.display-name,
|
||||||
|
display-icon: opts.display-icon,
|
||||||
|
)
|
||||||
|
show raw: set text(font: opts.font, spacing: opts.spacing)
|
||||||
|
body
|
||||||
}
|
}
|
||||||
|
|
||||||
#let __page_rules(font: "Times New Roman", body) = {
|
#let __page_rules(font: "Times New Roman", body) = {
|
||||||
// Page size and margins
|
// Page size and margins
|
||||||
set page(
|
set page(
|
||||||
paper: "a4",
|
paper: "a4",
|
||||||
width: 210mm,
|
width: 210mm,
|
||||||
height: 297mm,
|
height: 297mm,
|
||||||
margin: (
|
margin: (
|
||||||
left: 30mm,
|
left: 30mm,
|
||||||
right: 10mm,
|
right: 10mm,
|
||||||
bottom: 20mm,
|
bottom: 20mm,
|
||||||
top: 20mm
|
top: 20mm,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
set page(width: 595pt, height: 842pt)
|
set page(width: 595pt, height: 842pt)
|
||||||
|
|
||||||
// Numbering rules
|
// Numbering rules
|
||||||
set page(numbering: none, number-align: right)
|
set page(numbering: none, number-align: right)
|
||||||
|
|
||||||
// Use Lithuanian quotes
|
// Use Lithuanian quotes
|
||||||
set smartquote(quotes: "„“")
|
set smartquote(quotes: "„“")
|
||||||
|
|
||||||
// Heading numbering
|
// Heading numbering
|
||||||
set heading(numbering: "1.")
|
set heading(numbering: "1.")
|
||||||
|
|
||||||
// Number equations
|
// Number equations
|
||||||
set math.equation(numbering: "(1)")
|
set math.equation(numbering: __equation-numbering)
|
||||||
|
|
||||||
// Set text font
|
// Set text font
|
||||||
set text(
|
set text(
|
||||||
font: font,
|
font: font,
|
||||||
size: 12pt,
|
size: 12pt,
|
||||||
lang: "lt",
|
lang: "lt",
|
||||||
// Change where the bounding box is drawn for the text
|
// Change where the bounding box is drawn for the text
|
||||||
top-edge: "ascender",
|
top-edge: "ascender",
|
||||||
bottom-edge: "descender",
|
bottom-edge: "descender",
|
||||||
kerning: false, // Disable kerning
|
kerning: false, // Disable kerning
|
||||||
)
|
)
|
||||||
|
|
||||||
// Text line interval, defined differently in Typst
|
// Text line interval, defined differently in Typst
|
||||||
let leading = 1.15em // Your line spacing (1, 1.5, 2, etc.)
|
let leading = 1.15em // Your line spacing (1, 1.5, 2, etc.)
|
||||||
let leading = leading - 0.75em // "Normalization"
|
let leading = leading - 0.75em // "Normalization"
|
||||||
set par(leading: leading)
|
set par(leading: leading)
|
||||||
|
|
||||||
// Indentation for lists and enumerations
|
// Indentation for lists and enumerations
|
||||||
set enum(indent: 12pt)
|
set enum(indent: 12pt)
|
||||||
set list(indent: 12pt)
|
set list(indent: 12pt)
|
||||||
|
|
||||||
body
|
body
|
||||||
}
|
}
|
||||||
|
|
||||||
#let setup-page(
|
#let setup-page(
|
||||||
font: "Times New Roman",
|
font: "Times New Roman",
|
||||||
uppercaseSectionTitles: false,
|
uppercaseSectionTitles: false,
|
||||||
unnumberedHeadingAlignment: center,
|
unnumberedHeadingAlignment: center,
|
||||||
body
|
body,
|
||||||
) = {
|
) = {
|
||||||
show: __page_rules.with(font: font)
|
show: __page_rules.with(font: font)
|
||||||
|
|
||||||
// Pagal formaliuosius rašto darbų reikalavimus
|
// Pagal formaliuosius rašto darbų reikalavimus
|
||||||
|
|
||||||
// Tarpas tarp teksto pastraipų
|
// Tarpas tarp teksto pastraipų
|
||||||
set par(spacing: 10pt)
|
set par(spacing: 10pt)
|
||||||
|
set block(below: 10pt)
|
||||||
|
|
||||||
|
// Teksto lygiuotė, abipusė
|
||||||
|
set par(justify: true)
|
||||||
|
set linebreak(justify: true)
|
||||||
|
|
||||||
|
let maybe-uppercase(body) = {
|
||||||
|
if uppercaseSectionTitles {
|
||||||
|
upper(body)
|
||||||
|
} else {
|
||||||
|
body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Antraštės
|
||||||
|
// Force them into blocks so they don't count as paragraphs
|
||||||
|
show heading: it => {
|
||||||
|
// Align everything left
|
||||||
|
set align(left)
|
||||||
|
|
||||||
|
// Visų antraščių teksto dydis vienodas
|
||||||
|
// Visų antraščių teksto šifras paryškintas
|
||||||
|
set text(size: 12pt)
|
||||||
set block(below: 10pt)
|
set block(below: 10pt)
|
||||||
|
|
||||||
// Teksto lygiuotė, abipusė
|
let useExperiment = __HEADING_EXPERIMENT.get()
|
||||||
set par(justify: true)
|
|
||||||
set linebreak(justify: true)
|
|
||||||
|
|
||||||
let maybe-uppercase(body) = {
|
// TODO: intervalas tarp eilučių – 1,15 kiekvienai antraštei
|
||||||
if uppercaseSectionTitles {
|
|
||||||
upper(body)
|
// Priedas: kiekvienas pradedamas naujame lape, dešiniajame viršutiniame
|
||||||
} else {
|
// kampe rašoma "N priedas", pavadinimas (jei yra) – kaip skyriaus pavadinimas
|
||||||
body
|
if __is-appendix-heading(it) {
|
||||||
}
|
align(right, block(below: 10pt, text(weight: "regular")[
|
||||||
|
#__appendix-number(it) #__figure-kinds.appendix.supplement
|
||||||
|
]))
|
||||||
|
let title = __appendix-title(it)
|
||||||
|
if title != none {
|
||||||
|
block(below: 10pt, title)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Antraštės
|
// Antraštė be nr.
|
||||||
// Force them into blocks so they don't count as paragraphs
|
if it.numbering == none {
|
||||||
show heading: it => {
|
// Centruota lygiuotė by default, but can be overridden by the user
|
||||||
// Align everything left
|
let explicitlyAlignLeft = (
|
||||||
set align(left)
|
it.body.has("children")
|
||||||
|
and it.body.children.len() > 1
|
||||||
|
and it.body.children.at(1) == __METADATA_HEADING_ALIGN_LEFT
|
||||||
|
)
|
||||||
|
|
||||||
// Visų antraščių teksto dydis vienodas
|
// If the user explicitly set alignLeft to true, we should align left regardless of the global setting
|
||||||
// Visų antraščių teksto šifras paryškintas
|
let targetAlign = if explicitlyAlignLeft { left } else { unnumberedHeadingAlignment }
|
||||||
set text(size: 12pt)
|
|
||||||
set block(below: 10pt)
|
|
||||||
|
|
||||||
let useExperiment = __HEADING_EXPERIMENT.get()
|
set align(targetAlign)
|
||||||
|
|
||||||
// TODO: intervalas tarp eilučių – 1,15 kiekvienai antraštei
|
// atstumas prieš ir po antraštės - 10 pt
|
||||||
|
block[#maybe-uppercase(it.body)]
|
||||||
// Antraštė be nr.
|
if useExperiment {
|
||||||
if it.numbering == none {
|
v(10pt)
|
||||||
// Centruota lygiuotė by default, but can be overridden by the user
|
}
|
||||||
let explicitlyAlignLeft = it.body.has("children") and it.body.children.len() > 1 and it.body.children.at(1) == __METADATA_HEADING_ALIGN_LEFT
|
|
||||||
|
|
||||||
// If the user explicitly set alignLeft to true, we should align left regardless of the global setting
|
|
||||||
let targetAlign = if explicitlyAlignLeft { left } else { unnumberedHeadingAlignment }
|
|
||||||
|
|
||||||
set align(targetAlign)
|
|
||||||
|
|
||||||
// atstumas prieš ir po antraštės - 10 pt
|
|
||||||
block[#maybe-uppercase(it.body)]
|
|
||||||
if useExperiment {
|
|
||||||
v(10pt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Skyrius
|
|
||||||
if it.numbering != none and it.level == 1 {
|
|
||||||
// abipusė lygiuotė
|
|
||||||
set par(justify: true)
|
|
||||||
|
|
||||||
// Reset figure counters if numbering per section is enabled
|
|
||||||
if __FIG_PER_SECTION.get() {
|
|
||||||
counter(figure.where(kind: image)).update(0)
|
|
||||||
counter(figure.where(kind: table)).update(0)
|
|
||||||
counter(figure.where(kind: raw)).update(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// po antraštės - 10 pt
|
|
||||||
block[#counter(heading).display() #maybe-uppercase(it.body)]
|
|
||||||
if useExperiment {
|
|
||||||
v(10pt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine whether the heading has appending metadata attached and adjust its display accordingly
|
|
||||||
let isAppendixHeading = it.body.has("children") and it.body.children.at(0) == metadata("appendix-heading")
|
|
||||||
if isAppendixHeading {
|
|
||||||
block[#counter(heading).display(it.numbering) #it.body]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Poskyris ir skyrelis
|
|
||||||
if not isAppendixHeading and it.numbering != none and it.level != 1 {
|
|
||||||
// abipusė lygiuotė
|
|
||||||
set par(justify: true)
|
|
||||||
|
|
||||||
// prieš ir po antraštės - 10 pt
|
|
||||||
if useExperiment {
|
|
||||||
v(10pt)
|
|
||||||
}
|
|
||||||
block[#counter(heading).display() #it.body]
|
|
||||||
if useExperiment {
|
|
||||||
v(10pt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference style and numbering
|
// Skyrius
|
||||||
show ref: it => __format-ref(it)
|
if it.numbering != none and it.level == 1 {
|
||||||
|
// abipusė lygiuotė
|
||||||
|
set par(justify: true)
|
||||||
|
|
||||||
// Figure captions and numbering
|
// Reset figure counters if numbering per section is enabled
|
||||||
show figure: it => __format-figure(it)
|
if __FIG_PER_SECTION.get() {
|
||||||
|
__reset-figure-counters()
|
||||||
|
}
|
||||||
|
|
||||||
// Bibliography citing style
|
// po antraštės - 10 pt
|
||||||
set bibliography(style: "assets/iso690-numeric-lt.csl")
|
block[#counter(heading).display() #maybe-uppercase(it.body)]
|
||||||
|
if useExperiment {
|
||||||
// Block equations are left-aligned
|
v(10pt)
|
||||||
show math.equation.where(block: true): it => {
|
}
|
||||||
align(left, it)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body
|
// Poskyris ir skyrelis
|
||||||
|
if it.numbering != none and it.level != 1 {
|
||||||
|
// abipusė lygiuotė
|
||||||
|
set par(justify: true)
|
||||||
|
|
||||||
|
// prieš ir po antraštės - 10 pt
|
||||||
|
if useExperiment {
|
||||||
|
v(10pt)
|
||||||
|
}
|
||||||
|
block[#counter(heading).display() #it.body]
|
||||||
|
if useExperiment {
|
||||||
|
v(10pt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference style and numbering
|
||||||
|
show ref: it => __format-ref(it)
|
||||||
|
|
||||||
|
// Figure captions and numbering
|
||||||
|
show figure: it => __format-figure(it)
|
||||||
|
|
||||||
|
// Bibliography citing style
|
||||||
|
set bibliography(style: "assets/iso690-numeric-lt.csl")
|
||||||
|
|
||||||
|
// Block equations are left-aligned
|
||||||
|
show math.equation.where(block: true): it => {
|
||||||
|
align(left, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configure the template for a KTU paper.
|
/// Configure the template for a KTU paper.
|
||||||
@@ -532,22 +521,53 @@
|
|||||||
/// - figureNumberingPerSection (bool): Whether to number figures per section rather than globally.
|
/// - figureNumberingPerSection (bool): Whether to number figures per section rather than globally.
|
||||||
/// - uppercaseSectionTitles (bool): Whether to uppercase section titles.
|
/// - uppercaseSectionTitles (bool): Whether to uppercase section titles.
|
||||||
/// - unnumberedHeadingAlignment (alignment): Alignment for unnumbered headings.
|
/// - unnumberedHeadingAlignment (alignment): Alignment for unnumbered headings.
|
||||||
|
/// - figureKinds (dictionary): Extra figure kinds, e.g.
|
||||||
|
/// `(command: (supplement: "komanda", ref-name: "komanda", single-name: "komanda"))`.
|
||||||
|
/// Use them with `figure(kind: "command", ...)`. Keys:
|
||||||
|
/// - `supplement` (required): text after the number in captions, e.g. "1 komanda.".
|
||||||
|
/// - `ref-name`: text used in references, e.g. "(žr. 1 komanda)". Defaults to `supplement`.
|
||||||
|
/// Can also be a function `count => string`, called with the number of elements
|
||||||
|
/// referenced together, for kinds whose wording depends on it, e.g.
|
||||||
|
/// `count => if count == 1 { "komandą" } else { "komandas" }`.
|
||||||
|
/// - `single-name`: full word used when the figure is the only one of its kind
|
||||||
|
/// and is left unnumbered, e.g. "Komanda." and "(žr. komanda)". Defaults to `supplement`.
|
||||||
|
/// Currently only tables and images are left unnumbered when single, so this only matters for kinds added there.
|
||||||
|
/// - figureLayout (dictionary): Page-break behaviour and caption position per figure kind,
|
||||||
|
/// `(kind: (breakable: bool, caption: top | bottom))`, every field optional. Kinds are
|
||||||
|
/// `table`, `image`, `raw` (code), or a key of `figureKinds`. Defaults: `table` and `raw`
|
||||||
|
/// are breakable; everything else is unbreakable. Example: `(raw: (breakable: false, caption: bottom))`.
|
||||||
|
/// A breakable figure's top caption stays attached to the start of the body.
|
||||||
|
/// Use `breakable-figures[...]` / `unbreakable-figures[...]` to override it locally.
|
||||||
|
/// - code (dictionary | none): Code block configuration, or `none` to leave raw blocks unstyled. Keys:
|
||||||
|
/// - `font` (str): Monospace font. Defaults to "Hack".
|
||||||
|
/// - `spacing` (relative): Word spacing of code text. Defaults to `80%`.
|
||||||
|
/// - `fill` (paint): Background of code lines. Defaults to `white`.
|
||||||
|
/// - `stroke` (stroke | none): Outline around the code block. Defaults to `0.5pt + black`; `none` removes it.
|
||||||
|
/// - `numbers` (bool): Show line numbers. Defaults to `true`.
|
||||||
|
/// - `radius` (length): Corner radius of the outline. Defaults to `0pt` (square corners).
|
||||||
|
/// - `display-name` (bool): Show the language name badge. Defaults to `false`.
|
||||||
|
/// - `display-icon` (bool): Show the language icon badge. Defaults to `false`.
|
||||||
#let ktu-paper(
|
#let ktu-paper(
|
||||||
font: "Times New Roman",
|
font: "Times New Roman",
|
||||||
figureNumberingPerSection: false,
|
figureNumberingPerSection: false,
|
||||||
// Not sure about formal conformity of deviating
|
figureKinds: (:),
|
||||||
// from the defaults of the next options,
|
figureLayout: (:),
|
||||||
// but some modules may require them
|
code: (:),
|
||||||
uppercaseSectionTitles: false,
|
// Not sure about formal conformity of deviating
|
||||||
unnumberedHeadingAlignment: center,
|
// from the defaults of the next options,
|
||||||
body
|
// but some modules may require them
|
||||||
) = context {
|
uppercaseSectionTitles: false,
|
||||||
show: setup-page.with(
|
unnumberedHeadingAlignment: center,
|
||||||
font: font,
|
body,
|
||||||
uppercaseSectionTitles: uppercaseSectionTitles,
|
) = context {
|
||||||
unnumberedHeadingAlignment: unnumberedHeadingAlignment,
|
show: setup-page.with(
|
||||||
)
|
font: font,
|
||||||
__FIG_PER_SECTION.update(figureNumberingPerSection)
|
uppercaseSectionTitles: uppercaseSectionTitles,
|
||||||
__UPPERCASE_SECTION_TITLES.update(uppercaseSectionTitles)
|
unnumberedHeadingAlignment: unnumberedHeadingAlignment,
|
||||||
body
|
)
|
||||||
|
__FIG_PER_SECTION.update(figureNumberingPerSection)
|
||||||
|
__USER_FIGURE_KINDS.update(__normalize-figure-kinds(figureKinds))
|
||||||
|
__USER_FIGURE_LAYOUT.update(__normalize-figure-layout(figureLayout))
|
||||||
|
__UPPERCASE_SECTION_TITLES.update(uppercaseSectionTitles)
|
||||||
|
__setup-code(code, body)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
#import "@local/ktu-paper:0.5.1": (
|
||||||
|
ktu-paper,
|
||||||
|
ktu-table-of-contents, ktu-picture-list, ktu-table-list, ktu-code-list,
|
||||||
|
ktu-heading-page-normal,
|
||||||
|
ktu-gen-ai-usage-declaration-page,
|
||||||
|
ktu-table,
|
||||||
|
unnumbered-heading,
|
||||||
|
custom-ref, ref-no
|
||||||
|
)
|
||||||
|
|
||||||
|
#show: ktu-paper.with(
|
||||||
|
font: "Times New Roman", // or Arial
|
||||||
|
figureNumberingPerSection: true,
|
||||||
|
figureKinds: (
|
||||||
|
veryCustomKind: (supplement: "komanda", ref-name: "komanda"),
|
||||||
|
),
|
||||||
|
// Code blocks, `code: none` to disable styling
|
||||||
|
code: (
|
||||||
|
font: "Hack",
|
||||||
|
spacing: 80%,
|
||||||
|
fill: white,
|
||||||
|
stroke: 0.5pt + black,
|
||||||
|
numbers: true,
|
||||||
|
radius: 0pt,
|
||||||
|
display-name: false,
|
||||||
|
display-icon: false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Replace dots in equations with commas instead so 1.25 becomes 1,25.
|
||||||
|
#show math.equation: it => {
|
||||||
|
show regex("\d+\.\d+"): it => {show ".": {","+h(0pt)}
|
||||||
|
it}
|
||||||
|
it
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be used for writing purposes to mark TODOs in the document. They will be highlighted in yellow and have a dashed border.
|
||||||
|
#let todo(desc) = block(
|
||||||
|
width: 100%, inset: 10pt, stroke: (dash: "dashed"), fill: yellow.lighten(80%),
|
||||||
|
[*TODO:* #desc],
|
||||||
|
)
|
||||||
|
|
||||||
|
#ktu-heading-page-normal(
|
||||||
|
faculty: highlight[Informatikos fakultetas],
|
||||||
|
title: highlight[Laboratorinio darbo ataskaitos pavadinimas],
|
||||||
|
subtitles: (
|
||||||
|
"Laboratorinio darbo ataskaita",
|
||||||
|
highlight[Studijų modulio pavadinimas (kodas)]
|
||||||
|
),
|
||||||
|
authors: (
|
||||||
|
(highlight[Vardenis Pavardenis], "Ataskaitą parengė"),
|
||||||
|
(highlight[Pareigų ir mokslo laipsnio sutrumpinimas Vardenis Pavardenis], "Laboratoriniam darbui vadovavo"),
|
||||||
|
),
|
||||||
|
authorNamesFirst: false,
|
||||||
|
place: "Kaunas",
|
||||||
|
year: datetime.today().year(),
|
||||||
|
)
|
||||||
|
#pagebreak()
|
||||||
|
#set page(numbering: "1")
|
||||||
|
|
||||||
|
#ktu-table-of-contents()
|
||||||
|
#pagebreak()
|
||||||
|
|
||||||
|
#ktu-picture-list()
|
||||||
|
#pagebreak()
|
||||||
|
|
||||||
|
#ktu-table-list()
|
||||||
|
#pagebreak()
|
||||||
|
|
||||||
|
#ktu-code-list()
|
||||||
|
#pagebreak()
|
||||||
|
|
||||||
|
#unnumbered-heading[= Įvadas]
|
||||||
|
#lorem(50)
|
||||||
|
|
||||||
|
#pagebreak()
|
||||||
|
= Skyrius
|
||||||
|
#lorem(50)
|
||||||
|
|
||||||
|
== Poskyrius
|
||||||
|
#lorem(50)
|
||||||
|
|
||||||
|
=== Dalis
|
||||||
|
#lorem(50)
|
||||||
|
|
||||||
|
#pagebreak()
|
||||||
|
= Komponentai
|
||||||
|
|
||||||
|
== Paveikslai
|
||||||
|
Galima gauti paveikslo numerį #ref-no(<image-label>) arba visą paveikslo nuorodą #custom-ref(<image-label>).
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
image("images/santaka.png", width: 70%),
|
||||||
|
caption: [
|
||||||
|
Paveikslo pavadinimas
|
||||||
|
],
|
||||||
|
) <image-label>
|
||||||
|
|
||||||
|
|
||||||
|
== Paveikslų "grid" išdėstymas
|
||||||
|
Paveikslus taip pat galima sudėti į "grid" išdėstymą, į jį kreiptis kaip numerį #ref-no(<image-grid-label>) arba visą nuorodą #custom-ref(<image-grid-label>).
|
||||||
|
|
||||||
|
#figure(grid(
|
||||||
|
columns: 2,
|
||||||
|
gutter: 2mm,
|
||||||
|
image("images/santaka.png", width: 100%),
|
||||||
|
image("images/santaka.png", width: 100%),
|
||||||
|
), caption: [
|
||||||
|
Paveikslėliai "grid'e"
|
||||||
|
]) <image-grid-label>
|
||||||
|
|
||||||
|
|
||||||
|
== Lentelės
|
||||||
|
|
||||||
|
Galima gauti lentelės numerį /*#ref-no(<table-label>)*/ arba visą lentelės nuorodą #custom-ref(<table-label>).
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
ktu-table(
|
||||||
|
columns: (auto, 1fr, 1fr, 1fr),
|
||||||
|
align: (x, y) => { horizon + left },
|
||||||
|
table.header([*Stulpelio pavadinimas*], [*Stulpelio pavadinimas*], [*Stulpelio pavadinimas*], [*Stulpelio pavadinimas*]),
|
||||||
|
[Eilutė 1], [...], [...], [...],
|
||||||
|
[Eilutė 2], [...], [...], [...],
|
||||||
|
[Eilutė 3], [...], [...], [...],
|
||||||
|
[Eilutė 4], [...], [...], [...],
|
||||||
|
),
|
||||||
|
caption: [Lentelės pavadinimas],
|
||||||
|
) <table-label>
|
||||||
|
|
||||||
|
|
||||||
|
== Formulės
|
||||||
|
Formules galima išreikšti eilutėje, pavyzdžiui $E = m c^2$ arba atskiroje eilutėje, pavyzdžiui:
|
||||||
|
$
|
||||||
|
E = m c^2
|
||||||
|
$ <formula-label>
|
||||||
|
|
||||||
|
// TODO: fix
|
||||||
|
Formulės atskiroje eilutėje numeruojamos besąlygiškai, galima gauti formulės numerį #ref-no(<formula-label>) arba visą formulės nuorodą #custom-ref(<formula-label>).
|
||||||
|
|
||||||
|
== Kodo fragmentai
|
||||||
|
Kodo fragmentus galima išreikšti eilutėje, pavyzdžiui `print("Hello, world!")` arba atskiroje eilutėje, pavyzdžiui:
|
||||||
|
#figure(```python
|
||||||
|
def main():
|
||||||
|
print("Hello, world!")
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
```, caption: [
|
||||||
|
Python kodas
|
||||||
|
]) <code-label>
|
||||||
|
|
||||||
|
Galima gauti kodo fragmento numerį #ref-no(<code-label>) arba visą kodo fragmento nuorodą #custom-ref(<code-label>).
|
||||||
|
|
||||||
|
== Naudotojo apibrėžtos figūros
|
||||||
|
|
||||||
|
Naudotojai tai pat gali apibrėžti savo figūras, pavyzdžiui, komandų fragmentus. Pavyzdžiui, galima apibrėžti komandų fragmentą su papildoma informacija ir naudoti jį dokumente. Galima gauti kodo fragmento numerį #ref-no(<custom-figure-label>) arba visą kodo fragmento nuorodą #custom-ref(<custom-figure-label>).
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
```sh
|
||||||
|
npm install foo
|
||||||
|
```,
|
||||||
|
kind: "veryCustomKind",
|
||||||
|
supplement: "...",
|
||||||
|
caption: [Diegimo komanda],
|
||||||
|
) <custom-figure-label>
|
||||||
|
|
||||||
|
#pagebreak()
|
||||||
|
= Išvados
|
||||||
|
#lorem(50)
|
||||||
|
|
||||||
|
#pagebreak()
|
||||||
|
#ktu-gen-ai-usage-declaration-page()
|
||||||
+2
-3
@@ -1,5 +1,5 @@
|
|||||||
#import "@local/ktu-paper:0.3.1": (
|
#import "@local/ktu-paper:0.5.1": (
|
||||||
ktu-paper, setup-code,
|
ktu-paper,
|
||||||
ktu-table-of-contents, ktu-picture-list, ktu-table-list,
|
ktu-table-of-contents, ktu-picture-list, ktu-table-list,
|
||||||
ktu-heading-page-normal,
|
ktu-heading-page-normal,
|
||||||
ktu-table,
|
ktu-table,
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
#show: ktu-paper.with(
|
#show: ktu-paper.with(
|
||||||
font: "Times New Roman",
|
font: "Times New Roman",
|
||||||
)
|
)
|
||||||
#show: setup-code.with()
|
|
||||||
|
|
||||||
#show math.equation: it => {
|
#show math.equation: it => {
|
||||||
show regex("\d+\.\d+"): it => {show ".": {","+h(0pt)}
|
show regex("\d+\.\d+"): it => {show ".": {","+h(0pt)}
|
||||||
|
|||||||
+2
-3
@@ -1,5 +1,5 @@
|
|||||||
#import "@local/ktu-paper:0.3.1": (
|
#import "@local/ktu-paper:0.5.1": (
|
||||||
ktu-paper, setup-code,
|
ktu-paper,
|
||||||
ktu-table-of-contents, ktu-picture-list, ktu-table-list,
|
ktu-table-of-contents, ktu-picture-list, ktu-table-list,
|
||||||
ktu-heading-page-normal,
|
ktu-heading-page-normal,
|
||||||
ktu-table,
|
ktu-table,
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
#show: ktu-paper.with(
|
#show: ktu-paper.with(
|
||||||
font: "Times New Roman",
|
font: "Times New Roman",
|
||||||
)
|
)
|
||||||
#show: setup-code.with()
|
|
||||||
|
|
||||||
#show figure: it => {
|
#show figure: it => {
|
||||||
set block(breakable: true)
|
set block(breakable: true)
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ktu-paper"
|
name = "ktu-paper"
|
||||||
version = "0.3.1"
|
version = "0.5.1"
|
||||||
compiler = "0.15.0"
|
compiler = "0.15.0"
|
||||||
entrypoint = "src/lib.typ"
|
entrypoint = "src/lib.typ"
|
||||||
repository = "https://github.com/svetikas/ktu-paper"
|
repository = "https://github.com/svetikas/ktu-paper"
|
||||||
|
|||||||
Reference in new issue
Block a user