Explorar o código

титульный лист: выровнены черты подписей и подписи под ними, центрирование по листу

- единый помощник field() для всех полей «значение на черте + подпись»:
  черты одной строки теперь на одном уровне, подписи — всегда под чертой
  на одинаковом расстоянии (раньше «подпись, дата» висела над чертой)
- симметричные поля страницы + align(center): все блоки центрированы
  по физическому центру листа (раньше сдвиг 5-25 мм вправо)
- удалены словарь shift и три дублирующихся помощника с магическими
  смещениями (60pt/135pt/move-dy)
xander hai 1 semana
pai
achega
cd6ad3d158
Modificáronse 1 ficheiros con 87 adicións e 111 borrados
  1. 87 111
      title-page.typ

+ 87 - 111
title-page.typ

@@ -1,8 +1,8 @@
-// Титульный лист расчётного задания по экономике.
-// Конвертировано из «Титульный лист.docx», оформление — в стиле проекта
-// diploma-typst (title-page/title-page.typ). Запуск: typst compile
+// Титульный лист практической работы (СФУ).
+// Компилируется отдельно: typst compile title-page.typ
+// Подключается первой страницей в main.typ.
 
-// ── Данные расчётного задания ─────────────────────────────────────────
+// ── Данные работы (менять только здесь) ────────────────────────────────
 #let task = (
   ministry: "Министерство науки и высшего образования РФ",
   university_prename: "Федеральное государственное автономное\nобразовательное учреждение высшего образования\n",
@@ -18,139 +18,115 @@
   year: "2026 г.",
 )
 
-// ── Ручная подстройка положения блоков ────────────────────────────────
-// Значения в мм: dx > 0 — вправо, dy > 0 — вниз.
-// move() сдвигает блок только визуально и не сдвигает остальные блоки.
-#let shift = (
-  header:     (dx: 10mm, dy: 0mm),  // шапка: министерство + университет
-  institute:  (dx: 15mm, dy: 0mm),  // «Институт цветных металлов» + подпись
-  department: (dx: 10mm, dy: 0mm),  // кафедра + подпись
-  work_type:  (dx: 10mm, dy: 0mm),  // «РАСЧЕТНОЕ ЗАДАНИЕ»
-  topic:      (dx: 0mm, dy: -5mm),  // «по» + тема
-  signatures: (dx: 0mm, dy: 0mm),  // преподаватель + студент (одна таблица)
-  city:       (dx: 10mm, dy: 0mm),  // «Красноярск 2026»
-)
-
-// ── Помощники (повторяют title-page/title-page.typ) ───────────────────
-#let signature_label(body) = text(size: 10pt)[#body]
-#let topic_label_offset = -10pt
-#let signature_stroke = 0.65pt + black
-
-// Значение на underline + подпись под чертой (институт, кафедра, тема)
-#let line_field(value, label, width: 145mm) = box(width: width)[
-  #align(center)[#underline(offset: 2pt, stroke: 0.7pt + black)[#value]]
-  #v(topic_label_offset)
-  #v(-1pt)
-  #align(center)[#signature_label[#label]]
-]
-
-// Значение на underline + подпись под чертой (номер группы и т.п.)
-#let signature_field(value, label, width: 40mm) = box(width: width)[
-  #box(height: 8.5pt)[#align(center)[#underline()[#value]]]
-  #v(0pt)
-  #v(-10pt)
-  #box(height: 8.5pt)[#align(center)[#signature_label[#label]]]
-]
-
-// ФИО на underline + подпись «инициалы, фамилия»
-#let signature_name_field(value, width: 40mm) = box(width: width)[
-  #box(height: 8.5pt)[#align(center)[#underline[#value]]]
-  #v(0pt)
-  #v(-10pt)
-  #box(height: 8.5pt)[#align(center)[#signature_label[инициалы, фамилия]]]
-  #v(15pt)
-]
-
-// Пустая строка для подписи + подпись «подпись, дата»
-#let blank_signature(width: 26mm) = box(width: width)[
-  #move(dy: 10pt)[#line(length: 100%, stroke: signature_stroke)]
-  #move(dy: -5.5mm)[
-    #box(height: 8.5pt)[#align(center)[#signature_label[подпись, дата]]]
-  ]
-]
-
 // ── Страница ───────────────────────────────────────────────────────────
-#set page(paper: "a4", margin: (left: 30mm, right: 10mm, top: 20mm, bottom: 20mm))
+// Поля симметричные: центр текстовой колонки совпадает с центром листа,
+// поэтому для центрирования достаточно обычного align(center).
+#set page(paper: "a4", margin: (x: 20mm, y: 20mm))
 #set text(font: "Times New Roman", size: 14pt, lang: "ru")
 #set par(justify: false, first-line-indent: 0pt, leading: 0.65em)
 
