18 Commits
Author SHA1 Message Date
JustAnyone ed5a62c659 chore: bump version to 0.5.0 2026-10-25 18:51:43 +02:00
JustAnyone f078b8ae00 refactor: update to codly 2.0.0, move code configuration to ktu-paper instead of setup-code 2026-10-25 18:48:59 +02:00
JustAnyone 321703ddbc fix: appendix numbering was broken and did not respect 2025 requirements
Resolves #1 and #2
2026-10-25 17:53:01 +02:00
JustAnyone c15747ce98 fix: test.typ was not updated for new version 2026-10-18 17:26:45 +03:00
JustAnyone ada5bc3f63 chore: bump version to 0.4.1 2026-10-18 17:24:57 +03:00
JustAnyone e5c774f96c feat: add support for figure names without numbering if they're single 2026-10-18 17:23:52 +03:00
JustAnyone b803a906ea chore: bump version to 0.4.0 2026-10-15 00:24:39 +03:00
JustAnyone 71b83ab97f style: use consistent 2 space indentation 2026-10-15 00:21:18 +03:00
JustAnyone f8a747e6b3 refactor: add support for custom figure kinds
This also fixes some bugs with referencing figures in elements such as align,
this also generalizes the logic to handle nesting.

#__format-ref show rule now goes through #custom-ref most of the time,
so builtin #ref can be used instead.

Equations are now referenceable and respect numbering per sections.
2026-10-15 00:05:23 +03:00
JustAnyone dfac289590 chore: bump version to 0.3.2 2026-09-28 10:44:44 +03:00
JustAnyone 1740adfc5a feat: expose ktu-author-table and ktu-title-header-block 2026-09-28 10:43:21 +03:00
JustAnyone 55a236fe8b feat: add support for flipping the order of role and name in author table 2026-09-28 10:42:49 +03:00
JustAnyone d0d7d2a197 chore: bump version to 0.3.1 2026-09-21 18:27:15 +03:00
JustAnyone 9736619563 chore: move template images to a separate directory 2026-09-21 18:05:37 +03:00
JustAnyone 340c5ab92c feat: support custom alignment for unnumbered headings 2026-09-21 18:00:36 +03:00
JustAnyone 59d197f291 feat: support specifying department in heading page fragment 2026-09-21 17:37:29 +03:00
JustAnyone f8001593dd style: spelling mistake 2026-09-21 17:20:26 +03:00
JustAnyone 1ff507941d fix: math equation blocks were not left aligned 2026-09-21 17:18:29 +03:00
10 changed files with 778 additions and 291 deletions

No files matched your search

