diff --git a/README.md b/README.md index 449893d..5036e6f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Typst Template for NURE Works +pz-lb title page ## General Info @@ -6,16 +7,18 @@ This project contains two template functions and some utilities for writing NURE ### Templates -#### `pz-lb-template` - For Laboratory and Practical Works +#### `pz-lb` - For Practice and Laboratory Works This template: - Sets up document styles; - Formats the title page according to NURE/DSTU guidelines. -#### `cw-template` - For Course Works +#### `coursework` - For Course Works This template: - Sets up document styles; - Formats the title, task, calendar plan, and abstract pages; -- Typesets the bibliography, outline, and appendices according to standard requirements. +- Typesets the bibliography according to ДСТУ 3008:2015 using custom CSL style; +- Typesets the outline and appendices according to standard requirements. + ### Utilities - `nheading` - For unnumbered headings, such as "Introduction" and "Conclusion". @@ -24,61 +27,138 @@ This template: - `bold` - Inserts bold text inside functional environments. - `img` - Inserts images with a caption, automatically deriving the label from the image file name. +**Note:** `img()` is provided in `utils.typ` in project's root directory for compatibility, until [path() type](https://github.com/typst/typst/pull/7555) is released. + ## Usage ### As a local typst package 1. Clone this repository into ~/.local/share/typst/packages/: ```bash -git clone -b 0.1.0 https://gitea.linerds.us/pencelheimer/typst_nure_template.git ~/.local/share/typst/packages/local/nure/0.1.0 +git clone -b 0.1.1 https://gitea.linerds.us/pencelheimer/typst_nure_template.git ~/.local/share/typst/packages/local/nure/0.1.1 ``` 2. Init your project with Typst: ```bash -typst init @local/nure:0.1.0 project-name +typst init @local/nure:0.1.1 project-name ``` ### As a standalone file -Copy `lib.typ` to your project's root directory. +Copy `src/` to your project's root directory, optionally renaming `src/` to `lib/`. ### In your project ```typst // Import the template either from a local package... #import "@local/nure:0.1.0": * // ...or by importing a lib.typ directly -// #import "/lib.typ": * +// #import "/lib/lib.typ": * -// Setup the document -#show: pz-lb-template.with( - title: "Some title", - // etc: "and so on", - // ... +// 1. Setup the document +// by setting values directly... +#show: pz-lb.with( + title: "Some title", + // etc: "and so on", + // ... ) +// ...or using a yaml/toml file +#show: pz-lb.with(..toml("/doc.toml")) + // this template automatically inserts a `=title` -// Write your content... +// Write your content #v(-spacing) // remove spacing between headings == Purpose Some text // ...or include your modules -#include "src/intro.typ" -#include "src/chapter1.typ" -#include "src/chapter2.typ" +#include "chapters/intro.typ" +#include "chapters/chapter1.typ" +#include "chapters/chapter2.typ" // NOTE: if you want to use variables or utils provided by the package, // you have to import the package or a lib.typ inside a module. + + +// If you ever need appendices in pz-lb template use the show rule +// WARNING: when using coursework template use its own argument, +// so it can put bibliography before appendices +#show: style.appendices + += Quote +#link("https://youtu.be/bJQj1uKtnus")[ + The art isn't the art, the art is never the art, + the art is the thing that happens inside you when you make it and the feeling in the heart of the beholder. +] +``` + +And a TOML file would look like this: +```toml +# university = "ХНУРЕ" # "ХНУРЕ" is the default +# edu-program = "ПЗПІ" # can be null, sourced from authors.first() by default + +subject = "СМП" +doctype = "ЛБ" +worknumber = 2 +title = "Потiк керування та алгоритмічні структури Bash" + +[[mentors]] +name = "Шевченко Т. Г." +degree = "Доцент кафедри ПІ" +gender = "m" + +[[mentors]] +name = "Франко І. Я." +degree = "Асистент кафедри ПІ" +gender = "m" + +[[authors]] +name = "Косач Л. П." +edu-program = "ПЗПІ" +group = "23-2" +gender = "f" +variant = 8 +# For coursework +full-name-gen = "Косач Лариси Петрівни" +course = 2 +semester = 4 ``` ### Notes: 1. Use `#v(-spacing)` to remove vertical spacing between titles (this cannot be automatically handled by the template). Variable `spacing` used here is imported from the template. +2. When importing `@local/nure:0.1.1` and specifying file paths in functions handled by the package, the path will relative to package's root directory, e.g. setting `#show: coursework.with(bib-path: "bibl.yml")` will evaluate to `~/.local/share/typst/packages/local/nure/0.1.1/bibl.yml`, the same is for `#img` function, which makes it quite annoying and forces one to import `lib.typ` file. Please open an issue or contact us in any other way if you have any advice. + +### Bibliography Format +The template uses a custom CSL (Citation Style Language) file located at `src/csl/dstu-3008-2015.csl` to format bibliography entries. + +Supported bibliography entry types in `bibl.yml`: +- **Book**: Books with author, title, publisher, year, and page count +- **Web**: Web resources with title, author/organization, URL, and access date + +**Warning:** Other types were added by Kimi K2.5 without any additional checks for compliance. + +Example `bibl.yml`: +```yaml +mysql: + type: Book + title: MySQL Language Reference + author: Ab M. + publisher: MySQL Press + date: 2004 + page-total: 600 + +go: + type: Web + title: The Go Programming Language + author: The Go Programming Language + url: + value: https://go.dev/ + date: 2024-12-10 +``` ### Example Project Structure ``` project/ +├── doc.toml -- for things that don't change across works, i.e. author and mentor metadata ├── main.typ -- for boilerplate code and importing everything -├── config/ -│ ├── doc.yaml -- for things that don't change across works, i.e. author and mentor metadata -│ ├── universities.yaml -- for user-specific configuration, i.e. education programs and disciplines -│ └── ... -├── src/ +├── utils.typ -- for helper functions +├── chapters/ │ ├── intro.typ │ ├── chapter1.typ │ ├── chapter2.typ diff --git a/assets/pz-lb_title_page.png b/assets/pz-lb_title_page.png new file mode 100644 index 0000000..f727d4b Binary files /dev/null and b/assets/pz-lb_title_page.png differ diff --git a/config/universities.yaml b/config/universities.yaml deleted file mode 100644 index e21c999..0000000 --- a/config/universities.yaml +++ /dev/null @@ -1,24 +0,0 @@ -ХНУРЕ: - name: "Харківський національний університет радіоелектроніки" - edu_programs: - ПЗПІ: - name_long: "Інженерія програмного забезпечення" - department_gen: "Програмної інженерії" - code: 121 # TODO = ПЗПІ is "F2" now - КУІБ: - name_long: "Управління інформаційною безпекою" - department_gen: "Інфокомунікацій" - code: 125 - subjects: - БД: "Бази даних" - БЖД: "Безпека життєдіяльності" - ОІМ: "Основи IP-мереж" - "ОПНJ": "Основи програмування на Java" - ОС: "Операційні системи" - ОТК: "Основи теорії кіл" - ПП: "Проектний практикум" - ПРОГ: "Програмування" - СПМ: "Скриптові мови програмування" - УФМ: "Українське фахове мовлення" - Ф: "Філософія" - ФІЗ: "Фізика" diff --git a/lib.typ b/lib.typ deleted file mode 100644 index b51c4ac..0000000 --- a/lib.typ +++ /dev/null @@ -1,746 +0,0 @@ - -// Academic aliases {{{1 - -#let universities = yaml("config/universities.yaml") - -// Template formatting functions {{{1 - -/// numberless heading -#let nheading(title) = heading(depth: 1, numbering: none, title) - -/// fill horizontal space with a box and not an empty space -#let hfill(width) = box( - width: width, - repeat(" "), -) // NOTE: This is a HAIR SPACE (U+200A), not a regular space - -/// make underlined cell with filled value -#let uline(align: center, content) = underline[ - #if align != left { hfill(1fr) } - #content - #if align != right { hfill(1fr) } -] - -/// bold text -#let bold(content) = text(weight: "bold")[#content] - -/// month name from its number -#let month_gen(month) = ( - "січня", - "лютого", - "березня", - "квітня", - "травня", - "червня", - "липня", - "серпня", - "вересня", - "жовтня", - "листопада", - "грудня", -).at(month - 1) - -// Helper functions {{{1 - -/// captioned image with label derived from path: -/// - "image.png" = @image -/// - "img/image.png" = @image -/// - "img/foo/image.png" = @foo_image -/// - "img/foo/foo_image.png" = @foo_image -/// the caption will be modified based on a conditional positional value: -/// - `none`: no change -/// - some value: "`caption` (за даними `value`)" -/// - no value: "`caption` (рисунок виконано самостійно)" -/// additional named arguments will be passed to original `image` function -#let img(path, caption, ..sink) = { - let parts = path.split(".").first().split("/") - - let label_string = if ( - parts.len() <= 2 or parts.at(-1).starts-with(parts.at(-2)) - ) { - // ("image",), (_, "image") and (.., "img", "img_image") - parts.last() - } else { - // (.., "img", "image") = "img_image" - parts.at(-2) + "_" + parts.at(-1) - }.replace(" ", "_") - - let caption = if sink.pos().len() == 0 { - caption + " (рисунок виконано самостійно)" - } else if sink.pos().first() == none { - caption - } else { - [#caption (за даними #sink.pos().first())] - } - - [#figure( - image(path, ..sink.named()), - caption: caption, - ) #label(label_string)] -} - -// Styling {{{1 -/// NOTE: may be wrong -#let ua_alpha_numbering = "абвгдежиклмнпрстуфхцшщюя".split("") // 0 = "", 1 = "а" - -// general outlook {{{2 -// spacing between lines -#let spacing = 0.95em - -#let style(it) = { - set page( - paper: "a4", - margin: (top: 20mm, right: 10mm, bottom: 20mm, left: 25mm), - number-align: top + right, - numbering: (..numbers) => { - if numbers.pos().at(0) != 1 { - numbering("1", numbers.pos().at(0)) - } - }, - ) - - set text( - font: ("Times New Roman", "Liberation Serif"), - size: 14pt, - hyphenate: false, - lang: "uk", - ) - set par(justify: true, first-line-indent: (amount: 1.25cm, all: true)) - set underline(evade: false) - - // set 1.5 line spacing - set block(spacing: spacing) - set par(spacing: spacing) - set par(leading: spacing) - - // enums and lists {{{2 - set enum( - numbering: i => { ua_alpha_numbering.at(i) + ")" }, - indent: 1.25cm, - body-indent: 0.5cm, - ) - show enum: it => { - set enum(indent: 0em, numbering: "1)") - it - } - - set list(indent: 1.35cm, body-indent: 0.5cm, marker: [--]) - - // figures {{{2 - show figure: it => { - v(spacing * 2, weak: true) - it - v(spacing * 2, weak: true) - } - - set figure.caption(separator: [ -- ]) - show figure.where(kind: table): set figure.caption(position: top) - show figure.caption.where(kind: table): set align(left) - - // figure numbering - show heading.where(level: 1): it => { - counter(math.equation).update(0) - counter(figure.where(kind: image)).update(0) - counter(figure.where(kind: table)).update(0) - counter(figure.where(kind: raw)).update(0) - it - } - set math.equation( - numbering: (..num) => numbering( - "(1.1)", - counter(heading).get().at(0), - num.pos().first(), - ), - ) - set figure( - numbering: (..num) => numbering( - "1.1", - counter(heading).get().at(0), - num.pos().first(), - ), - ) - - // appearance of references to images and tables {{{2 - set ref( - supplement: it => { - if it == none or not it.has("kind") { - it - } else if it.kind == image { - "див. рис." - } else if it.kind == table { - "див. таблицю" - } else { - it - } - }, - ) - show ref: it => { - let el = it.element - - if el == none or not el.has("kind") { - return it - } - if el.kind != image and el.kind != table { - return it - } - - [(#it)] - } - - // headings {{{2 - set heading(numbering: "1.1") - - show heading.where(level: 1): it => { - set align(center) - set text(size: 14pt, weight: "semibold") - - pagebreak(weak: true) - upper(it) - v(spacing * 2, weak: true) - } - show heading.where(level: 2): it => { - set text(size: 14pt, weight: "regular") - - v(spacing * 2, weak: true) - block(width: 100%, spacing: 0em)[ - #h(1.25cm) - #counter(heading).display(it.numbering) - #it.body - ] - v(spacing * 2, weak: true) - } - - show heading.where(level: 3): it => { - set text(size: 14pt, weight: "regular") - - v(spacing * 2, weak: true) - block(width: 100%, spacing: 0em)[ - #h(1.25cm) - #counter(heading).display(it.numbering) - #it.body - ] - v(spacing * 2, weak: true) - } - - // listings {{{2 - show raw: it => { - let new_spacing = 0.5em - set block(spacing: new_spacing) - set par( - spacing: new_spacing, - leading: new_spacing, - ) - set text( - size: 11pt, - font: ("Iosevka NFM", "Courier New"), - weight: "semibold", - ) - - v(spacing * 2.5, weak: true) - pad(it, left: 1.25cm) - v(spacing * 2.5, weak: true) - } - - it -} - -// Coursework template {{{1 - -/// DSTU 3008:2015 Template for NURE -/// -> content -/// - doc (content): Content to apply the template to. -/// - title (str): Title of the document. -/// - subject (str): Subject short name. -/// - authors ((name: str, full_name_gen: str, variant: int, course: int, semester: int, group: str, gender: str),): List of authors. -/// - mentors ((name: str, degree: str),): List of mentors. -/// - edu_program (str): Education program shorthand. -/// - task_list (done_date: datetime, initial_date: datetime, source: (content | str), content: (content | str), graphics: (content | str)): Task list object. -/// - calendar_plan ( plan_table: (content | str), approval_date: datetime): Calendar plan object. -/// - abstract (keywords: (str, ), text: (content | str)): Abstract object. -/// - bib_path path: Path to the bibliography yaml file. -/// - appendices (content): Content with appendices. -#let cw-template( - doc, - title: none, - subject: none, - university: "ХНУРЕ", - author: (), - mentors: (), - edu_program: none, - task_list: (), - calendar_plan: (), - abstract: (), - bib_path: none, - appendices: (), -) = { - set document(title: title, author: author.name) - - show: style - - let bib-count = state("citation-counter", ()) - show cite: it => { - it - bib-count.update(((..c)) => (..c, it.key)) - } - show bibliography: it => { - set text(size: 0pt) - it - } - - - let head_mentor = mentors.at(0) - let uni = universities.at(university) - let edu_prog = uni.edu_programs.at(edu_program) - - // page 1 {{{2 - [ - #set align(center) - МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ\ - #upper(uni.name) - - \ - - Кафедра #edu_prog.department_gen - - \ - - ПОЯСНЮВАЛЬНА ЗАПИСКА\ - ДО КУРСОВОЇ РОБОТИ\ - з дисципліни: "#uni.subjects.at(subject, default: "NONE")"\ - Тема роботи: "#title" - - \ \ \ - - #columns(2, gutter: 4cm)[ - #set align(left) - - #if author.gender == "m" { [Виконав\ ] } else { [Виконала\ ] } ст. гр. #edu_program\-#author.group - - \ - Керівник:\ - #head_mentor.degree - - \ - Робота захищена на оцінку - - \ - Комісія:\ - #for mentor in mentors { - [#mentor.degree\ - ] - } - - #colbreak() - #set align(left) - - \ - #author.name - - \ \ - #head_mentor.name - - \ - #underline(" " * 35) - - \ \ - #for mentor in mentors { - [#mentor.name\ - ] - } - ] - - #v(1fr) - - Харків -- #task_list.done_date.display("[year]") - - #pagebreak() - ] - - // page 2 {{{2 - { - uline[#uni.name] - - linebreak() - linebreak() - - grid( - columns: (100pt, 1fr), - bold[ - Кафедра - Дисципліна - Спеціальність - ], - { - uline(align: left, edu_prog.department_gen) - linebreak() - uline(align: left, uni.subjects.at(subject)) - linebreak() - uline(align: left, [#edu_prog.code #edu_prog.name_long]) - }, - ) - grid( - columns: (1fr, 1fr, 1fr), - gutter: 0.3fr, - [#bold[Курс] #uline(author.course)], - [#bold[Група] #uline([#edu_program\-#author.group])], - [#bold[Семестр] #uline(author.semester)], - ) - - linebreak() - linebreak() - linebreak() - - align(center, bold[ЗАВДАННЯ \ на курсову роботу студента]) - - linebreak() - - uline(align: left)[_#author.full_name_gen _] - - linebreak() - linebreak() - - bold[\1. Тема роботи:] - uline[#title.] - - linebreak() - - { - bold[\2. Строк здачі закінченої роботи:] - uline(task_list.done_date.display("[day].[month].[year]")) - hfill(10fr) - } - - linebreak() - - bold[\3. Вихідні дані для роботи:] - uline(task_list.source) - - linebreak() - - bold[\4. Зміст розрахунково-пояснювальної записки:] - uline(task_list.content) - - linebreak() - - bold[\5. Перелік графічного матеріалу:] - uline(task_list.graphics) - - linebreak() - - { - bold[\6. Дата видачі завдання:] - uline(task_list.initial_date.display("[day].[month].[year]")) - hfill(10fr) - } - - pagebreak() - } - - // page 3 {{{2 - { - align(center, bold[КАЛЕНДАРНИЙ ПЛАН]) - set par(first-line-indent: 0pt) - - linebreak() - - calendar_plan.plan_table - - linebreak() - - grid( - columns: (5fr, 5fr), - grid( - columns: (1fr, 2fr, 1fr), - gutter: 0.2fr, - [ - Студент \ - Керівник \ - #align(center)["#underline[#calendar_plan.approval_date.day()]"] - ], - [ - #uline(align: center, []) \ - #uline(align: center, []) \ - #uline(align: center, month_gen(calendar_plan.approval_date.month())) - ], - [ - \ \ - #underline[#calendar_plan.approval_date.year()] р. - ], - ), - [ - #author.name, \ - #head_mentor.degree - #head_mentor.name. - ], - ) - - pagebreak() - } - - // page 4 {{{2 - [ - #align(center, bold[РЕФЕРАТ]) \ - - #context [ - #let pages = counter(page).final().at(0) - #let images = query(figure.where(kind: image)).len() - #let tables = query(figure.where(kind: table)).len() - #let bibs = bib-count.final().dedup().len() - /* TODO: why this stopped working? - #let tables = counter(figure.where(kind: table)).final().at(0) - #let images = counter(figure.where(kind: image)).final().at(0)*/ - - #let counters = () - - #if pages != 0 { counters.push[#pages с.] } - #if tables != 0 { counters.push[#tables табл.] } - #if images != 0 { counters.push[#images рис.] } - #if bibs != 0 { counters.push[#bibs джерел] } - - Пояснювальна записка до курсової роботи: #counters.join(", "). - ] - - \ - - #{ - let keywords = abstract.keywords.map(upper) - let is_cyrillic = word => word.split("").any(char => ("А" <= char and char <= "я")) - - let n = keywords.len() - for i in range(n) { - for j in range(0, n - i - 1) { - if ( - ( - not is_cyrillic(keywords.at(j)) and is_cyrillic(keywords.at(j + 1)) - ) - or ( - is_cyrillic(keywords.at(j)) == is_cyrillic(keywords.at(j + 1)) and keywords.at(j) > keywords.at(j + 1) - ) - ) { - (keywords.at(j), keywords.at(j + 1)) = ( - keywords.at(j + 1), - keywords.at(j), - ) - } - } - } - - keywords.join(", ") - } - - \ - - #abstract.text - ] - - // page 5 {{{2 - outline( - title: [ - ЗМІСТ - #v(spacing * 2, weak: true) - ], - depth: 2, - indent: auto, - ) - - doc - - // bibliography {{{2 - { - heading(depth: 1, numbering: none)[Перелік джерел посилання] - - bibliography( - bib_path, - style: "ieee", - full: true, - title: none, - ) - - let bib_data = yaml(bib_path) - - let format-entry(citation) = { - if (citation.type == "Web") { - let date_array = citation.url.date.split("-") - let date = datetime( - year: int(date_array.at(0)), - month: int(date_array.at(1)), - day: int(date_array.at(2)), - ) - [ - #citation.title. - #citation.author. - URL: #citation.url.value (дата звернення: #date.display("[day].[month].[year]")). - ] - } else if citation.type == "Book" [ - #citation.author - #citation.title. - #citation.publisher, - #citation.date. - #citation.page-total c. - ] else [ - UNSUPPORTED BIBLIOGRAPHY ENTRY TYPE, PLEASE OPEN AN ISSUE - ] - } - - show enum.item: it => { - set par(first-line-indent: 0pt) - box(width: 1.25cm) - box(width: 1em + 0.5cm)[#it.number.] - it.body - linebreak() - } - - context { - for (i, citation) in query(ref.where(element: none)).map(r => str(r.target)).dedup().enumerate() { - enum.item( - i + 1, - format-entry(bib_data.at(citation)), - ) - } - } - } - - // appendices {{{2 - { - counter(heading).update(0) - - set heading( - numbering: (i, ..nums) => { - let char = upper(ua_alpha_numbering.at(i)) - if nums.pos().len() == 0 { char } else { - char + "." + nums.pos().map(str).join(".") - } - }, - ) - - show heading.where(level: 1): it => { - set align(center) - set text(size: 14pt, weight: "regular") - - pagebreak(weak: true) - bold[ДОДАТОК #counter(heading).display(it.numbering)] - linebreak() - it.body - v(spacing * 2, weak: true) - } - - show heading.where(level: 2): it => { - set text(size: 14pt, weight: "regular") - - v(spacing * 2, weak: true) - block(width: 100%, spacing: 0em)[ - #h(1.25cm) - #counter(heading).display(it.numbering) - #it.body - ] - v(spacing * 2, weak: true) - } - - appendices - } -} - -// Laboratory work template {{{1 - -/// DSTU 3008:2015 Template for NURE -/// -> content -/// - doc (content): Content to apply the template to. -/// - doctype ("ЛБ" | "ПЗ"): Document type. -/// - edu_program (str): Education program shorthand. -/// - title (str): Title of the document. -/// - subject (str): Subject shorthand. -/// - authors ((name: str, full_name_gen: str, group: str, gender: str, variant: int or none),): List of authors. -/// - mentors ((name: str, degree: str, gender: str or none),): List of mentors. -/// - worknumber (int or none): Number of the work. Optional. -#let pz-lb-template( - doc, - doctype: none, - university: "ХНУРЕ", - edu_program: none, - title: none, - subject: none, - worknumber: none, - authors: (), - mentors: (), -) = { - set document(title: title, author: authors.at(0).name) - - show: style - - let uni = universities.at(university) - let edu_prog = uni.edu_programs.at(edu_program) - // page 1 {{{2 - align(center)[ - МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ \ - #upper(uni.name) - - \ \ - Кафедра #edu_prog.department_gen - - \ \ \ - Звіт \ - з - #if doctype == "ЛБ" [лабораторної роботи] else [практичної роботи] - #if worknumber != none { - context counter(heading).update(worknumber - 1) - [№#worknumber] - } - - з дисципліни: "#uni.subjects.at(subject, default: "UNKNOWN SUBJECT, PLEASE OPEN AN ISSUE")" - - з теми: "#title" - - \ \ \ \ - - #columns(2)[ - #set align(left) - #set par(first-line-indent: 0pt) - #if authors.len() == 1 { - let author = authors.at(0) - if author.gender == "m" [Виконав:\ ] else [Виконала:\ ] - [ - ст. гр. #edu_program\-#author.group\ - #author.name\ - ] - if author.variant != none [Варіант: №#author.variant] - } else [ - Виконали:\ - ст. гр. #edu_program\-#authors.at(0).group\ - #for author in authors [#author.name\ ] - ] - - #colbreak() - #set align(right) - - #if mentors.len() == 1 { - let mentor = mentors.at(0) - if mentor.gender == none [Перевірили:\ ] else if ( - mentor.gender == "m" - ) [Перевірив:\ ] else [Перевірилa:\ ] - [ - #mentor.degree\ - #mentor.name\ - ] - } else [ - Перевірили:\ - #for mentor in mentors { - [ - #mentor.degree\ - #mentor.name\ - ] - } - ] - ] - - #v(1fr) - - Харків -- #datetime.today().display("[year]") - ] - - pagebreak(weak: true) - - heading(title) - doc -} - -// vim:sts=2:sw=2:fdl=0:fdm=marker:cms=/*%s*/ diff --git a/src/config/universities.yaml b/src/config/universities.yaml new file mode 100644 index 0000000..8855a07 --- /dev/null +++ b/src/config/universities.yaml @@ -0,0 +1,78 @@ +ХНУРЕ: + name: Харківський національний університет радіоелектроніки + name-en: Kharkiv National University of Radioelectronics + edu-programs: + ПЗПІ: + name-long: Інженерія програмного забезпечення + department-gen: Програмної інженерії + code: 121 # TODO: change to F2? + КУІБ: + name-long: Управління інформаційною безпекою + department-gen: Інфокомунікаційної інженерії ім. В. В. Поповського + code: 125 # TODO: change to F5? + description: Кібербезпека та захист інформації + КНТ: + name-en: CST # computer sciences and technologies + name-long: Комп'ютерні науки та технології + department-gen: Системотехніки + department-en: ST + code: 122 + subjects: + DMT: Decision making theory + ODS: Основи Dаtа Sсіеnсе # NOTE: Eng O here + ІМ: Іноземна мова + ІТР: Information Technologies of Reengineering + ІТРОІ: Інтернет-технології Розподіленої Обробки Інформації + АВпЗ: Аналіз вимог до програмного забезпечення + АДан: Аналітика даних + АКтаК: Архітектура комп'ютера та комп'ютерних мереж + АТСД: Алгоритми та структури даних + АтаРК: Аналіз та рефакторинг коду + БД: Бази даних + БЖД: Безпека життєдіяльності + ВДІТБ: Введення до ІТ-бізнесу # NOTE: all in UA + ВМ: Вища математика + ГТГ: Гіпертекст та гіпермедіа + ДМ: Дискретна математика + ДПК: Динаміка Проектних Команд + ЕРВ: Електрорадіовимірювання + КДМА: Комп'ютерна дискретна математика + КЗВШ: Креативність з використанням штучного інтелекту + КМ: Комп`ютерні мережі + ЛМВ: Людино-машинна взаємодія + ЛМтБ: Локальні мережі та їх безпека # бидло не знає що українською "їхня" + МОКр: Математичні основи криптології + МОТДО: Методи оптимізаціі та дослідження операцій + МППС: Methodologies of designing software systems + МС: Моделювання систем + ОІМ: Основи IP-мереж + ООАПС: Об'єктно-орієнтований аналіз в проектуванні систем + ООП: Об'єктно-орієнтоване програмування + ОП: Основи права + ОПІ: Основи програмноі інженеріі + ОПНJ: Основи програмування на Java + ОПр: Основи програмування + ОРвІТ: Оцінка Ризиків в IT-проектах + ОС: Операційні системи + ОТК: Основи теорії кіл + ПБІП: Проектування та балансування ігрового процесу + ПВJ: Поглиблене вивчення Java + ПЕСЕ: Психологія екстремальних стосунків та ефективної адаптації + ПНП: Програмування на платформі .NЕТ + ПП: Проектний практикум + ПРОГ: Програмування + ПарП: Параллельне програмування + СА: Системний аналіз + СМП: Скриптові мови програмування + СОАПЗ: Сервіс-Орієнтована Архітектура Програмного Забезпечення + СРБД: Серверні рішення баз даних + СхТ: Схемотехніка + ТВО: Технології Високопродуктивних Обчислень + ТЗІ: Технології захисту інформації + ТЙтаМ: Теорія ймовірностей та математична # TODO: what? + ТКП: Технології комп`ютерного проєктування + УФМ: Українське фахове мовлення + ФІЗ: Фізика + ФІЛ: Філософія + ФВС: Фізичне виховання та спорт + ХТ: Хмарні технології diff --git a/src/csl/dstu-3008-2015.csl b/src/csl/dstu-3008-2015.csl new file mode 100644 index 0000000..e5afc48 --- /dev/null +++ b/src/csl/dstu-3008-2015.csl @@ -0,0 +1,357 @@ + + diff --git a/src/helpers.typ b/src/helpers.typ new file mode 100644 index 0000000..99ebdeb --- /dev/null +++ b/src/helpers.typ @@ -0,0 +1,52 @@ +/// month name from its number +#let month-gen(month) = ( + "січня", + "лютого", + "березня", + "квітня", + "травня", + "червня", + "липня", + "серпня", + "вересня", + "жовтня", + "листопада", + "грудня", +).at(month - 1) + +#let is-cyr(c) = regex("[\p{Cyrillic}]") in c + +/// type-safe emptiness check +#let is-empty(val) = { + if val == none { return true } + if type(val) == str { val.len() == 0 } else if type(val) == array { val == [] } else { false } +} + +#let degree-get(m) = if "degree" in m and not is-empty(m.degree) { [#m.degree\ ] } + +/// returns verb form based on gender ("m", "f", or "p" for plural) +#let gender-verb(verb, gender: "p") = { + ( + "author": ("m": "Виконав", "f": "Виконала", "p": "Виконали"), + "mentor": ("m": "Перевірив", "f": "Перевірила", "p": "Перевірили"), + ) + .at(verb) + .at(if gender == "m" or gender == "f" { gender } else { "p" }) +} + +/// returns verb form for dictionary containing gender field +#let gender-form(verb, dict: none) = { + let g = if type(dict) == dictionary and "gender" in dict { dict.gender } else { "p" } + gender-verb(verb, gender: g) +} + +#let pz-lb-title(type, number: none) = { + let type-title = ( + "ЛБ": [Звіт \ з лабораторної роботи], + "ПЗ": [Звіт \ з практичної роботи], + "КР": [Контрольна робота], + "РФ": [Реферат], + "ІДЗ": [Індивідуальне домашнє завдання], + ).at(type, default: type) + if not is-empty(number) { [#type-title №#number] } else { [#type-title] } +} diff --git a/src/lib.typ b/src/lib.typ new file mode 100644 index 0000000..3ab603c --- /dev/null +++ b/src/lib.typ @@ -0,0 +1,114 @@ +#import "./title-pages/main.typ" as tp +#import "./shared.typ": universities +#import "./helpers.typ": * + +#import "./style.typ" +#import "./utils.typ" + +/// Coursework template for NURE +/// - university (str): University code, default "ХНУРЕ" +/// - subject (str): Subject short name +/// - title (str): Work title +/// - authors (array): List of author dictionaries +/// - mentors (array): List of mentor dictionaries +/// - task-list (dict): Task metadata +/// - calendar-plan (dict): Calendar plan table and approval date +/// - abstract (dict): Keywords and abstract text +/// - bib-path (str): Path to bibliography file +/// - appendices (content): Appendix content +#let coursework( + doc, + university: "ХНУРЕ", + subject: none, + title: none, + authors: (), + mentors: (), + task-list: (), + calendar-plan: (), + abstract: (), + bib-path: none, + appendices: (), +) = { + set document(title: title, author: authors.map(c => c.name)) + + show: style.dstu.with(skip: 1) + + tp.cw.nure( + university, + subject, + title, + authors, + mentors, + task-list, + calendar-plan, + abstract, + ) + + doc + + // Bibliography with DSTU formatting + { + show regex("^\\d+\\."): it => [#it#h(0.5cm)] + show block: it => [#it.body#parbreak()] + bibliography(bib-path, title: [Перелік джерел посилання], style: "csl/dstu-3008-2015.csl", full: true) + } + + style.appendices(appendices) +} + +/// Practice and Laboratory works template +/// - layout (str): "default", "minimal", or "complex" +/// - university (str): University code +/// - edu-program (str): Education program code +/// - subject (str): Subject code +/// - type (str): Work type (ЛБ, ПЗ, КР, РФ, ІДЗ) +/// - number (int): Work number +/// - title (str): Work title +/// - authors (array): List of authors +/// - mentors (array): List of mentors +#let pz-lb( + doc, + layout: "default", + university: "ХНУРЕ", + edu-program: none, + subject: none, + type: none, + number: none, + title: none, + authors: (), + mentors: (), +) = { + assert(authors.len() > 0, message: "At least one author required") + + let edu-program = if edu-program != none { edu-program } else { authors.first().edu-program } + let uni = universities.at(university) + + set document(title: title, author: authors.map(c => c.name)) + + show: style.dstu.with(skip: 1) + + // Select layout variant + let layouts = ( + "complex": tp.pz-lb.complex(uni, edu-program, subject, type, number, title, authors, mentors), + "ХНУРЕ": tp.pz-lb.nure(uni, edu-program, subject, type, number, title, authors, mentors), + "default": tp.pz-lb.nure(uni, edu-program, subject, type, number, title, authors, mentors), + ) + + layouts.at(university, default: layouts.default) + + pagebreak(weak: true) + + // Set heading counter based on title/number + if title == none { + if number == none { context counter(heading).update(1) } else { + context counter(heading).update(number) + } + } else { + if number != none { + context counter(heading).update(number - 1) + } + heading(eval(title, mode: "markup")) + } + + doc +} diff --git a/src/shared.typ b/src/shared.typ new file mode 100644 index 0000000..6dd351c --- /dev/null +++ b/src/shared.typ @@ -0,0 +1 @@ +#let universities = yaml("config/universities.yaml") diff --git a/src/style.typ b/src/style.typ new file mode 100644 index 0000000..046862b --- /dev/null +++ b/src/style.typ @@ -0,0 +1,132 @@ +#import "utils.typ": bold +/// Constants for consistent styling +#let spacing = 0.95em +#let indent-size = 1.25cm +#let double-spacing = spacing * 2 +#let double-half-spacing = spacing * 2.5 + +/// Ukrainian alphabet for DSTU 3008:2015 numbering +#let ukr-enum = "абвгдежиклмнпрстуфхцшщюя".split("") + +/// Helper for level 2/3 heading blocks +#let heading-block(it, num: auto) = { + v(double-spacing, weak: true) + block(width: 100%, spacing: 0em)[ + #h(indent-size) + #counter(heading).display(num) + #it.body + ] + v(double-spacing, weak: true) +} + +/// DSTU 3008:2015 Style +#let dstu( + it, + skip: 0, + offset: 0, +) = { + // Page setup + set page( + paper: "a4", + number-align: top + right, + margin: (top: 20mm, right: 10mm, bottom: 20mm, left: 25mm), + numbering: (i, ..) => if i > skip { numbering("1", i + offset) }, + ) + + // Text and paragraph + set text(lang: "uk", size: 14pt, hyphenate: false, font: ("Times New Roman", "Liberation Serif")) + set par(justify: true, spacing: spacing, leading: spacing, first-line-indent: (amount: indent-size, all: true)) + set block(spacing: spacing) + set underline(evade: false) + + // Lists + set enum(indent: indent-size, body-indent: 0.5cm, numbering: i => ukr-enum.at(i) + ")") + show enum: it => { + set enum(indent: 0em, numbering: "1)") + it + } + set list(indent: indent-size + 0.1cm, body-indent: 0.5cm, marker: [--]) + + // Figures + show figure: it => { + v(double-spacing, weak: true) + it + v(double-spacing, weak: true) + } + set figure.caption(separator: [ -- ]) + show figure.where(kind: table): set figure.caption(position: top) + show figure.caption.where(kind: table): set align(left) + show figure.where(kind: raw): set figure.caption(position: top) + show figure.where(kind: raw): set align(left) + + // Numbering reset on level 1 headings + show heading.where(level: 1): it => { + counter(math.equation).update(0) + counter(figure.where(kind: raw)).update(0) + counter(figure.where(kind: image)).update(0) + counter(figure.where(kind: table)).update(0) + it + } + set figure(numbering: i => context numbering("1.1", counter(heading).get().at(0), i)) + set math.equation(numbering: i => context numbering("(1.1)", counter(heading).get().at(0), i)) + + // Headings + set heading(numbering: "1.1") + show heading: it => { + set text(size: 14pt) + if it.level == 1 { + set align(center) + set text(weight: "semibold") + pagebreak(weak: true) + upper(it) + v(double-spacing, weak: true) + } else { + set text(weight: "regular") + heading-block(it, num: if it.level == 3 { it.numbering } else { auto }) + } + } + + // Code listings + show raw.where(block: true): it => { + let code-spacing = 0.5em + set block(spacing: code-spacing) + set par(spacing: code-spacing, leading: code-spacing) + set text(size: 11pt, weight: "semibold", font: ("Courier New", "Liberation Mono")) + v(double-half-spacing, weak: true) + pad(it, left: indent-size) + v(double-half-spacing, weak: true) + } + + it +} + +/// DSTU 3008:2015 Appendices Style +#let appendices(it) = { + counter(heading).update(0) + + context { + let app-letter = upper(ukr-enum.at(counter(heading).get().at(0))) + set heading(numbering: (i, ..n) => upper(ukr-enum.at(i)) + numbering(".1.1", ..n)) + set figure(numbering: i => app-letter + "." + str(i)) + set math.equation(numbering: i => app-letter + "." + str(i)) + set heading(supplement: [Додаток]) + + show heading: h => { + set text(size: 14pt) + if h.level == 1 { + set align(center) + set text(weight: "regular") + pagebreak(weak: true) + bold([ДОДАТОК #counter(heading).display(auto)]) + linebreak() + h.body + v(double-spacing, weak: true) + } else { + set text(weight: "regular") + heading-block(h) + } + } + + it + } +} diff --git a/src/title-pages/coursework/main.typ b/src/title-pages/coursework/main.typ new file mode 100644 index 0000000..52e579b --- /dev/null +++ b/src/title-pages/coursework/main.typ @@ -0,0 +1 @@ +#import "nure.typ": * diff --git a/src/title-pages/coursework/nure.typ b/src/title-pages/coursework/nure.typ new file mode 100644 index 0000000..ebce727 --- /dev/null +++ b/src/title-pages/coursework/nure.typ @@ -0,0 +1,254 @@ +#import "../../shared.typ": universities +#import "../../helpers.typ": * +#import "../../style.typ": * +#import "../../utils.typ": bold, hfill, uline + +#let nure( + university, + subject, + title, + authors, + mentors, + task-list, + calendar-plan, + abstract, +) = { + let bib-count = state("citation-counter", ()) + show cite: it => { + it + bib-count.update(((..c)) => (..c, it.key)) + } + + let author = authors.first() + let head-mentor = mentors.first() + + let uni = universities.at(university) + let edu-prog = uni.edu-programs.at(author.edu-program) + + // page 1 {{{2 + [ + #set align(center) + МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ\ + #upper(uni.name) + + \ + + Кафедра #edu-prog.department-gen + + \ + + ПОЯСНЮВАЛЬНА ЗАПИСКА\ + ДО КУРСОВОЇ РОБОТИ\ + з дисципліни: "#uni.subjects.at(subject, default: subject)"\ + Тема роботи: "#title" + + \ \ \ + + #columns(2, gutter: 4cm)[ + #set align(left) + #set par(first-line-indent: 0pt) + + #gender-form("author", dict: author) ст. гр. #author.edu-program\-#author.group + + \ + Керівник:\ #head-mentor.degree + + \ + Робота захищена на оцінку + + \ + Комісія:\ #for m in mentors { degree-get(m) } + + #colbreak() + #set align(left) + + + #author.name + + \ \ + #head-mentor.name + + \ + #underline(" " * 35) + + \ \ + #for m in mentors [#m.name\ ] + ] + + #v(1fr) + + Харків -- #task-list.done-date.display("[year]") + + #pagebreak() + ] + + // page 2 {{{2 + { + uline[#uni.name] + + linebreak() + linebreak() + + grid( + columns: (100pt, 1fr), + bold[ + Кафедра + Дисципліна + Спеціальність + ], + { + uline(align: left, edu-prog.department-gen) + linebreak() + uline(align: left, uni.subjects.at(subject, default: subject)) + linebreak() + uline(align: left, [#edu-prog.code #edu-prog.name-long]) + }, + ) + grid( + columns: (1fr, 1fr, 1fr), + gutter: 0.3fr, + [#bold[Курс] #uline(author.course)], + [#bold[Група] #uline([#author.edu-program\-#author.group])], + [#bold[Семестр] #uline(author.semester)], + ) + + linebreak() + linebreak() + linebreak() + + align(center, bold[ЗАВДАННЯ \ на курсову роботу студента]) + + linebreak() + + uline(align: left)[_#author.full-name-gen _] + + linebreak() + linebreak() + + bold[\1. Тема роботи:] + uline[#title.] + + linebreak() + + { + bold[\2. Строк здачі закінченої роботи:] + uline(task-list.done-date.display("[day].[month].[year]")) + hfill(10fr) + } + + linebreak() + + bold[\3. Вихідні дані для роботи:] + uline(task-list.source) + + linebreak() + + bold[\4. Зміст розрахунково-пояснювальної записки:] + uline(task-list.content) + + linebreak() + + bold[\5. Перелік графічного матеріалу:] + uline(task-list.graphics) + + linebreak() + + { + bold[\6. Дата видачі завдання:] + uline(task-list.initial-date.display("[day].[month].[year]")) + hfill(10fr) + } + + pagebreak() + } + + // page 3 {{{2 + { + align(center, bold[КАЛЕНДАРНИЙ ПЛАН]) + set par(first-line-indent: 0pt) + + linebreak() + + calendar-plan.plan-table + + linebreak() + + grid( + columns: (5fr, 5fr), + grid( + columns: (1fr, 2fr, 1fr), + gutter: 0.2fr, + [ + Студент \ + Керівник \ + #align(center)["#underline[#calendar-plan.approval-date.day()]"] + ], + [ + #uline(align: center, []) \ + #uline(align: center, []) \ + #uline(align: center, month-gen(calendar-plan.approval-date.month())) + ], + [ + \ \ + #underline[#calendar-plan.approval-date.year()] р. + ], + ), + [ + #author.name, \ + #head-mentor.degree + #head-mentor.name. + ], + ) + + pagebreak() + } + + // page 4 {{{2 + [ + #align(center, bold[РЕФЕРАТ]) \ + + #context [ + #let pages = counter(page).final().at(0) + #let images = query(figure.where(kind: image)).len() + #let tables = query(figure.where(kind: table)).len() + #let bibs = bib-count.final().dedup().len() + /* TODO: why this stopped working? + #let tables = counter(figure.where(kind: table)).final().at(0) + #let images = counter(figure.where(kind: image)).final().at(0)*/ + + #let counters = () + + #if pages != 0 { counters.push[#pages с.] } + #if tables != 0 { counters.push[#tables табл.] } + #if images != 0 { counters.push[#images рис.] } + #if bibs != 0 { counters.push[#bibs джерел] } + + Пояснювальна записка до курсової роботи: #counters.join(", "). + ] + + \ + + #( + abstract + .keywords + .map(upper) + .sorted(by: (a, b) => { + if is-cyr(a) != is-cyr(b) { true } else { a < b } + }) + .join(", ") + ) + + \ + #abstract.text + ] + + // page 5 {{{2 + outline( + title: [ + ЗМІСТ + #v(spacing * 2, weak: true) + ], + depth: 2, + indent: auto, + ) +} diff --git a/src/title-pages/main.typ b/src/title-pages/main.typ new file mode 100644 index 0000000..f28c162 --- /dev/null +++ b/src/title-pages/main.typ @@ -0,0 +1,2 @@ +#import "pz-lb/main.typ" as pz-lb +#import "coursework/main.typ" as cw diff --git a/src/title-pages/pz-lb/complex.typ b/src/title-pages/pz-lb/complex.typ new file mode 100644 index 0000000..1ab6309 --- /dev/null +++ b/src/title-pages/pz-lb/complex.typ @@ -0,0 +1,60 @@ +#import "../../helpers.typ": * +#let complex(uni, edu-program, subject, type, number, title, authors, mentors) = { + align(center)[ + Міністерство освіти і науки України \ + #uni.name + + \ + #set par(first-line-indent: 0pt) + #align(left)[ + #let edu = uni.edu-programs.at(edu-program) + Кафедра #underline(edu.department-gen) \ + Спеціальність #underline([#edu.code #edu.description]) \ + Освітня програма #underline(edu.name-long) + ] + + \ \ + + #pz-lb-title(type, number: number) + + з навчальної дисципліни "#uni.subjects.at(subject, default: subject)"\ + #if title != none [з теми "#eval(title, mode: "markup")"\ ] + #if authors.first().variant != none [\ Варіант №#authors.first().variant\ ] + + \ \ \ + + #align(right)[ + #if authors.len() == 1 { + let a = authors.first() + [#gender-form("author", dict: a):\ + студент групи #a.edu-program\-#a.group\ #a.name\ ] + text(size: 8pt, [(прізвище та ініціали)\ ]) + } else if authors.len() > 1 [ + #gender-verb("author"):\ + #for a in authors [студент групи #a.edu-program\-#a.group\ #a.name\ ] + #text(size: 8pt, [(прізвище та ініціали)\ ]) + ] + + \ + + #if mentors.len() == 1 { + let m = mentors.first() + [#gender-form("mentor", dict: m):\ ] + degree-get(m) + [#m.name\ ] + text(size: 8pt, [(прізвище та ініціали)\ ]) + } else if mentors.len() > 1 [ + #gender-verb("mentor"):\ + #for m in mentors { + degree-get(m) + [#m.name\ ] + } + ] + ] + + #v(1fr) + + Харків\ + #datetime.today().display("[year]") + ] +} diff --git a/src/title-pages/pz-lb/main.typ b/src/title-pages/pz-lb/main.typ new file mode 100644 index 0000000..80af7e9 --- /dev/null +++ b/src/title-pages/pz-lb/main.typ @@ -0,0 +1,2 @@ +#import "complex.typ": * +#import "nure.typ": * diff --git a/src/title-pages/pz-lb/nure.typ b/src/title-pages/pz-lb/nure.typ new file mode 100644 index 0000000..40d5abd --- /dev/null +++ b/src/title-pages/pz-lb/nure.typ @@ -0,0 +1,52 @@ +#import "../../helpers.typ": * +#let nure(uni, edu-program, subject, type, number, title, authors, mentors) = { + align(center)[ + #upper([Міністерство освіти і науки України\ #uni.name]) + + \ \ + Кафедра #uni.edu-programs.at(edu-program).department-gen + + \ \ \ + #pz-lb-title(type, number: number) + + з дисципліни: "#uni.subjects.at(subject, default: subject)" + #if title != none [\ з теми: "#eval(title, mode: "markup")"] + + \ \ \ \ + #columns(2)[ + #set align(left) + #set par(first-line-indent: 0pt) + + #if authors.len() == 1 { + let a = authors.first() + [#gender-form("author", dict: a):\ ] + [ст. гр. #a.edu-program\-#a.group\ ] + [#a.name\ ] + if not is-empty(a.variant) [Варіант: №#a.variant] + } else if authors.len() > 1 [ + #gender-form("author"):\ + #for a in authors [ст. гр. #a.edu-program\-#a.group\ #a.name\ ] + ] + + #colbreak() + #set align(right) + + #if mentors.len() == 1 { + let m = mentors.first() + [#gender-form("mentor", dict: m):\ ] + degree-get(m) + [#m.name\ ] + } else if mentors.len() > 1 [ + #gender-form("mentor"):\ + #for m in mentors { + degree-get(m) + [#m.name\ ] + } + ] + ] + + #v(1fr) + + Харків -- #datetime.today().display("[year]") + ] +} diff --git a/src/utils.typ b/src/utils.typ new file mode 100644 index 0000000..1b81922 --- /dev/null +++ b/src/utils.typ @@ -0,0 +1,56 @@ +/// bold text +#let bold(content) = text(weight: "bold")[#content] + +/// numberless heading +#let nheading(title) = heading(depth: 1, numbering: none, title) + +/// fill horizontal space with a filled box +#let hfill(width) = box(width: width, repeat(" ")) // HAIR SPACE (U+200A) + +/// underlined cell with centered content by default +#let uline(align: center, content) = underline[ + #if align != left { hfill(1fr) } + #content + #if align != right { hfill(1fr) } +] + +/// Extract filename stem without extension +#let stem(path) = path.split("/").last().split(".").first() + +/// Extract parent directory name +#let parent-dir(path) = path.split("/").at(-2, default: "") + +/// Generate label from image path: +/// - "image.png" → "image" +/// - "img/foo/bar.png" → "foo_bar" +#let img-label(path) = { + let name = stem(path) + let parent = parent-dir(path) + + // If parent exists and name doesn't start with parent name, combine them + let base = if parent != "" and not name.starts-with(parent) { + parent + "_" + name + } else { + name + } + + label(base.replace(" ", "_")) +} + +/// Format image caption based on optional source +#let img-caption(base-caption, source) = { + if source == none { + base-caption + " (рисунок виконано самостійно)" + } else if source == () or source == "" { + base-caption + } else { + base-caption + " (за даними " + source + ")" + } +} + +/// captioned image with auto-generated label from path +/// Usage: img("path/to/image.png", "Caption")(optional: "source") +#let img(path, caption, ..sink) = { + let source = sink.pos().at(0, default: ()) + [ #figure(image(path, ..sink.named()), caption: utils.img-caption(caption, source)) #utils.img-label(path) ] +} diff --git a/template/bibl.yml b/template/bibl.yml index 745471e..a05e699 100644 --- a/template/bibl.yml +++ b/template/bibl.yml @@ -6,7 +6,6 @@ go: value: https://go.dev/ date: 2024-12-10 - htmx: type: Web title: Htmx - high power tools for html diff --git a/template/config/doc.yaml b/template/config/doc.yaml deleted file mode 100644 index 1e6f7d5..0000000 --- a/template/config/doc.yaml +++ /dev/null @@ -1,22 +0,0 @@ -title: Потiк керування та алгоритмічні структури Bash -subject: СПМ -doctype: ЛБ -worknumber: 2 -mentors: - - name: Шевченко Т. Г. - degree: Доцент кафедри ПІ - gender: m - - name: Франко І. Я. - degree: Асистент кафедри ПІ - gender: m -edu_program: &EDU ПЗПІ -university: ХНУРЕ -authors: - - name: Косач Л. П. - full_name_gen: Косач Лариси Петрівни - course: 2 - edu: *EDU - gender: f - group: 23-2 - semester: 4 - variant: 8 diff --git a/template/coursework.typ b/template/coursework.typ index 75b80f1..b286a40 100644 --- a/template/coursework.typ +++ b/template/coursework.typ @@ -1,13 +1,19 @@ #import "@local/nure:0.1.0": * +#import style: spacing -#let author = ( - name: "Ситник Є. С.", - full_name_gen: "Ситника Єгора Сергійовича", - course: 2, - semester: 3, - variant: 13, - group: "23-2", - gender: "m", +#import "utils.typ": img + +#let authors = ( + ( + name: "Ситник Є. С.", + full-name-gen: "Ситника Єгора Сергійовича", + edu-program: "ПЗПІ", + group: "23-2", + gender: "m", + course: 2, + semester: 3, + variant: 13, + ), ) #let mentors = ( @@ -16,34 +22,39 @@ (name: "Широкопетлєва М. С.", degree: "Ст. викл. каф. ПІ"), ) -#let task_list = ( - done_date: datetime(year: 2024, month: 12, day: 27), - initial_date: datetime(year: 2024, month: 9, day: 15), +#let task-list = ( + done-date: datetime(year: 2024, month: 12, day: 27), + initial-date: datetime(year: 2024, month: 9, day: 15), source: "методичні вказівки до виконання курсової роботи, вимоги до інформаційної системи, предметна область, що пов’язана з управлінням класом та класним керівництвом.", content: "вступ, аналіз предметної області; постановка задачі; проектування бази даних; опис програми; висновки; перелік джерел посилання.", graphics: "загальна діаграма класів, ER-діаграма, UML-діаграми, DFD-діаграма, схема БД в 1НФ, 2НФ, 3НФ, копії екранів (“скриншоти”) прикладної програми, приклади звітів прикладної програми.", ) -#let calendar_plan = ( - plan_table: table( +#let calendar-plan = ( + plan-table: table( columns: 4, align: (center, left, center, center), [Номер], [Назва етапів курсової роботи], [Строк виконання етапів роботи], [Примітки], + [1], [Аналіз предметної області], [15.09.24 – 24.09.24], [Виконано], [2], [Концептуальне моделювання], [24.09.24-30.09.24], [~], [2], [Постановка задачі], [28.09.24 – 2.10.24], [Виконано], [3], [Побудова ER-діаграми та схеми БД], [2.10.24 – 18.10.24], [Виконано], [4], [Оформлення розділів 1, 2 та 3.1, 3.2 пояснювальної записки], [10.10.24 - 18.10.24], [Виконано], + [5], [Перша контрольна точка з курсової роботи], [20.10.24], [Виконано], [6], [Нормалізація бази даних], [20.10.24 - 15.11.24], [Виконано], [7], [Створення програми], [20.10.24 – 20.11.24], [Виконано], [8], [Тестування програми, наповнення бази даних], [20.11.24 - 5.12.24], [Виконано], + [9], [Друга контрольна точка з курсової роботи], [7.12.24], [Виконано], [10], [Реалізація остаточної версії програми], [7.12.24-15.12.24], [Виконано], + [11], [Оформлення інших розділів пояснювальної записки], [1.11.24 – 25.12.24], [Виконано], + [12], [Третя контрольна точка з курсової роботи], [27.12.24], [Виконано], ), - approval_date: datetime(year: 2024, month: 12, day: 27), + approval-date: datetime(year: 2024, month: 12, day: 27), ) #let abstract = ( @@ -87,7 +98,7 @@ #v(-spacing) == Частина 1 #lorem(100) - == Частина2 + == Частина 2 #lorem(200) = Приклад звіту 2 @@ -97,16 +108,15 @@ #lorem(200) ] -#show: cw-template.with( +#show: coursework.with( title: "Інформаційна система «Помічник класного керівника». Керування класом", - subject_short: "БД", - edu_program_short: "ПЗПІ", - author: author, + subject: "БД", + authors: authors, mentors: mentors, - task_list: task_list, - calendar_plan: calendar_plan, + task-list: task-list, + calendar-plan: calendar-plan, abstract: abstract, - bib_path: "bibl.yml", + bib-path: bytes(read("bibl.yml")), // NOTE: use `bytes("bibl.yml")` as typst looks in template dir when using just filename appendices: appendices, ) diff --git a/template/lab.typ b/template/lab.typ index f5bd94e..cedd86f 100644 --- a/template/lab.typ +++ b/template/lab.typ @@ -1,6 +1,31 @@ -#import "@local/nure:0.1.0": * +#import "@local/nure:0.1.1": * +#import "utils.typ": img -#show: pz-lb-template.with(..yaml("config/doc.yaml")) +#import style: spacing + +#show: pz-lb.with( + university: "ХНУРЕ", + subject: "СМП", + type: "ЛБ", + number: 2, + title: "Потiк керування та алгоритмічні структури Bash", + mentors: ( + (name: "Шевченко Т. Г.", degree: "Доцент кафедри ПІ", gender: "m"), + (name: "Франко І. Я.", degree: "Асистент кафедри ПІ", gender: "m"), + ), + authors: ( + ( + name: "Косач Л. П.", + full-name-gen: "Косач Лариси Петрівни", + edu-program: "КУІБ", + group: "23-2", + gender: "f", + course: 2, + semester: 4, + variant: 8, + ), + ), +) #v(-spacing) @@ -29,3 +54,25 @@ - #lorem(25); - #lorem(42); - #lorem(27). + +#show: style.appendices + += Quote +#link("https://youtu.be/bJQj1uKtnus")[ + The art isn't the art, the art is never the art, + the art is the thing that happens inside you when you make it and the feeling in the heart of the beholder. +] + + += Приклад звіту 1 +#v(-spacing) +== Частина 1 +#lorem(100) +== Частина 2 +#lorem(200) + += Приклад звіту 2 +#lorem(200) + += Приклад звіту 3 +#lorem(200) diff --git a/template/utils.typ b/template/utils.typ new file mode 100644 index 0000000..3ace327 --- /dev/null +++ b/template/utils.typ @@ -0,0 +1,7 @@ +#import "@local/nure:0.1.1": utils +/// captioned image with auto-generated label from path +/// Usage: img("path/to/image.png", "Caption")(optional: "source") +#let img(path, caption, ..sink) = { + let source = sink.pos().at(0, default: ()) + [ #figure(image(path, ..sink.named()), caption: utils.img-caption(caption, source)) #utils.img-label(path) ] +} diff --git a/typst.toml b/typst.toml index c09a9d5..81aa0e0 100644 --- a/typst.toml +++ b/typst.toml @@ -1,7 +1,7 @@ [package] name = "nure" -version = "0.1.0" -entrypoint = "lib.typ" +version = "0.1.1" +entrypoint = "src/lib.typ" authors = ["linerds"] license = "GPL-3.0" description = "Typst NURE package"