+// ── Поле: значение на черте + подпись под чертой ───────────────────────
+// Одна и та же геометрия у всех полей листа: черта значения — underline
+// на базовой линии текста, пустая черта — line на той же высоте
+// (blank-line-dy). Оба варианта лежат в слоте фиксированной высоты,
+// поэтому подписи всегда на одинаковом расстоянии от своих черт, а
+// черты соседних полей — на одной горизонтали.
+//   value = none → пустая черта (для подписи), требуется width.
+#let label-size = 10pt
+#let field-stroke = 0.7pt + black
+#let slot-height = 16pt     // высота слота со значением
+#let blank-line-dy = 11.5pt // уровень пустой черты = уровень underline
+#let label-gap = 2.8mm      // зазор от черты до подписи
+#let label-lift = 10.5pt    // компенсация верхнего интервала строки подписи
+
+#let field(value, label, width: 100%) = box(width: width)[
+  #grid(
+    columns: 100%,
+    inset: 0pt,
+    align: center + top,
+    rows: (slot-height, auto),
+    // черта со значением (или пустая черта для подписи)
+    [
+      #if value == none [
+        #move(dy: blank-line-dy)[#line(length: 100%, stroke: field-stroke)]
+      ] else [
+        #underline(offset: 2pt, stroke: field-stroke)[#value]
+      ]
+    ],
+    // подпись под чертой
+    [
+      #v(label-gap + slot-height - blank-line-dy - label-lift)
+      #text(size: label-size)[#label]
+    ],
+  )
+]
+
 // ── Шапка ──────────────────────────────────────────────────────────────
-#move(dx: 60pt, dy: shift.header.dy)[
-  #align(center)[
-    #text(size: 14pt)[#task.ministry]
-    #linebreak()
-    #text(size: 12pt)[#task.university_prename]
-    *#task.university_shorten*
-  ]
+#align(center)[
+  #text(size: 14pt)[#task.ministry]
+  #linebreak()
+  #text(size: 12pt)[#task.university_prename]
+  *#task.university_shorten*
 ]
 
 #v(5mm)
 
 // ── Институт ───────────────────────────────────────────────────────────
-#move(dx: shift.institute.dx, dy: shift.institute.dy)[
-  #align(center)[#line_field(task.institute, [институт], width: 135mm)]
-]
+#align(center)[#field(task.institute, [институт], width: 135mm)]
 
 #v(4mm)
 
 // ── Кафедра ────────────────────────────────────────────────────────────
-#move(dx: shift.department.dx, dy: shift.department.dy)[
-  #align(center)[#line_field(task.department, [кафедра], width: 145mm)]
-]
+#align(center)[#field(task.department, [кафедра], width: 145mm)]
 
 #v(25mm)
 
 // ── Тип работы ─────────────────────────────────────────────────────────
-#move(dx: 135pt, dy: shift.work_type.dy)[
-  #align(center)[#text(size: 16pt, weight: "bold")[#task.work_type]]
-]
+#align(center)[#text(size: 16pt, weight: "bold")[#task.work_type]]
 
 #v(8mm)
 
-// ── Тема («по» слева; тема центрирована по оси заголовка выше) ─────────
-#move(dx: shift.topic.dx, dy: shift.topic.dy)[
+// ── Тема: «по» слева от подчёркнутого текста ───────────────────────────
+#align(center)[
   #grid(
-    columns: (1fr, 145mm, 1fr),
-    column-gutter: 0pt,
-    align: (right + top, center, left),
-    [],
-    line_field(task.topic, [тема], width: 145mm),
-    [],
+    columns: 100%,
+    inset: 0pt,
+    align: center + top,
+    [
+      по #underline(offset: 2pt, stroke: field-stroke)[#task.topic]
+    ],
+    [
+      #v(label-gap + 2pt)
+      #text(size: label-size)[тема]
+    ],
   )
 ]
 
 #v(35mm)
 
 // ── Подписи ────────────────────────────────────────────────────────────
-// Одна таблица с общими колонками (как title_signature_block в
-// diploma-typst): черты для подписи и ФИО строго друг под другом.
-#move(dx: shift.signatures.dx, dy: shift.signatures.dy)[
-  #table(
-    columns: (34mm, 49mm, 8mm, 27mm, 11mm, 41mm),
-    stroke: none,
-    inset: (x: 0pt, y: 2.2mm),
-    align: (left, center, center, center, center, center),
-
-    // Преподаватель | (пусто) | подпись | (пусто) | ФИО
-    table.cell(colspan: 2)[Преподаватель],
-    [],
-    blank_signature(width: 27mm),
-    [],
-    signature_name_field(task.teacher, width: 41mm),
-
-    // Студент | номер группы | подпись | (пусто) | ФИО
-    [Студент],
-    signature_field(task.group, [номер группы, зачетной книжки], width: 49mm),
-    [],
-    blank_signature(width: 27mm),
-    [],
-    signature_name_field(task.student_short_name, width: 41mm),
-  )
-]
+// Колонки: роль | группа | зазор | подпись | зазор | ФИО.
+// Черты для подписи и подчёркнутые значения в одной строке таблицы
+// находятся на одном уровне благодаря общей геометрии field().
+#table(
+  columns: (34mm, 49mm, 8mm, 27mm, 11mm, 41mm),
+  stroke: none,
+  inset: (x: 0pt, y: 2.2mm),
+  align: (left, center, center, center, center, center),
+
+  table.cell(colspan: 2)[Преподаватель],
+  [],
+  field(none, [подпись, дата], width: 27mm),
+  [],
+  field(task.teacher, [инициалы, фамилия]),
+
+  [Студент],
+  field(task.group, [номер группы, зачетной книжки]),
+  [],
+  field(none, [подпись, дата], width: 27mm),
+  [],
+  field(task.student_short_name, [инициалы, фамилия]),
+)
 
-// ── Город, год — центр физического листа, у нижнего поля ───────────────
-#context {
-  // сдвиг к центру физического листа (поля 30/10 мм) + ручная подстройка
-  let dx = (page.margin.right - page.margin.left) / 2 + shift.city.dx
-  place(bottom + center, dx: dx, dy: shift.city.dy)[#task.city #task.year]
-}
+// ── Город, год — по центру листа, у нижнего поля ───────────────────────
+#place(bottom + center)[#task.city #task.year]