+5 -3
View File
@@ -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.2.1/` - Linux: `~/.local/share/typst/packages/local/ktu-paper/0.5.0/`
And then initiate a new project: And then initiate a new project:
```sh ```sh
typst init @local/ktu-paper:0.2.1 typst init @local/ktu-paper:0.5.0
``` ```
+349 -90
View File
@@ -1,137 +1,396 @@
// 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 referencable 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).
/// Must be called in a context.
#let __reset-figure-counters() = {
let custom = (..__USER_FIGURE_KINDS.get().keys(),)
for kind in (image, table, raw, ..custom) {
counter(figure.where(kind: kind)).update(0)
} }
if func == image { counter(math.equation).update(0)
return "pav."
}
if func == grid {
return "pav."
}
return func
} }
/// 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 figNum = counter(figure.where(kind: fig-item.kind)).at(loc).at(0, default: 1) let fig-num = fig-counter.at(loc).at(0, default: 1)
str(chapter) + "." + str(figNum) str(chapter) + "." + str(fig-num)
} else { } else {
let caption = fig-item.caption str(fig-counter.at(loc).at(0))
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
/// first child (or as their whole body, when the appendix has no title) and
/// are numbered separately from normal headings.
#let __is-appendix-heading(item) = {
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()))
}
if group-key != none and group-key != key {
panic("custom-ref does not support grouping different elements together")
}
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 __format-ref(it) = {
let el = it.element let el = it.element
if el == none { if el == none { return it }
return it
}
// Override equation references
if el.func() == math.equation { if el.func() == math.equation {
link( let loc = el.location()
el.location(), link(loc, "(" + __get-equation-number(loc) + ")")
numbering(el.numbering, ..counter(math.equation).at(el.location())) } else if el.func() == figure and __figure-key(el) in __all-figure-kinds() {
) custom-ref(it.target)
// Override references to figures } else if el.func() == heading and __is-appendix-heading(el) {
} else if el.func() == figure { custom-ref(it.target)
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 { } else {
it it
} }
} }
// ---------------------------------------------------------------------------
// Figure layout
// ---------------------------------------------------------------------------
/// 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
let supplement = caption.supplement
if it.body.func() == math.equation {
supplement = __fig-supplement("equation")
} else {
supplement = __fig-supplement(it.kind)
}
set text(size: 11pt) set text(size: 11pt)
let fig-num = context __get-figure-number(it, here()) let caption-line = [*#__caption-label(it)* #caption.body]
// Tables have captions at the top // Tables have captions at the top
if it.kind == table { if it.kind == table {
align(left)[*#fig-num #supplement#separator* #caption.body] align(left, caption-line)
it.body it.body
} else { } else {
it.body it.body
align(center)[*#fig-num #supplement#separator* #caption.body] align(center, caption-line)
} }
} }
+79 -27
View File
@@ -17,6 +17,7 @@
#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")
@@ -51,29 +52,43 @@
table.header([]), table.header([]),
..for author in authors { ..for author in authors {
let (name, role) = author let (name, role) = author
(align(center)[ name = [*#name*]
if not namesFirst {
(role, name) = (name, role)
}
(
align(center)[
#set block(below: 8pt) #set block(below: 8pt)
#block[*#name*] #block[#name]
#block[#role] #block[#role]
], []) ],
[],
)
} }
)) ))
} else { } else {
align(alignment, table( align(alignment, table(
columns: (198.5pt, 56.7pt), columns: (198.5pt, 56.7pt),
table.header( table.header([], []),
[], [],
),
..for author in authors { ..for author in authors {
let (name, role) = author let (name, role) = author
(align(left)[ name = [*#name*]
if not namesFirst {
(role, name) = (name, role)
}
(
align(left)[
#set block(below: 8pt) #set block(below: 8pt)
#block[*#name*] #block[#name]
#block[#role] #block[#role]
], [], [], []) ],
} [],
[],
[],
)
},
)) ))
} }
} }
@@ -128,8 +143,9 @@
] ]
} }
#let ktu-heading-page-centered( #let ktu-heading-page(
faculty: highlight[Fakulteto pavadinimas], faculty: highlight[Fakulteto pavadinimas],
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: (
@@ -138,44 +154,80 @@
), ),
place: highlight[Kaunas], place: highlight[Kaunas],
year: highlight[#datetime.today().year()], year: highlight[#datetime.today().year()],
centerAuthors: false,
authorNamesFirst: true, // if false, roles will be displayed first
) = { ) = {
let isArr = type(subtitles) == array let subHeaders = (faculty,)
if not isArr { if department != none {
subHeaders = (faculty, department)
}
if type(subtitles) != array {
subtitles = (subtitles,) subtitles = (subtitles,)
} }
ktu-title-header-block( ktu-title-header-block(
subHeaders: (faculty,), subHeaders: subHeaders,
bigTitle: title, bigTitle: title,
subTitles: subtitles, subTitles: subtitles,
) )
v(94pt) v(94pt)
ktu-author-table(authors: authors, alignment: center) if centerAuthors {
ktu-author-table(authors: authors, namesFirst: authorNamesFirst, alignment: center)
} else {
ktu-author-table(authors: authors, namesFirst: authorNamesFirst)
}
align(center + bottom, block([*#place, #year*])) align(center + bottom, block([*#place, #year*]))
} }
#let ktu-heading-page-centered(
faculty: highlight[Fakulteto pavadinimas],
department: none, // optional
title: highlight[Rašto darbo pavadinimas],
subtitles: highlight[Praktikos ataskaita / referatas ir pan. (įrašyti rašto darbo tipą)],
authors: (
(highlight[Vardenis Pavardenis], highlight[Projekto autorius]),
(highlight[Vardenis Pavardenis], highlight[Vadovas]),
),
authorNamesFirst: true, // if false, roles will be displayed first
place: highlight[Kaunas],
year: highlight[#datetime.today().year()],
) = {
ktu-heading-page(
faculty: faculty,
department: department,
title: title,
subtitles: subtitles,
authors: authors,
place: place,
year: year,
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
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]),
), ),
authorNamesFirst: true, // if false, roles will be displayed first
place: highlight[Kaunas], place: highlight[Kaunas],
year: highlight[#datetime.today().year()], year: highlight[#datetime.today().year()],
) = { ) = {
let isArr = type(subtitles) == array ktu-heading-page(
if not isArr { faculty: faculty,
subtitles = (subtitles,) department: department,
} title: title,
ktu-title-header-block( subtitles: subtitles,
subHeaders: (faculty,), authors: authors,
bigTitle: title, place: place,
subTitles: subtitles, year: year,
centerAuthors: false,
authorNamesFirst: authorNamesFirst,
) )
v(94pt)
ktu-author-table(authors: authors)
align(center+bottom, block([*#place, #year*]))
} }
#let ktu-academic-honestly-declaration-page( #let ktu-academic-honestly-declaration-page(
@@ -186,7 +238,7 @@
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)
[ [
+171 -154
View File
@@ -1,17 +1,30 @@
#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-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
) )
#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,
__format-ref, __format-ref,
__format-figure, __format-figure,
__figure-kinds,
__is-appendix-heading,
__appendix-title,
__appendix-number,
) )
/** /**
@@ -24,22 +37,51 @@
* - 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");
/// ///
/// 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.
/// - text (str): The heading's title. /// - headingElement (heading): The heading's title.
/// - alignLeft (bool): Whether the heading should be left-aligned or centered.
/// -> /// ->
#let unnumbered-heading(text) = { #let unnumbered-heading(headingElement, alignLeft: false) = {
set heading(numbering: none) let fields = headingElement.fields()
[#text] let body = fields.body
let level = fields.at("level", default: 1)
if alignLeft {
body = body + __METADATA_HEADING_ALIGN_LEFT
} }
#let appendix-item(body) = { heading(level: level, numbering: none, body)
}
/// Insert an appendix (priedas).
///
/// Appendices are numbered 1, 2, 3, ... in the order they appear in the
/// document, so place them in the order they are first mentioned in the text.
/// 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( heading(
metadata("appendix-heading") + "priedas. " + body, if title == none { metadata("appendix-heading") } else { metadata("appendix-heading") + title },
level: 2, level: 2,
numbering: (..any) => {str(any.at(1))} numbering: none,
) )
} }
@@ -51,7 +93,6 @@
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()
let padding-needed = decimals - current-decimal-length let padding-needed = decimals - current-decimal-length
@@ -70,109 +111,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.
@@ -184,7 +122,7 @@
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)
@@ -202,18 +140,25 @@
show outline.entry: it => { show outline.entry: it => {
// Recompute the gap based on the prefix content, so that the outline entry is indented // 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) // from the left regardless of the length of the prefix (based on the requirement)
let prefixContent = it.prefix() let isAppendix = __is-appendix-heading(it.element)
let measurement = measure(prefixContent)
let target = targets.at(it.level - 1, default: 0.64cm) // Appendices are listed as "N priedas. Pavadinimas", the number being the prefix
let newGap = target - measurement.width let prefixContent = if isAppendix {
if it.element.body.has("children") and it.element.body.children.at(0) == metadata("appendix-heading") { context [#__appendix-number(it.element)]
target = 0.64cm } else {
it.prefix()
} }
let measurement = measure(prefixContent)
let target = if isAppendix { 0.64cm } else { targets.at(it.level - 1, default: 0.64cm) }
let newGap = target - measurement.width let newGap = target - measurement.width
// Uppercase body if need be // Uppercase body if need be
let bodyContent = it.element.body let bodyContent = it.element.body
if isUpper and (it.level == 1 or it.element.numbering == none) { 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) bodyContent = upper(bodyContent)
} }
@@ -242,7 +187,7 @@
show outline.entry: it => link( show outline.entry: it => link(
it.element.location(), it.element.location(),
it.indented( it.indented(
[*#__get-locatable-element-number(it.element) #__fig-supplement(image).*], [*#__caption-label(it.element)*],
[ #it.inner()], gap: 0pt [ #it.inner()], gap: 0pt
), ),
) )
@@ -253,7 +198,7 @@
show outline.entry: it => link( show outline.entry: it => link(
it.element.location(), it.element.location(),
it.indented( it.indented(
[*#__get-locatable-element-number(it.element) #__fig-supplement(table).*], [*#__caption-label(it.element)*],
[ #it.inner()], gap: 0pt [ #it.inner()], gap: 0pt
), ),
) )
@@ -264,7 +209,7 @@
show outline.entry: it => link( show outline.entry: it => link(
it.element.location(), it.element.location(),
it.indented( it.indented(
[*#__get-locatable-element-number(it.element) #__fig-supplement(raw).*], [*#__caption-label(it.element)*],
[ #it.inner()], gap: 0pt [ #it.inner()], gap: 0pt
), ),
) )
@@ -282,11 +227,12 @@
#(o.target == selector(heading)) #(o.target == selector(heading))
]*/ ]*/
// Any other figure kind (generally, user defined kinds)
show outline.entry: it => link( show outline.entry: it => link(
it.element.location(), it.element.location(),
it.indented( it.indented(
[*#__get-locatable-element-number(it.element) unknown.*], [*#__caption-label(it.element)*],
it.inner(), gap: 0pt [ #it.inner()], gap: 0pt
), ),
) )
o o
@@ -310,7 +256,7 @@
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)
} }
@@ -327,6 +273,10 @@
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.
/// This function creates an outline entry with a specified title and figure type. /// This function creates an outline entry with a specified title and figure type.
/// The outline entry will link to the figure of the specified type. /// The outline entry will link to the figure of the specified type.
@@ -336,16 +286,41 @@
__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) = { /// `code` option defaults for the library entrypoint.
show: codly-init.with() #let __CODE_DEFAULTS = (
codly( font: "Hack",
spacing: 80%,
fill: white, fill: white,
zebra-fill: none, stroke: 0.5pt + black,
stroke: none, numbers: true,
display-name: false, display-name: false,
display-icon: false, display-icon: false,
) )
show raw: set text(font: "Hack", spacing: 80%)
/// 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.where(block: true): codly.new
show: codly.set_(number-enabled: opts.numbers)
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 body
} }
@@ -359,8 +334,8 @@
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)
@@ -374,7 +349,7 @@
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(
@@ -399,11 +374,13 @@
body body
} }
#let setup-code(body, ..ignored) = 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)
@@ -440,10 +417,32 @@
// TODO: intervalas tarp eilučių – 1,15 kiekvienai antraštei // TODO: intervalas tarp eilučių – 1,15 kiekvienai antraštei
// Priedas: kiekvienas pradedamas naujame lape, dešiniajame viršutiniame
// kampe rašoma "N priedas", pavadinimas (jei yra) – kaip skyriaus pavadinimas
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ė be nr. // Antraštė be nr.
if it.numbering == none { if it.numbering == none {
// Centruota lygiuotė by default, but can be overridden by the user // Centruota lygiuotė by default, but can be overridden by the user
set align(unnumberedHeadingAlignment) 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 // atstumas prieš ir po antraštės - 10 pt
block[#maybe-uppercase(it.body)] block[#maybe-uppercase(it.body)]
@@ -452,7 +451,6 @@
} }
} }
// Skyrius // Skyrius
if it.numbering != none and it.level == 1 { if it.numbering != none and it.level == 1 {
// abipusė lygiuotė // abipusė lygiuotė
@@ -460,9 +458,7 @@
// Reset figure counters if numbering per section is enabled // Reset figure counters if numbering per section is enabled
if __FIG_PER_SECTION.get() { if __FIG_PER_SECTION.get() {
counter(figure.where(kind: image)).update(0) __reset-figure-counters()
counter(figure.where(kind: table)).update(0)
counter(figure.where(kind: raw)).update(0)
} }
// po antraštės - 10 pt // po antraštės - 10 pt
@@ -472,14 +468,8 @@
} }
} }
// 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 // Poskyris ir skyrelis
if not isAppendixHeading and it.numbering != none and it.level != 1 { if it.numbering != none and it.level != 1 {
// abipusė lygiuotė // abipusė lygiuotė
set par(justify: true) set par(justify: true)
@@ -503,6 +493,11 @@
// Bibliography citing style // Bibliography citing style
set bibliography(style: "assets/iso690-numeric-lt.csl") set bibliography(style: "assets/iso690-numeric-lt.csl")
// Block equations are left-aligned
show math.equation.where(block: true): it => {
align(left, it)
}
body body
} }
@@ -511,15 +506,36 @@
/// - 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.
/// - 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`.
/// - `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,
figureKinds: (:),
code: (:),
// Not sure about formal conformity of deviating // Not sure about formal conformity of deviating
// from the defaults of the next options, // from the defaults of the next options,
// but some modules may require them // but some modules may require them
uppercaseSectionTitles: false, uppercaseSectionTitles: false,
unnumberedHeadingAlignment: center, unnumberedHeadingAlignment: center,
body body,
) = context { ) = context {
show: setup-page.with( show: setup-page.with(
font: font, font: font,
@@ -527,6 +543,7 @@
unnumberedHeadingAlignment: unnumberedHeadingAlignment, unnumberedHeadingAlignment: unnumberedHeadingAlignment,
) )
__FIG_PER_SECTION.update(figureNumberingPerSection) __FIG_PER_SECTION.update(figureNumberingPerSection)
__USER_FIGURE_KINDS.update(__normalize-figure-kinds(figureKinds))
__UPPERCASE_SECTION_TITLES.update(uppercaseSectionTitles) __UPPERCASE_SECTION_TITLES.update(uppercaseSectionTitles)
body __setup-code(code, body)
} }
+159
View File
@@ -0,0 +1,159 @@
#import "@local/ktu-paper:0.5.0": (
ktu-paper,
ktu-table-of-contents, ktu-picture-list, ktu-table-list, ktu-code-list,
ktu-heading-page-normal,
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, optional, `code: none` disables styling
code: (
font: "Hack",
spacing: 80%,
fill: white,
stroke: 0.5pt + black,
numbers: true,
display-name: false,
display-icon: false,
),
)
#show math.equation: it => {
show regex("\d+\.\d+"): it => {show ".": {","+h(0pt)}
it}
it
}
#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)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

