From 1a06e7008268d1e719aed285c0b4a8150bd0ce97 Mon Sep 17 00:00:00 2001 From: Sytnyk Yehor Date: Thu, 6 Feb 2025 14:50:02 +0200 Subject: [PATCH] moved WIP templates here --- default.typ | 267 +++++++++++++++++++++++ test.typ | 600 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 867 insertions(+) create mode 100644 default.typ create mode 100644 test.typ diff --git a/default.typ b/default.typ new file mode 100644 index 0000000..9aea294 --- /dev/null +++ b/default.typ @@ -0,0 +1,267 @@ + +#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/test.typ b/test.typ new file mode 100644 index 0000000..ae40509 --- /dev/null +++ b/test.typ @@ -0,0 +1,600 @@ + +#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: "БД", +) +