From 7c7ac9257d03daf100e40f82b70780e4bd25b5c4 Mon Sep 17 00:00:00 2001 From: Sytnyk Yehor Date: Sat, 8 Feb 2025 23:26:49 +0200 Subject: [PATCH] usable --- .gitignore | 1 + README.md | 2 +- bibl.yml | 80 +++++++ default.typ | 267 ---------------------- example.typ | 127 +++++++++++ template.typ | 609 +++++++++++++++++++++++++++++++++++++++++++++++++++ test.typ | 600 -------------------------------------------------- 7 files changed, 818 insertions(+), 868 deletions(-) create mode 100644 bibl.yml delete mode 100644 default.typ create mode 100644 example.typ create mode 100644 template.typ delete mode 100644 test.typ diff --git a/.gitignore b/.gitignore index e69de29..a136337 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +*.pdf diff --git a/README.md b/README.md index 2eb1aa0..d8f0c95 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # Typst template for NURE works. > [!WARNING] -> Extremely WIP! +> Still WIP, but you can use it. diff --git a/bibl.yml b/bibl.yml new file mode 100644 index 0000000..745471e --- /dev/null +++ b/bibl.yml @@ -0,0 +1,80 @@ +go: + type: Web + title: The Go Programming Language + author: The Go Programming Language + url: + value: https://go.dev/ + date: 2024-12-10 + + +htmx: + type: Web + title: Htmx - high power tools for html + author: Htmx - high power tools for html + url: + value: https://htmx.org/ + date: 2024-12-10 + +mysql: + type: Book + title: MySQL Language Reference + author: Ab M. + publisher: MySQL Press + date: 2004 + page-total: 600 + +neovim: + type: Web + title: About neovim + author: Neovim + url: + value: https://neovim.io/charter/ + date: 2024-12-10 + +echo: + type: Web + title: High performance, extensible, minimalist Go web framework | Echo + author: High performance, extensible, minimalist Go web framework | Echo + url: + value: https://echo.labstack.com/ + date: 2024-12-10 + +sqlx: + type: Web + title: Illustrated Guide to SQLX + author: GitHub Pages + url: + value: http://jmoiron.github.io/sqlx/ + date: 2024-12-10 + +human: + type: Web + title: Про нас | HUMAN + author: HUMAN + url: + value: https://human.ua/ + date: 2024-12-11 + +docker: + type: Web + title: "Docker: accelerated container application development" + author: Docker + url: + value: https://www.docker.com/ + date: 2024-12-15 + +docker_compose: + type: Web + title: Docker compose + author: Docker Documentation + url: + value: https://docs.docker.com/compose/ + date: 2024-12-15 + +hateoas: + type: Web + title: HATEOAS and Why It's Needed in RESTful API? + author: GeeksforGeeks + url: + value: https://www.geeksforgeeks.org/hateoas-and-why-its-needed-in-restful-api/ + date: 2024-12-15 diff --git a/default.typ b/default.typ deleted file mode 100644 index 9aea294..0000000 --- a/default.typ +++ /dev/null @@ -1,267 +0,0 @@ - -#import "@preview/indenta:0.0.3": fix-indent - -#let subjects = ( - БД: ( - name: "Бази даних", - mentor: ( - name: "Черепанова Ю. Ю.", - gender: "f", - degree: "ст. викл. каф. ПІ", - ), - ), -) - -/// DSTU 3008:2015 Template for NURE -/// -> content -/// - doc (content): Content to apply the template to. -/// - title (string): Title of the document. -/// - authors: List of Author dicts. -/// - mentor: Mentor dict. -/// - include_toc: Include table of contents? -/// - doctype ("lb" | "pz" | "ku"): Document type. -/// - worknumber: Number of the work, can be omitted. -/// - subject: Subject name. -#let conf( - doc, - title: [Work Title], - authors: ((name: "Author Name", variant: 1, group: "Group Name", gender: "m"),), - include_toc: false, - doctype: "ЛБ", - worknumber: 1, - subject_shorthand: "NONE", -) = { - // numless header - let numless(it) = { - set heading(numbering: none) - it - } - - // LaTeX-like vfill shorthand - let vfill = () => v(1fr) - - set document(title: title, author: authors.at(0).name) - - 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", size: 14pt, hyphenate: false, lang: "ua") - set par(justify: true, first-line-indent: 1.25cm) - - // set 1.5 line spacing - let spacing = 0.95em - set block(spacing: spacing) - set par(spacing: spacing) - set par(leading: spacing) - - // enums and lists - let ua_alph(pattern: "а)") = { - // INFO: This alphabet is not full, maybe it should be extended or maybe not. - // I cant remember nor find proper formatting rules. - // "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя" (full alphabet) - - let alphabet = "абвгдежиклмнпрстуфхцшщюя".split("") - - i => { - let letter = alphabet.at(i) - let str = "" - for char in pattern { - if char == "а" { - str += letter - } else if char == "А" { - str += upper(letter) - } else { - str += char - } - } - str - } - } - - set enum(numbering: ua_alph(pattern: "а)"), 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 - set figure.caption(separator: [ -- ]) - - let fig = counter("figure") - let tab = counter("table") - - show figure.where(kind: image): set figure( - numbering: (..) => { - fig.step() - context str(counter(heading).get().at(0) + worknumber - 1) + "." + context fig.display() - }, - ) - show figure.where(kind: table): set figure( - numbering: (..) => { - tab.step() - context str(counter(heading).get().at(0) + worknumber - 1) + "." + context tab.display() - }, - ) - - // TODO: Maybe this will be better. Must be investigated. - // - // set math.equation(numbering: (..num) => - // numbering("(1.1)", counter(heading).get().first(), num.pos().first()) - // ) - // set figure(numbering: (..num) => - // numbering("1.1", counter(heading).get().first(), num.pos().first()) - // ) - - show figure: it => { - v(spacing * 2, weak: true) - it - v(spacing * 2, weak: true) - } - - // headings - // set heading(numbering: "1.1") - - // HACK: I can't set initial value for headers counter, so change is only visual. If this style is changed do not forget to fix images and tables numbering as well. - set heading(numbering: (n1, ..x) => numbering("1.1", n1 - 1 + worknumber, ..x)) - - - show heading.where(level: 1): it => { - set align(center) - set text(size: 14pt, weight: "semibold") - - pagebreak(weak: true) - - block(width: 100%, spacing: 0em)[ #upper(it) ] - } - show heading.where(level: 2): it => { - set text(size: 14pt, weight: "regular") - - block(width: 100%, spacing: 0em)[ - #h(1.25cm) - #counter(heading).display(it.numbering) - #it.body - ] - } - - let fix-spacings() = doc => { - if not doc.has("children") { return doc } - - let elems = doc.children.filter(x => x != [ ] and x.func() != parbreak) - - let is_heading = e => e != none and e.func() == heading - - for (i, elem) in elems.enumerate() { - if not is_heading(elem) { - elem - continue - } - - let prev_elem = elems.at(i - 1, default: none) - let next_elem = elems.at(i + 1, default: none) - - if elem.depth == 2 { - v(spacing * (if not is_heading(prev_elem) { 2 } else { 1 }), weak: true) - } - - elem - - v(spacing * (if not is_heading(next_elem) { 2 } else { 1 }), weak: true) - } - } - - show: fix-spacings() - show: fix-indent() - - if doctype in ("ЛБ", "ПЗ") { - let subject = subjects.at(subject_shorthand, default: "NONE") - let mentor = subject.mentor - - align( - center, - [ - МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ - - ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ - - #linebreak() - - Кафедра Програмної інженерії - - #linebreak() - #linebreak() - #linebreak() - - Звіт - - з - #if doctype == "ЛБ" { [лабораторної роботи] } else { [практичної роботи] } - #if worknumber != none { [№ #worknumber] } - - з дисципліни: "#subject.name" - - з теми: "#title" - - #linebreak() - #linebreak() - #linebreak() - - #columns(2)[ - #set align(left) - - #if authors.len() == 1 { - let author = authors.at(0) - if author.gender == "m" { [Виконав:\ ] } else { [Виконала:\ ] } - [ - ст. гр. #author.group\ - #author.name\ - #if author.variant != none { [Варіант: №#author.variant] } - ] - } else { - [ - Виконали:\ - ст. гр. #authors.at(0).group\ - #authors.map(a => [ #a.name\ ]) - ] - } - - #colbreak() - #set align(right) - - #if mentor.gender == "m" { [Перевірив:\ ] } else { [Перевірила:\ ] } - #mentor.degree #if mentor.degree.len() >= 15 { - [\ - ] - } - #mentor.name\ - ] - - #vfill() - - Харків -- #datetime.today().display("[year]") - ], - ) - } else if doctype == "КУ" { } - - if include_toc { - outline( - title: [ - ЗМІСТ - #v(spacing * 2) - ], - depth: 2, - indent: auto, - ) - } - - doc -} diff --git a/example.typ b/example.typ new file mode 100644 index 0000000..5de7a78 --- /dev/null +++ b/example.typ @@ -0,0 +1,127 @@ +#import "template.typ": * + +#let authors = ( + ( + name: "Ситник Є. С.", + full_name_gen: "Ситника Єгора Сергійовича", + variant: 13, + group: "ПЗПІ-23-2", + gender: "m", + ), +) + +#let mentors = ( + ( + name: "Черепанова Ю. Ю.", + gender: "f", + degree: "Ст. викл. каф. ПІ", + ), + ( + name: "Русакова Н. Є.", + gender: "f", + degree: "Доц. каф. ПІ", + ), + ( + name: "Широкопетлєва М. С.", + gender: "f", + degree: "Ст. викл. каф. ПІ", + ), +) + +#let task_list = ( + done_date: datetime(year: 2024, month: 12, day: 27), + initial_data: datetime(year: 2024, month: 9, day: 15), + source: "методичні вказівки до виконання курсової роботи, вимоги до інформаційної системи, предметна область, що пов’язана з управлінням класом та класним керівництвом.", + content: "вступ, аналіз предметної області; постановка задачі; проектування бази даних; опис програми; висновки; перелік джерел посилання.", + graphics: "загальна діаграма класів, ER-діаграма, UML-діаграми, DFD-діаграма, схема БД в 1НФ, 2НФ, 3НФ, копії екранів (“скриншоти”) прикладної програми, приклади звітів прикладної програми.", +) + +#let calendar_plan = ( + plan_table: [], + approval_date: datetime(year: 2024, month: 12, day: 27), +) + +#let abstract = ( + keywords: ( + "БАЗА ДАНИХ", + "АВТОМАТИЗАЦІЯ", + "КЛАСНИЙ КЕРІВНИК", + "КЛАС", + "ШКОЛА", + "GO", + "HTMX", + "MYSQL", + "SQL", + ), + text: [ + Мета даної роботи -- проєктування та розробка інформаційної системи «Помічник класного керівника. Керування класом», яка спрямована на автоматизацію процесів управління класом, облік даних про учнів, планування та аналіз навчального процесу. Основна задача інформаційної системи – спростити роботу класного керівника, забезпечити ефективну організацію документації та взаємодію з учасниками освітнього процесу. + + Для реалізації системи було використано сучасний стек технологій, а саме: Go -- як основна мова програмування для створення серверної логіки, HTMX -- для динамічного оновлення інтерфейсу без використання складних фреймворків, MySQL -- як СУБД для зберігання даних про учнів, їх оцінки та розклад, Neovim -- як середовище для швидкої та ефективної розробки коду, Go Echo -- веб-фреймворк для створення REST API, Go SQLx -- бібліотека для роботи з базою даних, що забезпечує зручність і гнучкість. + + Результат роботи – веб-додаток, який дозволяє обліковувати особисті дані учнів та їхніх опікунів, включаючи інформацію про успішність, відвідуваність та інші показники; планувати розклад занять; генерувати звіти про успішність учнів та переглядати різну статистику. Інтерфейс, створений з використанням HTMX, легко адаптується під потреби користувача. + ], +) + +#let appendices = ( + ( + title: "Приклад звіту 1", + content: [test], + ), + ( + title: "Приклад звіту 2", + content: [test], + ), + ( + title: "Приклад звіту 3", + content: [test], + ), +) + +#show: conf.with( + doctype: "КП", + title: "Інформаційна система «Помічник класного керівника». Керування класом", + subject_shorthand: "БД", + department_gen: "Програмної інженерії", + edu_program: "ПЗПІ", + authors: authors, + mentors: mentors, + task_list: task_list, + calendar_plan: calendar_plan, + abstract: abstract, + bib_path: "bibl.yml", + appendices: appendices, +) + +#heading(depth: 1, numbering: none)[Вступ] + +У сучасному освітньому середовищі інформаційні системи відіграють +ключову роль у забезпеченні ефективного управління та автоматизації процесів. +Особливо це важливо для шкіл, де необхідно систематизувати облік даних про +учнів, планувати навчальний процес і створювати звіти. Відсутність зручних +інструментів ускладнює роботу класного керівника, змушуючи його витрачати +багато часу на тяганину з документами, зокрема на складання звітів, ведення +обліку даних про учнів і підготовку розкладу, що потребує сучасних рішень для +організації взаємодії між учасниками освітнього процесу. + +Метою цієї курсової роботи є розробка інформаційної системи «Помічник +класного керівника. Керування класом», яка спрощує процес управління класом, +дозволяючи автоматизувати складання звітів, зберігати та обробляти дані про +учнів, а також планувати навчальний процес у зручному форматі, забезпечує +зручний облік даних про учнів і сприяє ефективному плануванню навчального +процесу. У процесі роботи над системою було проведено аналіз потреб +користувачів, спроєктовано реляційну базу даних і розроблено веб-додаток, який +дозволяє обліковувати особисті дані учнів та їхніх опікунів, відстежувати +успішність і відвідуваність, планувати розклад занять, формувати звіти та +переглядати статистичні дані. + +Основну серверну логіку написано мовою програмування Go@go, а для +забезпечення роботи інтерфейсу застосовано HTMX@htmx. Дані зберігаються у базі +даних MySQL@mysql, взаємодія з якою здійснюється через бібліотеку Go SQLx@sqlx. +Для створення REST API використано веб-фреймворк Go Echo@echo. +Розробка виконувалася у середовищі Neovim@neovim. + += Аналіз та концептуальне моделювання предметної області +#v(-1em) +== test +test +== test diff --git a/template.typ b/template.typ new file mode 100644 index 0000000..8b88fdb --- /dev/null +++ b/template.typ @@ -0,0 +1,609 @@ +#import "@preview/indenta:0.0.3": fix-indent + +#let hfill(width) = box(width: width, repeat(" ")) // NOTE: This is a HAIR SPACE (U+200A ), not a regular space + +#let uline(align: center, content) = underline([ + #if align != left { hfill(1fr) } + #content + #if align != right { hfill(1fr) } +]) + +#let bold(content) = text(weight: "bold")[#content] + +#let fig(path, caption) = [ + #figure( + image(path), + caption: caption, + ) + #label(path.split("/").last().split(".").first()) +] + +#let subjects = ( + "БД": "Бази даних", +) + +#let edu_programs = ( + "ПЗПІ": ( + name: "Інженерія програмного забезпечення", + number: 121, + ), +) + +#let month_gen(month) = ( + "січня", + "лютого", + "березня", + "квітня", + "травня", + "червня", + "липня", + "серпня", + "вересня", + "жовтня", + "листопада", + "грудня", +).at(month - 1) + +#let spacing = 0.95em + +/// DSTU 3008:2015 Template for NURE +/// -> content +/// - doc (content): Content to apply the template to. +/// - doctype ("ЛБ" | "ПЗ" | "КП"): Document type. +/// - title (str): Title of the document. +/// - subject_shorthand (str): Subject name. +/// - department_gen (str): Department name in genitive form. +/// - edu_program_number (int): Education program number. +/// - worknumber (int): Number of the work, can be omitted. +/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts. +/// - task_list (done_date: datetime, initial_data: datetime, source: str, content: str, graphics: str): Task list. +/// - calendar_plan (plan_table: list, approval_date: datetime): Calendar plan. +/// - abstract (keywords: (str,), text: [str,]): Abstract. +#let conf( + doc, + title: "NONE", + doctype: "NONE", + subject_shorthand: "NONE", + department_gen: "Програмної інженерії", + worknumber: 1, + authors: (), + mentors: (), + edu_program: "NONE", + task_list: (), + calendar_plan: (), + abstract: (), + bib_path: "bibl.yml", + appendices: (), +) = { + set document(title: title, author: authors.at(0).name) + + 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: "Liberation Serif", size: 14pt, hyphenate: false, lang: "ua") + set par(justify: true, first-line-indent: 1.25cm) + set underline(evade: false) + + // set 1.5 line spacing + set block(spacing: spacing) + set par(spacing: spacing) + set par(leading: spacing) + + // enums and lists + let ua_alph_numbering() = { + // INFO: This alphabet is not full, maybe it should be extended or maybe not. + // I cant remember nor find proper formatting rules. + // "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя" (full alphabet) + + let alphabet = "абвгдежиклмнпрстуфхцшщюя".split("") + i => { alphabet.at(i) + ")" } + } + + set enum(numbering: ua_alph_numbering(), 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: [--]) + + // citations + let bib-count = state("citation-counter", ()) + show cite: it => { + it + bib-count.update(((..c)) => (..c, it.key)) + } + let cit = context bib-count.final().dedup().len() + + // figures + set figure.caption(separator: [ -- ]) + + let img = counter("image") + let tab = counter("table") + + show figure.where(kind: image): set figure( + numbering: (..) => { + img.step() + context str(counter(heading).get().at(0) + worknumber - 1) + "." + context img.display() + }, + ) + show figure.where(kind: table): set figure( + numbering: (..) => { + tab.step() + context str(counter(heading).get().at(0) + worknumber - 1) + "." + context tab.display() + }, + ) + + // TODO: Maybe this will be better. Must be investigated. + // + // set math.equation(numbering: (..num) => + // numbering("(1.1)", counter(heading).get().first(), num.pos().first()) + // ) + // set figure(numbering: (..num) => + // numbering("1.1", counter(heading).get().first(), num.pos().first()) + // ) + + show figure: it => { + v(spacing * 2, weak: true) + it + v(spacing * 2, weak: true) + } + + // headings + // HACK: I can't set initial value for headers counter, so change is only visual. If this style is changed do not forget to fix images and tables numbering as well. + set heading(numbering: (n1, ..x) => numbering("1.1", n1 - 1 + worknumber, ..x)) + + 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: fix-indent() + + let subject = subjects.at(subject_shorthand, default: "NONE") + + if doctype in ("ЛБ", "ПЗ") { + let mentor = subject.mentors.at(0) + align(center) + [ + МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ + + ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ + + #linebreak() + + Кафедра Програмної інженерії + + #linebreak() + #linebreak() + #linebreak() + + Звіт + + з + #if doctype == "ЛБ" [лабораторної роботи] else [практичної роботи] + #if worknumber != none [№ #worknumber] + + з дисципліни: "#subject.name" + + з теми: "#title" + + #linebreak() + #linebreak() + #linebreak() + + #columns(2)[ + #set align(left) + + #if authors.len() == 1 [ + #let author = authors.at(0) + #if author.gender == "m" { [Виконав:\ ] } else { [Виконала:\ ] } + ст. гр. #author.group\ + #author.name\ + #if author.variant != none { [Варіант: №#author.variant] } + ] else [ + Виконали:\ + ст. гр. #authors.at(0).group\ + #authors.map(a => [ #a.name\ ]) + ] + + #colbreak() + #set align(right) + + #if mentor.gender == "m" { [Перевірив:\ ] } else { [Перевірила:\ ] } + #mentor.degree #if mentor.degree.len() >= 15 [\ ] + #mentor.name\ + ] + + #v(1fr) + + Харків -- #datetime.today().display("[year]") + ] + } else if doctype == "КП" { + let head_mentor = mentors.at(0) + let author = authors.at(0) + let edu_program = edu_programs.at(edu_program) + + // page 1 + align(center)[ + МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ + + ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ + + #linebreak() + + Кафедра Програмної інженерії + + #linebreak() + + ПОЯСНЮВАЛЬНА ЗАПИСКА + + ДО КУРСОВОЇ РОБОТИ + + з дисципліни: "#subject" + + Тема роботи: "#title" + + #linebreak() + #linebreak() + #linebreak() + + #columns(2, gutter: 4cm)[ + #set align(left) + + #if authors.len() == 1 [ + #if author.gender == "m" { [Виконав\ ] } else { [Виконала\ ] } ст. гр. #author.group + ] + + #linebreak() + Керівник:\ + #head_mentor.degree + + #linebreak() + Робота захищена на оцінку + + #linebreak() + Комісія:\ + #for mentor in mentors { + [#mentor.degree\ + ] + } + + #colbreak() + #set align(left) + + #linebreak() + #author.name + + #linebreak() + #linebreak() + #head_mentor.name + + #linebreak() + #underline(" " * 35) + + #linebreak() + #linebreak() + #for mentor in mentors { + [#mentor.name\ + ] + } + ] + + #v(1fr) + + Харків -- #datetime.today().display("[year]") + + #pagebreak() + ] + // + + // page 2 + { + uline([Харківський національний університет радіоелектроніки]) + + linebreak() + linebreak() + + grid( + columns: (100pt, 1fr), + bold([ + Кафедра + Дисципліна + Спеціальність + ]), + { + uline(align: left, department_gen) + linebreak() + uline(align: left, subject) + linebreak() + uline(align: left, [#edu_program.number #edu_program.name]) + }, + ) + grid( + columns: (1fr, 1fr, 1fr), + gutter: 0.3fr, + [#bold("Курс") #uline(2)], [#bold("Група") #uline(author.group)], [#bold("Семестр") #uline(3)], + ) + + linebreak() + linebreak() + linebreak() + + align(center)[#bold([ + ЗАВДАННЯ + + на курсову роботу студента + ])] + + linebreak() + + uline(align: left)[#emph(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.done_date.display("[day].[month].[year]")) + hfill(10fr) + } + + pagebreak() + } + + // page 3 + { + align(center)[#bold([КАЛЕНДАРНИЙ ПЛАН])] + + linebreak() + + calendar_plan.plan_table + + linebreak() + + grid( + columns: (6fr, 5fr), + grid( + columns: (1fr, 3fr, 1fr), + gutter: 0.2fr, + [ + Студент + #linebreak() + Керівник + #linebreak() + #align(center, ["#calendar_plan.approval_date.day()"]) + ], + [ + #uline(align: center, []) + #linebreak() + #uline(align: center, []) + #linebreak() + #uline(align: center, month_gen(calendar_plan.approval_date.month())) + ], + { + linebreak() + linebreak() + [#calendar_plan.approval_date.year() р.] + }, + ), + [ + #author.name, + #linebreak() + #head_mentor.degree + #head_mentor.name. + ], + ) + + pagebreak() + } + + // page 4 {{{ + [ + #align(center)[#bold([РЕФЕРАТ])] + #linebreak() + + #context [ + #let pages = counter(page).final().at(0) + #let tables = counter("table").final().at(0) + #let images = counter("image").final().at(0) + #let bibs = bib-count.final().dedup().len() + + #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(", "). + ] + + #linebreak() + + #{ + let keywords = abstract.keywords + let is_cyrillic = word => word + .split("") + .any(char => ("А" <= char and char <= "я") or char == "Ё" or 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(", ") + } + + #linebreak() + + #abstract.text + ] + // }}} + + // page 5 {{{ + show outline.entry: it => { + show linebreak: none + it + } + outline( + title: [ + ЗМІСТ + #v(spacing * 2) + ], + depth: 2, + indent: auto, + ) + // }}} + } + + doc + + // bibliography {{{ + show bibliography: it => { + set text(size: 0pt) + it + } + + 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 THE ISSUE + ] + } + + show enum.item: it => { + box(width: 1.25cm) + box(width: 1em + 0.5cm)[#it.number.] + it.body + linebreak() + } + + context { + let citations = query(ref.where(element: none)).map(r => str(r.target)).dedup() + + for (i, citation) in citations.enumerate() { + enum.item( + i + 1, + format-entry(bib_data.at(citation)), + ) + } + } + // }}} + + // appendices {{{ + counter(heading).update(0) + + for (i, appendix) in appendices.enumerate() [ + #set heading( + numbering: i => [ + Додаток #"АБВГДЕЖИКЛМНПРСТУФХЦШЩЮЯ".split("").at(i) + ], + ) + + #show heading: it => { + set align(center) + set text(size: 14pt, weight: "regular") + pagebreak(weak: true) + + bold(upper(counter(heading).display(it.numbering))) + + linebreak() + + it.body + + v(spacing * 2, weak: true) + } + = #appendix.title + #appendix.content + ] + // }}} +} diff --git a/test.typ b/test.typ deleted file mode 100644 index ae40509..0000000 --- a/test.typ +++ /dev/null @@ -1,600 +0,0 @@ - -#import "@preview/indenta:0.0.3": fix-indent - -#let subjects = ( - "БД": ( - name: "Бази даних", - mentors: ( - ( - name: "Черепанова Ю. Ю.", - gender: "f", - degree: "Ст. викл. каф. ПІ", - ), - ( - name: "Русакова Н. Є.", - gender: "f", - degree: "Доц. каф. ПІ", - ), - ( - name: "Широкопетлєва М. С.", - gender: "f", - degree: "Ст. викл. каф. ПІ", - ), - ), - ), -) - -/// DSTU 3008:2015 Template for NURE -/// -> content -/// - doc (content): Content to apply the template to. -/// - title (string): Title of the document. -/// - authors: List of Author dicts. -/// - mentor: Mentor dict. -/// - include_toc: Include table of contents? -/// - doctype ("lb" | "pz" | "ku"): Document type. -/// - worknumber: Number of the work, can be omitted. -/// - subject: Subject name. -#let conf( - doc, - authors: ( - ( - name: "Ситник Є. С.", - full_name_gen: "Ситника Єгора Сергійовича", - variant: 14, - group: "ПЗПІ-23-2", - ) - ), - title: "Інформаційна система «Помічник класного керівника». Керування класом", - worknumber: 1, - doctype: "ЛБ", - subject_shorthand: "БД", - department: "Програмної інженерії", - edu_program: ( - name: "Інженерія програмного забезпечення", - number: 121, - ), - task_list: ( - done_date: datetime(year: 2024, month: 12, day: 27), - initial_data: datetime(year: 2024, month: 9, day: 15), - source: "методичні вказівки до виконання курсової роботи, вимоги до інформаційної системи, предметна область, що пов’язана з управлінням класом та класним керівництвом.", - content: "вступ, аналіз предметної області; постановка задачі; проектування бази даних; опис програми; висновки; перелік джерел посилання.", - graphics: "загальна діаграма класів, ER-діаграма, UML-діаграми, DFD-діаграма, схема БД в 1НФ, 2НФ, 3НФ, копії екранів (“скриншоти”) прикладної програми, приклади звітів прикладної програми.", - ), - calendar_plan: ( - plan_table: [], - approval_date: datetime(year: 2024, month: 12, day: 27), - ), - abstract: ( - keywords: ( - "БАЗА ДАНИХ", - "АВТОМАТИЗАЦІЯ", - "КЛАСНИЙ КЕРІВНИК", - "КЛАС", - "ШКОЛА", - "GO", - "HTMX", - "MYSQL", - "SQL", - ), - text: [ - Мета даної роботи – проєктування та розробка інформаційної системи «Помічник класного керівника. Керування класом», яка спрямована на автоматизацію процесів управління класом, облік даних про учнів, планування та аналіз навчального процесу. Основна задача інформаційної системи – спростити роботу класного керівника, забезпечити ефективну організацію документації та взаємодію з учасниками освітнього процесу. - - Для реалізації системи було використано сучасний стек технологій, а саме: Go – як основна мова програмування для створення серверної логіки, HTMX – для динамічного оновлення інтерфейсу без використання складних фреймворків, MySQL – як СУБД для зберігання даних про учнів, їх оцінки та розклад, Neovim – як середовище для швидкої та ефективної розробки коду, Go Echo – веб-фреймворк для створення REST API, Go SQLx – бібліотека для роботи з базою даних, що забезпечує зручність і гнучкість. - - Результат роботи – веб-додаток, який дозволяє обліковувати особисті дані учнів та їхніх опікунів, включаючи інформацію про успішність, відвідуваність та інші показники; планувати розклад занять; генерувати звіти про успішність учнів та переглядати різну статистику. Інтерфейс, створений з використанням HTMX, легко адаптується під потреби користувача. - ], - ), - include_toc: true, -) = { - // LaTeX-like vfill/hfill shorthands - let vfill = () => v(1fr) - let hfill(width) = box(width: width, repeat(" ")) // NOTE: This is a HAIR SPACE (U+200A ), not a regular space - - set underline(evade: false) - - let uline(align: center, content) = { - underline([ - #if align != left { hfill(1fr) } - #content - #if align != right { hfill(1fr) } - ]) - } - - // other shorthands - let bold(it) = text(weight: "bold")[#it] - - let month_gen(month) = ( - "січня", - "лютого", - "березня", - "квітня", - "травня", - "червня", - "липня", - "серпня", - "вересня", - "жовтня", - "листопада", - "грудня", - ).at(month - 1) - - set document(title: title, author: authors.at(0).name) - - 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", size: 14pt, hyphenate: false, lang: "ua") - set par(justify: true, first-line-indent: 1.25cm) - - // set 1.5 line spacing - let spacing = 0.95em - set block(spacing: spacing) - set par(spacing: spacing) - set par(leading: spacing) - - // enums and lists - let ua_alph(pattern: "а)") = { - // INFO: This alphabet is not full, maybe it should be extended or maybe not. - // I cant remember nor find proper formatting rules. - // "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя" (full alphabet) - - let alphabet = "абвгдежиклмнпрстуфхцшщюя".split("") - - i => { - let letter = alphabet.at(i) - let str = "" - for char in pattern { - if char == "а" { - str += letter - } else if char == "А" { - str += upper(letter) - } else { - str += char - } - } - str - } - } - - set enum(numbering: ua_alph(pattern: "а)"), 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 - set figure.caption(separator: [ -- ]) - - let img = counter("image") - let tab = counter("table") - - show figure.where(kind: image): set figure( - numbering: (..) => { - img.step() - context str(counter(heading).get().at(0) + worknumber - 1) + "." + context img.display() - }, - ) - show figure.where(kind: table): set figure( - numbering: (..) => { - tab.step() - context str(counter(heading).get().at(0) + worknumber - 1) + "." + context tab.display() - }, - ) - - // TODO: Maybe this will be better. Must be investigated. - // - // set math.equation(numbering: (..num) => - // numbering("(1.1)", counter(heading).get().first(), num.pos().first()) - // ) - // set figure(numbering: (..num) => - // numbering("1.1", counter(heading).get().first(), num.pos().first()) - // ) - - show figure: it => { - v(spacing * 2, weak: true) - it - v(spacing * 2, weak: true) - } - - // headings - // set heading(numbering: "1.1") - - // HACK: I can't set initial value for headers counter, so change is only visual. If this style is changed do not forget to fix images and tables numbering as well. - set heading(numbering: (n1, ..x) => numbering("1.1", n1 - 1 + worknumber, ..x)) - - - show heading.where(level: 1): it => { - set align(center) - set text(size: 14pt, weight: "semibold") - - pagebreak(weak: true) - - block(width: 100%, spacing: 0em)[ #upper(it) ] - } - show heading.where(level: 2): it => { - set text(size: 14pt, weight: "regular") - - block(width: 100%, spacing: 0em)[ - #h(1.25cm) - #counter(heading).display(it.numbering) - #it.body - ] - } - - let fix-spacings() = doc => { - if not doc.has("children") { return doc } - - let elems = doc.children.filter(x => x != [ ]) - - let is_heading = e => e != none and e.func() == heading - - for (i, elem) in elems.enumerate() { - if not is_heading(elem) { - elem - continue - } - - let prev_elem = elems.at(i - 1, default: none) - let next_elem = elems.at(i + 1, default: none) - - if elem.depth == 2 { - v(spacing * (if not is_heading(prev_elem) { 2 } else { 1 }), weak: true) - } - - elem - - v(spacing * (if not is_heading(next_elem) { 2 } else { 1 }), weak: true) - } - } - - show: fix-spacings() - show: fix-indent() - - let subject = subjects.at(subject_shorthand, default: "NONE") - - if doctype in ("ЛБ", "ПЗ") { - let mentor = subject.mentors.at(0) - align( - center, - [ - МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ - - ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ - - #linebreak() - - Кафедра Програмної інженерії - - #linebreak() - #linebreak() - #linebreak() - - Звіт - - з - #if doctype == "ЛБ" { [лабораторної роботи] } else { [практичної роботи] } - #if worknumber != none { [№ #worknumber] } - - з дисципліни: "#subject.name" - - з теми: "#title" - - #linebreak() - #linebreak() - #linebreak() - - #columns(2)[ - #set align(left) - - #if authors.len() == 1 { - let author = authors.at(0) - if author.gender == "m" { [Виконав:\ ] } else { [Виконала:\ ] } - [ - ст. гр. #author.group\ - #author.name\ - #if author.variant != none { [Варіант: №#author.variant] } - ] - } else { - [ - Виконали:\ - ст. гр. #authors.at(0).group\ - #authors.map(a => [ #a.name\ ]) - ] - } - - #colbreak() - #set align(right) - - #if mentor.gender == "m" { [Перевірив:\ ] } else { [Перевірила:\ ] } - #mentor.degree #if mentor.degree.len() >= 15 { - [\ - ] - } - #mentor.name\ - ] - - #vfill() - - Харків -- #datetime.today().display("[year]") - ], - ) - } else if doctype == "КУ" { - let head_mentor = subject.mentors.at(0) - let author = authors.at(0) - - // page 1 {{{ - align(center)[ - МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ - - ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ - - #linebreak() - - Кафедра Програмної інженерії - - #linebreak() - - ПОЯСНЮВАЛЬНА ЗАПИСКА - - ДО КУРСОВОЇ РОБОТИ - - з дисципліни: "#subject.name" - - Тема роботи: "#title" - - #linebreak() - #linebreak() - #linebreak() - - #columns(2, gutter: 4cm)[ - #set align(left) - - #if authors.len() == 1 [ - #if author.gender == "m" { [Виконав\ ] } else { [Виконала\ ] } ст. гр. #author.group - ] - - #linebreak() - Керівник:\ - #head_mentor.degree - - #linebreak() - Робота захищена на оцінку - - #linebreak() - Комісія:\ - #for mentor in subject.mentors { - [#mentor.degree\ - ] - } - - #colbreak() - #set align(left) - - #linebreak() - #author.name - - #linebreak() - #linebreak() - #head_mentor.name - - #linebreak() - #underline(" " * 35) - - #linebreak() - #linebreak() - #for mentor in subject.mentors { - [#mentor.name\ - ] - } - ] - - #vfill() - - Харків -- #datetime.today().display("[year]") - - #pagebreak() - ] - // }}} - - // page 2 {{{ - uline([Харківський національний університет радіоелектроніки]) - - linebreak() - linebreak() - - grid( - columns: (100pt, 1fr), - bold([ - Кафедра - Дисципліна - Спеціальність - ]), - { - uline(align: left, department) - linebreak() - uline(align: left, subject.name) - linebreak() - uline(align: left, [#edu_program.number #edu_program.name]) - }, - ) - grid( - columns: (1fr, 1fr, 1fr), - gutter: 0.3fr, - [#bold("Курс") #uline(2)], [#bold("Група") #uline(author.group)], [#bold("Семестр") #uline(3)], - ) - - linebreak() - linebreak() - linebreak() - - align(center)[#bold([ - ЗАВДАННЯ - - на курсову роботу студента - ])] - - linebreak() - - uline(align: left)[#emph(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.done_date.display("[day].[month].[year]")) - hfill(10fr) - } - - pagebreak() - // }}} - - // page 3 {{{ - heading(numbering: none, depth: 1, [Календарний план]) - - calendar_plan.plan_table - - linebreak() - - grid( - columns: (6fr, 5fr), - grid( - columns: (1fr, 3fr, 1fr), - gutter: 0.2fr, - [ - Студент - #linebreak() - Керівник - #linebreak() - #align(center, ["#calendar_plan.approval_date.day()"]) - ], - [ - #uline(align: center, []) - #linebreak() - #uline(align: center, []) - #linebreak() - #uline(align: center, month_gen(calendar_plan.approval_date.month())) - ], - { - linebreak() - linebreak() - [#calendar_plan.approval_date.year() р.] - }, - ), - [ - #author.name, - #linebreak() - #head_mentor.degree - #head_mentor.name. - ], - ) - - pagebreak() - - // }}} - - // page 4 {{{ - [ - #heading(numbering: none, depth: 1, [Реферат]) - - Пояснювальна записка до курсової роботи: - #context [ #counter(page).final().at(0) ] с., - #context [ #counter("table").final().at(0) ] табл., - #context [ #counter("image").final().at(0) ] рис., - #context [ #counter(bibliography).final().at(0) ] джерел. - - #linebreak() - - #{ - let keywords = abstract.keywords - let is_cyrillic = word => word - .split("") - .any(char => ("А" <= char and char <= "я") or char == "Ё" or 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(", ") - } - - #linebreak() - - #abstract.text - ] - // }}} - } - - if include_toc { - outline( - title: [ - ЗМІСТ - #v(spacing * 2) - ], - depth: 2, - indent: auto, - ) - } - - - doc -} - -#show: conf.with( - authors: ( - (name: "Ситник Є. С.", full_name_gen: "Ситника Єгора Сергійовича", variant: 15, group: "ПЗПІ-23-2", gender: "m"), - ), - title: "Інформаційна система «Помічник класного керівника». Керування класом", - include_toc: true, - doctype: "КУ", - subject_shorthand: "БД", -) -