File renamed without changes.
+11 -12
View File
@@ -1,5 +1,5 @@
#import "@local/ktu-paper:0.3.0": ( #import "@local/ktu-paper:0.5.0": (
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)}
@@ -94,7 +93,7 @@ show table.cell: set text(size: 8pt)
Duomenų sklaidą yra patogu pavaizduoti ir stačiakampe diagrama: Duomenų sklaidą yra patogu pavaizduoti ir stačiakampe diagrama:
#figure( #figure(
image("image.jpeg", width: 70%), image("images/santaka.png", width: 70%),
caption: [ caption: [
Skaitinių atributų stačiakampė diagrama Skaitinių atributų stačiakampė diagrama
], ],
@@ -136,8 +135,8 @@ Paveikslėlius galima grupuoti į "grid" #custom-ref(<image-grid-2>, <image-grid
#figure(grid( #figure(grid(
columns: 2, columns: 2,
gutter: 2mm, gutter: 2mm,
image("image.jpeg", width: 100%), image("images/santaka.png", width: 100%),
image("image.jpeg", width: 100%), image("images/santaka.png", width: 100%),
), caption: [ ), caption: [
Paveikslėliai "grid'e" 1 Paveikslėliai "grid'e" 1
]) <image-grid-2> ]) <image-grid-2>
@@ -145,11 +144,11 @@ Paveikslėlius galima grupuoti į "grid" #custom-ref(<image-grid-2>, <image-grid
#figure(grid( #figure(grid(
columns: 3, columns: 3,
gutter: 2mm, gutter: 2mm,
image("image.jpeg", width: 100%), image("images/santaka.png", width: 100%),
image("image.jpeg", width: 100%), image("images/santaka.png", width: 100%),
image("image.jpeg", width: 100%), image("images/santaka.png", width: 100%),
image("image.jpeg", width: 100%), image("images/santaka.png", width: 100%),
image("image.jpeg", width: 100%), image("images/santaka.png", width: 100%),
), caption: [ ), caption: [
Paveikslėliai "grid'e" 2 Paveikslėliai "grid'e" 2
]) <image-grid-3> ]) <image-grid-3>
@@ -190,7 +189,7 @@ $
čia $X$ -- imtis, $mu$ -- imties vidurkis, $sigma$ -- imties standartinis nuokrypis. Fragmentas pateikiamas #ref-no(<image-1>) paveikslėlyje. čia $X$ -- imtis, $mu$ -- imties vidurkis, $sigma$ -- imties standartinis nuokrypis. Fragmentas pateikiamas #ref-no(<image-1>) paveikslėlyje.
#figure( #figure(
image("image.jpeg", width: 90%), image("images/santaka.png", width: 90%),
caption: [ caption: [
Paveikslėlio pavadinimas Paveikslėlio pavadinimas
], ],
+3 -4
View File
@@ -1,5 +1,5 @@
#import "@local/ktu-paper:0.3.0": ( #import "@local/ktu-paper:0.5.0": (
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)
@@ -191,7 +190,7 @@ Eu eum decore inimicus consetetur, cu usu habeo corpora intellegam. Ut antiopam
Lorem ipsum dolor sit amet, eam ex decore persequeris, sit at illud lobortis atomorum. Sed dolorem quaerendum ne, prompta instructior ne pri. Et mel partiendo suscipiantur, docendi abhorreant ea sit. Recteque imperdiet eum te. Lorem ipsum dolor sit amet, eam ex decore persequeris, sit at illud lobortis atomorum. Sed dolorem quaerendum ne, prompta instructior ne pri. Et mel partiendo suscipiantur, docendi abhorreant ea sit. Recteque imperdiet eum te.
#figure( #figure(
image("Picture.png", width: 11.2cm, height: 8cm), image("images/santaka.png", width: 11.2cm, height: 8cm),
caption: [ caption: [
Kauno technologijos universiteto „Santakos“ slėnio fasadas Kauno technologijos universiteto „Santakos“ slėnio fasadas
], ],
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "ktu-paper" name = "ktu-paper"
version = "0.3.0" version = "0.5.0"
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"