Initial commit
This commit is contained in:
commit
c534d5ce80
163 files changed
+11500
No files matched your search
@@ -0,0 +1,409 @@
|
||||
// ==========================================
|
||||
// PRESENTATION: ПЕРЕИСПОЛЬЗУЕМЫЕ КОМПОНЕНТЫ
|
||||
// ==========================================
|
||||
#import "../components.typ": corp_table, formula
|
||||
#import "foundation.typ": render-media-slot
|
||||
#import "../shared/numbering.typ": attachment_numbering
|
||||
|
||||
#let letter-accent = rgb("fbb20d")
|
||||
|
||||
// Большая информационная плашка для замечаний, пояснений и важных оговорок.
|
||||
#let info-block(
|
||||
body,
|
||||
title: [ИНФОРМАЦИЯ],
|
||||
fill: rgb("fbebec"),
|
||||
accent: rgb("d73a49"),
|
||||
text-fill: rgb("#402023"),
|
||||
radius: 8pt,
|
||||
inset: 8pt,
|
||||
) = block(
|
||||
width: 100%,
|
||||
breakable: true,
|
||||
fill: fill,
|
||||
stroke: (left: 3pt + accent),
|
||||
radius: radius,
|
||||
inset: inset,
|
||||
)[
|
||||
#set par(first-line-indent: 0pt, justify: false)
|
||||
#if title != none {
|
||||
block(below: 0.35em)[
|
||||
#text(fill: accent, weight: "bold", size: 9pt)[#title]
|
||||
]
|
||||
}
|
||||
#text(fill: text-fill, size: 9pt)[#body]
|
||||
]
|
||||
|
||||
#let footer-icon(name, color) = {
|
||||
box(width: 20pt, height: 20pt, fill: color, radius: 2pt)[
|
||||
#align(center + horizon)[
|
||||
#image(
|
||||
path("../assets/icons/" + name + ".png"),
|
||||
width: 15pt,
|
||||
height: 15pt,
|
||||
fit: "contain",
|
||||
)
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
#let company-logo(company, width: 4cm, height: 2.5cm, policy: "placeholder") = {
|
||||
render-media-slot(
|
||||
company.resources.logo,
|
||||
policy: policy,
|
||||
width: width,
|
||||
height: height,
|
||||
label: "ЛОГОТИП",
|
||||
)
|
||||
}
|
||||
|
||||
#let signing-media(stamp, signature, policy, show_stamp: true, offset: -1cm) = {
|
||||
let has-missing-media = signature == none or (show_stamp and stamp == none)
|
||||
let stamp-resource = if stamp == none and policy == "placeholder" {
|
||||
path("../assets/placeholders/stamp.svg")
|
||||
} else {
|
||||
stamp
|
||||
}
|
||||
let signature-resource = if signature == none and policy == "placeholder" {
|
||||
path("../assets/placeholders/signature.svg")
|
||||
} else {
|
||||
signature
|
||||
}
|
||||
if policy == "placeholder" and has-missing-media {
|
||||
if show_stamp {
|
||||
place(center, dx: -1.6cm, dy: offset)[
|
||||
#render-media-slot(
|
||||
stamp-resource,
|
||||
policy: policy,
|
||||
width: 2.8cm,
|
||||
height: 2.8cm,
|
||||
label: "ПЕЧАТЬ",
|
||||
)
|
||||
]
|
||||
}
|
||||
place(center, dx: if show_stamp { 1.6cm } else { 0cm }, dy: offset)[
|
||||
#render-media-slot(
|
||||
signature-resource,
|
||||
policy: policy,
|
||||
width: 2.8cm,
|
||||
height: 1.4cm,
|
||||
label: "ПОДПИСЬ",
|
||||
)
|
||||
]
|
||||
} else {
|
||||
if show_stamp {
|
||||
place(center, dx: -0.5cm, dy: offset)[
|
||||
#render-media-slot(
|
||||
stamp-resource,
|
||||
policy: policy,
|
||||
width: 3.5cm,
|
||||
height: 3.5cm,
|
||||
label: "МЕСТО ПЕЧАТИ",
|
||||
)
|
||||
]
|
||||
}
|
||||
place(center, dx: if show_stamp { 1.5cm } else { 0cm }, dy: offset)[
|
||||
#render-media-slot(
|
||||
signature-resource,
|
||||
policy: policy,
|
||||
width: 3.5cm,
|
||||
height: 2.5cm,
|
||||
label: "МЕСТО ПОДПИСИ",
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#let signature-block(
|
||||
signer,
|
||||
company: none,
|
||||
media_policy: "placeholder",
|
||||
show_stamp: true,
|
||||
note: none,
|
||||
) = {
|
||||
let signature = signer.at(
|
||||
"signature",
|
||||
default: if company == none { none } else { company.resources.signature },
|
||||
)
|
||||
let stamp = signer.at(
|
||||
"stamp",
|
||||
default: if company == none { none } else { company.resources.stamp },
|
||||
)
|
||||
|
||||
set par(first-line-indent: 0pt, justify: false, leading: 0.75em)
|
||||
let left-content = [
|
||||
#signer.title
|
||||
#if company != none { [\ #company.legal.name] }
|
||||
]
|
||||
let right-content = [#signer.name]
|
||||
let media-content = signing-media(
|
||||
stamp,
|
||||
signature,
|
||||
media_policy,
|
||||
show_stamp: show_stamp,
|
||||
)
|
||||
v(2cm)
|
||||
layout(size => {
|
||||
let left-width = measure(left-content).width
|
||||
let right-width = measure(right-content).width
|
||||
let roomy = left-width + right-width + 5.5cm <= size.width
|
||||
if roomy {
|
||||
grid(
|
||||
columns: (auto, 1fr, auto),
|
||||
align: (left + bottom, center + bottom, right + bottom),
|
||||
left-content,
|
||||
media-content,
|
||||
right-content,
|
||||
)
|
||||
} else {
|
||||
grid(
|
||||
columns: (1fr, 6.5cm, 1fr),
|
||||
column-gutter: 8pt,
|
||||
align: (left + bottom, center + bottom, right + bottom),
|
||||
left-content,
|
||||
media-content,
|
||||
right-content,
|
||||
)
|
||||
}
|
||||
})
|
||||
if note != none {
|
||||
text(font: "Arial", size: 7.5pt, fill: luma(90))[#note]
|
||||
}
|
||||
}
|
||||
|
||||
#let approval-block(approval, company, media_policy: "placeholder") = {
|
||||
let signer = approval.signer
|
||||
let signature = signer.at("signature", default: company.resources.signature)
|
||||
let signature-resource = if signature == none and media_policy == "placeholder" {
|
||||
path("../assets/placeholders/signature.svg")
|
||||
} else {
|
||||
signature
|
||||
}
|
||||
set par(first-line-indent: 0pt, justify: false, leading: 0.75em)
|
||||
box(width: 8cm)[
|
||||
#align(right)[
|
||||
#text(weight: "bold")[#approval.label] \
|
||||
#signer.title \
|
||||
#company.legal.name \
|
||||
#v(0.2cm)
|
||||
#render-media-slot(
|
||||
signature-resource,
|
||||
policy: media_policy,
|
||||
width: 3cm,
|
||||
height: 1.2cm,
|
||||
label: "ПОДПИСЬ",
|
||||
) \
|
||||
#signer.name \
|
||||
#if approval.date != none { approval.date }
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
#let company-footer(company) = {
|
||||
let contacts = company.contacts
|
||||
let banking = company.banking
|
||||
let contact-lines = ()
|
||||
if contacts.phone != none { contact-lines.push(contacts.phone) }
|
||||
if contacts.email != none { contact-lines.push(contacts.email) }
|
||||
if contacts.website != none { contact-lines.push(contacts.website) }
|
||||
let id-lines = ()
|
||||
for (key, label) in (
|
||||
("inn", "ИНН"),
|
||||
("kpp", "КПП"),
|
||||
("ogrn", "ОГРН"),
|
||||
("bin", "БИН"),
|
||||
("kbe", "КБЕ"),
|
||||
) {
|
||||
let value = company.legal.at(key, default: none)
|
||||
if value != none { id-lines.push([#label #value]) }
|
||||
}
|
||||
let banking-lines = ()
|
||||
if banking.bank != none { banking-lines.push([Банк: #banking.bank]) }
|
||||
if banking.at("correspondent-account", default: none) != none {
|
||||
banking-lines.push([Кор. счёт: #banking.at("correspondent-account")])
|
||||
}
|
||||
if banking.bik != none { banking-lines.push([БИК: #banking.bik]) }
|
||||
if contacts.at("address-en", default: none) != none {
|
||||
banking-lines.push(contacts.at("address-en"))
|
||||
}
|
||||
set text(font: "Arial", size: 7.5pt, fill: luma(85))
|
||||
set par(first-line-indent: 0pt, justify: false, leading: 0.2em)
|
||||
grid(
|
||||
columns: (1fr, 1.2fr),
|
||||
column-gutter: 15pt,
|
||||
[
|
||||
#grid(
|
||||
columns: (20pt, 1fr),
|
||||
rows: (auto, auto),
|
||||
column-gutter: 8pt,
|
||||
row-gutter: 8pt,
|
||||
if contact-lines.len() == 0 { none } else { footer-icon("email", company.brand.color) },
|
||||
contact-lines.join([\ ]),
|
||||
if contacts.address == none { none } else { footer-icon("location", company.brand.color) },
|
||||
if contacts.address == none { none } else { contacts.address },
|
||||
)
|
||||
],
|
||||
grid(
|
||||
columns: (1fr, 20pt),
|
||||
rows: (auto, auto),
|
||||
column-gutter: 8pt,
|
||||
row-gutter: 8pt,
|
||||
align: (right, center + horizon),
|
||||
align(right, id-lines.join([\ ])),
|
||||
if id-lines.len() == 0 { none } else { footer-icon("card", company.brand.color) },
|
||||
align(right, banking-lines.join([\ ])),
|
||||
if banking-lines.len() == 0 { none } else { footer-icon("bank", company.brand.color) },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#let letter-header(
|
||||
company,
|
||||
recipient,
|
||||
date: none,
|
||||
reference: none,
|
||||
title: none,
|
||||
media_policy: "placeholder",
|
||||
) = {
|
||||
set par(first-line-indent: 0pt, justify: false, leading: 0.65em)
|
||||
place(top + left, dx: 10cm, dy: -1.5cm)[
|
||||
#rect(
|
||||
width: 6.5cm,
|
||||
height: 2cm,
|
||||
fill: letter-accent,
|
||||
radius: (bottom: 2pt),
|
||||
)
|
||||
]
|
||||
v(30pt)
|
||||
box(width: 4cm, height: 2.5cm)[
|
||||
#company-logo(company, width: 4cm, height: 2.5cm, policy: media_policy)
|
||||
]
|
||||
v(-50pt)
|
||||
v(2.5cm)
|
||||
grid(
|
||||
columns: (1.4fr, 1fr),
|
||||
[
|
||||
#if reference != none { [Исх. № #reference] }
|
||||
#if date != none { [ от #date] }
|
||||
],
|
||||
[
|
||||
#if recipient.company != none { [#recipient.company\ ] }
|
||||
#if recipient.title != none { [#recipient.title\ ] }
|
||||
#if recipient.name != none { recipient.name }
|
||||
#if recipient.address != none { [\ #recipient.address] }
|
||||
],
|
||||
)
|
||||
v(0.7cm)
|
||||
if title != none {
|
||||
align(center)[#text(weight: "bold")[#upper(title)]]
|
||||
v(0.2cm)
|
||||
}
|
||||
}
|
||||
|
||||
#let attachment-list(attachments) = {
|
||||
let items = if type(attachments) == dictionary { attachments.items } else { attachments }
|
||||
if items.len() > 0 {
|
||||
set par(first-line-indent: 0pt, justify: false)
|
||||
for (index, item) in items.enumerate() {
|
||||
let number = if item.number == auto { index + 1 } else { item.number }
|
||||
[Приложение #number: #item.title]
|
||||
if index < items.len() - 1 { linebreak() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#let requisites-table(parties) = {
|
||||
let field-labels = (
|
||||
inn: "ИНН",
|
||||
kpp: "КПП",
|
||||
ogrn: "ОГРН",
|
||||
bin: "БИН",
|
||||
kbe: "КБе",
|
||||
address: "Юридический адрес",
|
||||
legal-address: "Юридический адрес",
|
||||
phone: "Телефон",
|
||||
email: "E-mail",
|
||||
website: "Сайт",
|
||||
bank: "Банк",
|
||||
account: "Расчётный счёт",
|
||||
settlement-account: "Расчётный счёт",
|
||||
correspondent-account: "Корреспондентский счёт",
|
||||
ks: "Корреспондентский счёт",
|
||||
bik: "БИК",
|
||||
iban: "IBAN",
|
||||
)
|
||||
let hidden-fields = (
|
||||
"name",
|
||||
"short-name",
|
||||
"jurisdiction",
|
||||
"summary",
|
||||
"address-en",
|
||||
"city",
|
||||
)
|
||||
let render-fields(fields) = {
|
||||
for (key, value) in fields {
|
||||
if value != none and key not in hidden-fields {
|
||||
let label = field-labels.at(key, default: key)
|
||||
[#label: #value\ ]
|
||||
}
|
||||
}
|
||||
}
|
||||
let columns = range(parties.len()).map(_ => 1fr)
|
||||
table(
|
||||
columns: columns,
|
||||
stroke: 0.5pt,
|
||||
inset: 6pt,
|
||||
..parties.map(item => [
|
||||
#set par(first-line-indent: 0pt, justify: false, leading: 0.75em)
|
||||
#text(weight: "bold")[#item.role] \
|
||||
#item.name \
|
||||
#render-fields(item.legal)
|
||||
#render-fields(item.contacts)
|
||||
#render-fields(item.banking)
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
#let multi-party-signing(parties, media_policy: "reserve-space") = {
|
||||
let columns = range(parties.len()).map(_ => 1fr)
|
||||
grid(
|
||||
columns: columns,
|
||||
column-gutter: 16pt,
|
||||
..parties.map(item => {
|
||||
let person = item.representative
|
||||
[
|
||||
#set par(first-line-indent: 0pt, justify: false, leading: 0.75em)
|
||||
#if person != none {
|
||||
grid(
|
||||
columns: (1fr,),
|
||||
rows: (auto, 0.35cm, 3.5cm, 0.25cm, auto),
|
||||
[#text(weight: "bold")[#item.role] \ #person.title],
|
||||
[],
|
||||
block(width: 100%, height: 3.5cm)[
|
||||
#signing-media(
|
||||
person.stamp,
|
||||
person.signature,
|
||||
media_policy,
|
||||
show_stamp: true,
|
||||
offset: 0cm,
|
||||
)
|
||||
],
|
||||
[],
|
||||
[#person.name],
|
||||
)
|
||||
} else {
|
||||
text(weight: "bold")[#item.role]
|
||||
}
|
||||
]
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#let appendix-heading(item, display-number) = {
|
||||
set par(first-line-indent: 0pt, justify: false, leading: 0.75em)
|
||||
align(right)[Приложение #display-number]
|
||||
v(0.2cm)
|
||||
align(center)[
|
||||
#text(weight: "bold")[#upper(item.title)]
|
||||
#if item.subtitle != none { [\ #text(weight: "bold")[#item.subtitle]] }
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user