Improve content formatting

This commit is contained in:
2026-05-05 22:14:54 +02:00
parent 5c0f6c30e0
commit 9ecbfeb99d
10 changed files with 126 additions and 155 deletions
+1 -4
View File
@@ -1,5 +1,2 @@
#set heading(numbering: "1.1")
= Wstęp <wstep> = Wstęp <wstep>
== Cel i zakres pracy <cel> Tu będzie dopiero treść :)
== Struktura pracy <struktura>
+1 -1
View File
@@ -40,4 +40,4 @@ W przypadku oparcia aplikacji komunikujacej się peer to peer z innymi urządzen
== Istniejące rozwiązania i ich problemy == Istniejące rozwiązania i ich problemy
Dwoma najpopularniejszymi aplikacjami do współtworzenia notatek w czasie rzeczywistym Google Docs i Microsoft Word Online. Ich zakres funkcjonalności jest bardzo podobny - złożone formatowanie tekstu; możliwość dodawania załączników, tabel; historia wersji dokumentu; obecność publicznego API; wykorzystanie nowoczesnych standardów szyfrowania komunikacji; eksport dokumentu w postaci innego rodzaju pliku oraz wymagają konta do możliwości ich użycia. Google Docs korzysta ze swojego algorytmu Operational Transformation do synchronizacji zmian między użytkownikami, sposób przechowywania dokumentów nie jest jasny, nie wiemy w jakiej postaci są one przechowywane na serwerach Google, a dostęp do aplikacji jest darmowy. Microsoft Word Online nie udostępnia publicznie informacji o stosowanym podejściu do synchronizacji danych, dokumenty przechowywane w postaci plików docx, a dostęp do aplikacji jest również darmowy. Dwoma najpopularniejszymi aplikacjami do współtworzenia notatek w czasie rzeczywistym Google Docs i Microsoft Word Online. Ich zakres funkcjonalności jest bardzo podobny - złożone formatowanie tekstu; możliwość dodawania załączników, tabel; historia wersji dokumentu; obecność publicznego API; wykorzystanie nowoczesnych standardów szyfrowania komunikacji; eksport dokumentu w postaci innego rodzaju pliku oraz wymagają konta do możliwości ich użycia. Google Docs korzysta ze swojego algorytmu Operational Transformation do synchronizacji zmian między użytkownikami, sposób przechowywania dokumentów nie jest jasny, nie wiemy w jakiej postaci są one przechowywane na serwerach Google, a dostęp do aplikacji jest darmowy. Microsoft Word Online nie udostępnia publicznie informacji o stosowanym podejściu do synchronizacji danych, dokumenty przechowywane w postaci plików docx, a dostęp do aplikacji jest również darmowy.
Głównym problemem większości dzisiejszych narzędzi do tworzenia dokumentów jest uzależnienie od dostawcy. Każda z wymienionych aplikacji, jak i wiele innych dostępnych na rynku do skorzystania ze swoich usług wymaga założenia konta na platformie dostawcy, a w czasie współpracy wymagany jest ciągły dostęp do Internetu. W momencie gdy pracujemy nad jednym dokumentem z innymi użytkownikami w tym samym pomieszczeniu i nasze urządzenia podłączone do tej samej sieci, opóźnienie w nanoszeniu zmian między użytkownikami zawsze uwzględnia dostęp do scentralizowanych serwerów. W momencie gdy zostaniemy odcięci od dostępu do Internetu, ale nadal będąc w tej samej sieci lokalnej, tracimy możliwość dalszej pracy. Szczególnie widać to w przypadku Google Docs, którego algorytm synchronizujący narzuca obecność serwera wybierającego kolejność nanoszenia zmian w dokumentach. Głównym problemem większości dzisiejszych narzędzi do tworzenia dokumentów jest uzależnienie od dostawcy. Każda z wymienionych aplikacji, jak i wiele innych dostępnych na rynku do skorzystania ze swoich usług wymaga założenia konta na platformie dostawcy, a w czasie współpracy wymagany jest ciągły dostęp do Internetu. W momencie gdy pracujemy nad jednym dokumentem z innymi użytkownikami w tym samym pomieszczeniu i nasze urządzenia podłączone do tej samej sieci, opóźnienie w nanoszeniu zmian między użytkownikami zawsze uwzględnia dostęp do scentralizowanych serwerów. W momencie gdy zostaniemy odcięci od dostępu do Internetu, ale nadal będąc w tej samej sieci lokalnej, tracimy możliwość dalszej pracy. Szczególnie widać to w przypadku Google Docs, którego algorytm synchronizujący narzuca obecność serwera wybierającego kolejność nanoszenia zmian w dokumentach.
+2
View File
@@ -1,3 +1,5 @@
#set heading(numbering: "1.1")
= Wymagania systemowe <wymagania> = Wymagania systemowe <wymagania>
== Wymagania funkcjonalne == Wymagania funkcjonalne
== Wymagania niefunkcjonalne == Wymagania niefunkcjonalne
+2
View File
@@ -1,3 +1,5 @@
#set heading(numbering: "1.1")
= Implementacja <implementacja> = Implementacja <implementacja>
== Projekt architektury systemu <projekt> == Projekt architektury systemu <projekt>
== Model danych == Model danych
+2
View File
@@ -1,3 +1,5 @@
#set heading(numbering: "1.1")
= Testowanie i weryfikacja <testy> = Testowanie i weryfikacja <testy>
== Metodologia testowania == Metodologia testowania
== Scenariusze testowe == Scenariusze testowe
+2 -2
View File
@@ -1,6 +1,6 @@
#set heading(numbering: "1.1")
= Podsumowanie i kierunki rozwoju <podsumowanie> = Podsumowanie i kierunki rozwoju <podsumowanie>
== Osiągnięte cele == Osiągnięte cele
== Ocena spełnienia wymagań == Ocena spełnienia wymagań
== Możliwości dalszej rozbudowy == Możliwości dalszej rozbudowy
=== Szyfrowanie end-to-end
=== Optymalizacja dużych dokumentów
BIN
View File
Binary file not shown.
+1
View File
@@ -11,6 +11,7 @@
#pagebreak() #pagebreak()
#zut-template([ #zut-template([
#include "Chapters/0. Introduction.typ"
#include "Chapters/1. Theoretical Scope.typ" #include "Chapters/1. Theoretical Scope.typ"
#include "Chapters/2. Requirements.typ" #include "Chapters/2. Requirements.typ"
#include "Chapters/3. Implementation.typ" #include "Chapters/3. Implementation.typ"
+62 -144
View File
@@ -3,29 +3,26 @@
// Wydział Informatyki, ZUT w Szczecinie // Wydział Informatyki, ZUT w Szczecinie
// Typst 0.12+ // Typst 0.12+
// ========================================================= // =========================================================
// ╔═══════════════════════════════════════════════════════╗ //
// ║ 1. KOLORY ║
// ╚═══════════════════════════════════════════════════════╝
#let blue-wi = cmyk(60%, 20%, 0%, 0%) // blueWI jasny niebieski WI #let blue-wi = cmyk(60%, 20%, 0%, 0%) // blueWI jasny niebieski WI
#let blue-zut = cmyk(100%, 75%, 0%, 20%) // blueZUT granatowy ZUT #let blue-zut = cmyk(100%, 75%, 0%, 20%) // blueZUT granatowy ZUT
#let gray-zut = cmyk(0%, 0%, 0%, 40%) // grayZUT szary ZUT #let gray-zut = cmyk(0%, 0%, 0%, 40%) // grayZUT szary ZUT
// Pochodne (odpowiedniki blueWI!20, blueZUT!60 itp.) // Pochodne (odpowiedniki blueWI!20, blueZUT!60 itp.)
#let blue-wi-20 = blue-wi.lighten(80%) #let blue-wi-20 = blue-wi.lighten(80%)
#let blue-zut-60 = blue-zut.lighten(40%) #let blue-zut-60 = blue-zut.lighten(40%)
#let gray-zut-10 = gray-zut.lighten(90%) #let gray-zut-10 = gray-zut.lighten(90%)
// Kolory kodu źródłowego // Kolory kodu źródłowego
#let code-green = rgb(0, 154, 0) #let code-green = rgb(0, 154, 0)
#let code-gray = rgb(128, 128, 128) #let code-gray = rgb(128, 128, 128)
#let code-violet = rgb(148, 0, 211) #let code-violet = rgb(148, 0, 211)
#let theorem(title: none, body) = block( #let theorem(title: none, body) = block(
width: 100%, width: 100%,
fill: luma(97%), fill: luma(97%),
stroke: (top: 1.2pt + blue-zut, bottom: 1.2pt + blue-zut, stroke: (top: 1.2pt + blue-zut, bottom: 1.2pt + blue-zut, left: 1.2pt + blue-zut, right: 1.2pt + blue-zut),
left: 1.2pt + blue-zut, right: 1.2pt + blue-zut),
inset: 8pt, inset: 8pt,
above: 8pt, above: 8pt,
below: 8pt, below: 8pt,
@@ -63,7 +60,6 @@
#body #h(1fr) $blacksquare$ #body #h(1fr) $blacksquare$
] ]
// ╔═══════════════════════════════════════════════════════╗ // ╔═══════════════════════════════════════════════════════╗
// ║ 3. GŁÓWNA FUNKCJA SZABLONU ║ // ║ 3. GŁÓWNA FUNKCJA SZABLONU ║
// ╚═══════════════════════════════════════════════════════╝ // ╚═══════════════════════════════════════════════════════╝
@@ -77,36 +73,30 @@
shorttitle: "", shorttitle: "",
body, body,
) = { ) = {
// ── 3.1 STRONA ────────────────────────────────────────── // ── 3.1 STRONA ──────────────────────────────────────────
set page( set page(
paper: "a4", paper: "a4",
margin: ( margin: (
top: 3.2cm, top: 3.2cm,
bottom: 3.5cm, bottom: 3.5cm,
inside: 3.5cm, // 2.5cm tekst + 1cm bindingoffset inside: 3.5cm, // 2.5cm tekst + 1cm bindingoffset (rozwiązuje problem marginesu z lewej z Twojego kodu)
outside: 2.5cm, outside: 2.5cm,
), ),
// ── Nagłówek ───────────────────────────────────────── // ── Nagłówek ─────────────────────────────────────────
// Strony nieparzyste (prawe): tytuł rozdziału + numer strony
// Strony parzyste (lewe): numer strony + shorttitle
// Strony otwierające rozdział: nagłówek ukryty (styl "plain")
header: context { header: context {
let pg = counter(page).get().first() let pg = counter(page).get().first()
let is-odd = calc.odd(pg) let is-odd = calc.odd(pg)
// Czy ta strona otwiera rozdział? (→ plain style: brak nagłówka) // Czy ta strona otwiera rozdział? (→ plain style: brak nagłówka)
let chapter-locs = query(heading.where(level: 1)) let chapter-locs = query(heading.where(level: 1))
let is-chapter-page = chapter-locs.any(h => let is-chapter-page = chapter-locs.any(h => counter(page).at(h.location()).first() == pg)
counter(page).at(h.location()).first() == pg
)
if not is-chapter-page { if not is-chapter-page {
// Tytuł bieżącego rozdziału do nagłówka // Tytuł bieżącego rozdziału do nagłówka
let prev = query(heading.where(level: 1).before(here())) let prev = query(heading.where(level: 1).before(here()))
let ch-label = if prev.len() > 0 { let ch-label = if prev.len() > 0 {
let h = prev.last() let h = prev.last()
let num = counter(heading).at(h.location()) let num = counter(heading).at(h.location())
[#num.first().#h.body] [#num.first().#h.body]
} else { [] } } else { [] }
@@ -119,12 +109,12 @@
columns: (1fr, auto), columns: (1fr, auto),
align: horizon, align: horizon,
box( box(
fill: blue-wi-20, fill: blue-wi-20,
width: 100%, width: 100%,
inset: (x: 7pt, y: 4pt), inset: (x: 7pt, y: 4pt),
)[#ch-label], )[#ch-label],
box( box(
fill: blue-zut, fill: blue-zut,
inset: (x: 7pt, y: 4pt), inset: (x: 7pt, y: 4pt),
)[#text(fill: white, weight: "bold")[#pg]], )[#text(fill: white, weight: "bold")[#pg]],
) )
@@ -134,11 +124,11 @@
columns: (auto, 1fr), columns: (auto, 1fr),
align: horizon, align: horizon,
box( box(
fill: blue-zut, fill: blue-zut,
inset: (x: 7pt, y: 4pt), inset: (x: 7pt, y: 4pt),
)[#text(fill: white, weight: "bold")[#pg]], )[#text(fill: white, weight: "bold")[#pg]],
box( box(
fill: blue-wi-20, fill: blue-wi-20,
width: 100%, width: 100%,
inset: (x: 7pt, y: 4pt), inset: (x: 7pt, y: 4pt),
)[#shorttitle], )[#shorttitle],
@@ -148,20 +138,15 @@
}, // /header }, // /header
// ── Stopka ─────────────────────────────────────────── // ── Stopka ───────────────────────────────────────────
// Widoczna tylko na stronach otwierających rozdział (plain style).
footer: context { footer: context {
let pg = counter(page).get().first() let pg = counter(page).get().first()
let chapter-locs = query(heading.where(level: 1)) let chapter-locs = query(heading.where(level: 1))
let is-chapter-page = chapter-locs.any(h => let is-chapter-page = chapter-locs.any(h => counter(page).at(h.location()).first() == pg)
counter(page).at(h.location()).first() == pg
)
if is-chapter-page { if is-chapter-page {
set text(font: "Fira Sans", size: 10pt) set text(font: "Fira Sans", size: 10pt)
align(right, align(right, box(fill: blue-zut, inset: (x: 7pt, y: 4pt))[
box(fill: blue-zut, inset: (x: 7pt, y: 4pt))[ #text(fill: white, weight: "bold")[#pg]
#text(fill: white, weight: "bold")[#pg] ])
]
)
} }
}, },
@@ -170,129 +155,77 @@
// ── 3.2 TEKST ─────────────────────────────────────────── // ── 3.2 TEKST ───────────────────────────────────────────
set text(font: "Fira Sans", size: 12pt, lang: "pl") set text(font: "New Computer Modern", size: 12pt, lang: "pl")
set par(justify: true, leading: 0.65em) set par(justify: true, leading: 0.65em)
// ── 3.3 LISTY ─────────────────────────────────────────── // ── 3.3 LISTY ───────────────────────────────────────────
// \setlist{nolistsep} → spacing: 0.4em
// \setlist[itemize]{label=--}
set list(marker: [--], spacing: 0.4em, indent: 1em) set list(marker: [--], spacing: 0.4em, indent: 1em)
set enum(spacing: 0.4em, indent: 1em) set enum(spacing: 0.4em, indent: 1em)
// ── 3.4 NAGŁÓWKI ──────────────────────────────────────── // ── 3.4 NAGŁÓWKI ─────────────
// Rozdział (\chapter) level 1 set heading(numbering: "1.1")
// {\huge\sffamily\color{blueZUT}} + numer wysuniẹty o \hspace{-3ex}
show heading.where(level: 1): it => { show heading: it => {
pagebreak(weak: true) let num = if it.numbering != none {
v(1cm) counter(heading).display(it.numbering)
context { }
set text(size: 24pt, weight: "bold", font: "Fira Sans", fill: blue-zut)
if it.numbering != none { if it.level == 1 {
block(below: 0.6em)[ // Wymuszenie nowej strony dla głównego rozdziału
// Numer wysuniẹty w lewo (odpowiednik \hspace{-3ex}) pagebreak(weak: true)
#box(width: 0pt)[ v(1.5em, weak: true)
#place(dx: -2em)[#counter(heading).display().]
block(width: 100%, inset: (bottom: 1em, top: 7em))[
#if num != none {
place(left + top, dx: -1.5cm, dy: 0.1em)[
#text(size: 26pt, fill: blue-zut, weight: "bold", font: "Fira Sans", num)
] ]
#h(1.2em) }
#it.body #align(left)[
#text(size: 26pt, fill: blue-zut, weight: "bold", font: "Fira Sans", it.body)
] ]
} else { ]
block(below: 0.6em)[#it.body] } else {
} let txt-size = if it.level == 2 { 14pt } else if it.level == 3 { 12pt } else { 11pt }
} let spacing-top = if it.level == 2 { 1.5em } else if it.level == 3 { 1.2em } else { 1em }
} let spacing-bottom = if it.level == 2 { 0.5em } else { 0.4em }
// Sekcja (\section) level 2, wiszący numer w marginesie v(spacing-top, weak: true)
// \large\sffamily\bfseries + \llap{\color{blueZUT}{numer}\hspace{1em}}
show heading.where(level: 2): it => { block(width: 100%, inset: (bottom: spacing-bottom))[
v(1.5em, weak: true) #if num != none {
context { let dy-val = if it.level == 2 { 0.0em } else { 0.05em }
block(below: 0.5em, above: 0pt)[ place(left + top, dx: -1.5cm, dy: dy-val)[
#set text(size: 13pt, weight: "bold", font: "Fira Sans") #text(size: txt-size, fill: blue-zut, weight: "bold", font: "Fira Sans", num)
#if it.numbering != none {
// Numer wysuniẹty w lewo (llap)
box(width: 0pt)[
#place(dx: -3em)[
#text(fill: blue-zut)[#counter(heading).display()]
]
] ]
} }
#it.body // Tytuł na czarno, dopasowany do tekstu
#text(size: txt-size, fill: black, weight: "bold", font: "Fira Sans", it.body)
] ]
} }
v(0.4em, weak: true)
}
// Podsekcja (\subsection) level 3
show heading.where(level: 3): it => {
v(1.2em, weak: true)
context {
block(below: 0.4em, above: 0pt)[
#set text(size: 12pt, weight: "bold", font: "Fira Sans")
#if it.numbering != none {
box(width: 0pt)[
#place(dx: -3em)[
#text(fill: blue-zut)[#counter(heading).display()]
]
]
}
#it.body
]
}
v(0.3em, weak: true)
}
// Podpodsekcja (\subsubsection) level 4
show heading.where(level: 4): it => {
v(1em, weak: true)
context {
block(below: 0.3em, above: 0pt)[
#set text(size: 11pt, weight: "bold", font: "Fira Sans")
#if it.numbering != none {
box(width: 0pt)[
#place(dx: -3em)[
#text(fill: blue-zut)[#counter(heading).display()]
]
]
}
#it.body
]
}
}
// Paragraf (\paragraph) level 5, inline
show heading.where(level: 5): it => {
v(0.8em, weak: true)
text(size: 11pt, weight: "bold", font: "Fira Sans")[#it.body]
v(0.15em, weak: true)
} }
// ── 3.5 SPIS TREŚCI ───────────────────────────────────── // ── 3.5 SPIS TREŚCI ─────────────────────────────────────
// \titlecontents numery, wcięcia, kolory, linie kropkowane
set outline(indent: auto) set outline(indent: auto)
show outline.entry: it => { show outline.entry: it => {
if it.level == 1 { if it.level == 1 {
// Rozdział: +12pt przerwy, \large, blueZUT, pogrubiony
v(12pt, weak: true) v(12pt, weak: true)
text(size: 11pt, weight: "bold", font: "Fira Sans", fill: blue-zut)[ text(size: 11pt, weight: "bold", font: "Fira Sans", fill: blue-zut)[
#h(1.25cm) #h(1.25cm)
#it #it
] ]
} else if it.level == 2 { } else if it.level == 2 {
// Sekcja: wcięcie 1.25cm, normalny
v(3pt, weak: true) v(3pt, weak: true)
text(size: 10pt, font: "Fira Sans")[ text(size: 10pt, font: "Fira Sans")[
#h(1.25cm) #h(1.25cm)
#it #it
] ]
} else if it.level == 3 { } else if it.level == 3 {
// Podsekcja: wcięcie 2.5cm, small
v(1pt, weak: true) v(1pt, weak: true)
text(size: 9pt, font: "Fira Sans")[ text(size: 9pt, font: "Fira Sans")[
#h(2.5cm) #h(2.5cm)
@@ -305,12 +238,6 @@
// ── 3.6 BLOKI KODU ────────────────────────────────────── // ── 3.6 BLOKI KODU ──────────────────────────────────────
// Odpowiednik lstdefinestyle{mystyle}:
// • małe litery, font monospace
// • lewa kreska w kolorze blueWI
// • wcięcia x: 5ex
// • numery linii (Typst 0.12+: set raw(numbering: "1"))
show raw.where(block: true): it => { show raw.where(block: true): it => {
block( block(
width: 100%, width: 100%,
@@ -321,34 +248,29 @@
below: 9pt, below: 9pt,
radius: (right: 2pt), radius: (right: 2pt),
)[ )[
#set text(size: 9.5pt, font: ("Fira Mono", "Courier New", "monospace")) #set text(size: 9.5pt, font: ("Fira Mono", "Courier New"))
#it #it
] ]
} }
// Kod inline dyskretne tło
show raw.where(block: false): it => { show raw.where(block: false): it => {
box( box(
fill: gray-zut.lighten(93%), fill: gray-zut.lighten(93%),
inset: (x: 3pt, y: 1pt), inset: (x: 3pt, y: 1pt),
radius: 2pt, radius: 2pt,
)[ )[
#set text(size: 10pt, font: ("Fira Mono", "Courier New", "monospace")) #set text(size: 10pt, font: ("Fira Mono", "Courier New"))
#it #it
] ]
} }
// ── 3.7 PODPISY RYSUNKÓW I TABEL ──────────────────────── // ── 3.7 PODPISY RYSUNKÓW I TABEL ────────────────────────
// \captionsetup[figure]{name={\small\sffamily\color{blueZUT} Rysunek}}
// \captionsetup[table] {name={\small\sffamily\color{blueZUT} Tabela}}
set figure(gap: 0.8em) set figure(gap: 0.8em)
show figure.caption: it => { show figure.caption: it => {
set text(size: 9.5pt, font: "Fira Sans") set text(size: 9.5pt, font: "Fira Sans")
let kind-label = if it.kind == image { [Rysunek] } let kind-label = if it.kind == image { [Rysunek] } else if it.kind == table { [Tabela] } else { [Algorytm] }
else if it.kind == table { [Tabela] }
else { [Algorytm] }
[ [
#text(fill: blue-zut, weight: "bold")[ #text(fill: blue-zut, weight: "bold")[
#kind-label #it.counter.display() #kind-label #it.counter.display()
@@ -358,17 +280,13 @@
// ── 3.8 TABELE ────────────────────────────────────────── // ── 3.8 TABELE ──────────────────────────────────────────
// \usepackage{booktabs} poziome linie tabel
set table( set table(
stroke: none, stroke: none,
inset: (x: 8pt, y: 5pt), inset: (x: 8pt, y: 5pt),
) )
// Linie nagłówka i dołu tabeli (booktabs-style)
show table.cell.where(y: 0): set text(weight: "bold") show table.cell.where(y: 0): set text(weight: "bold")
show table: set block(above: 8pt, below: 8pt) show table: set block(above: 8pt, below: 8pt)
// ── Treść dokumentu ─────────────────────────────────────
body body
} // /zut-template } // /zut-template
+51 -2
View File
@@ -1,6 +1,55 @@
#import "style.typ": definition, example, theorem, zut-template #import "style.typ": definition, example, theorem, zut-template
#set heading(numbering: "1.") #let color-dark-blue = rgb("#223d73")
#set par(first-line-indent: 0pt) #let color-page-num = rgb("#6b7b96")
#let color-dots = rgb("#a0aabf")
#set heading(numbering: "1.1")
#set text(font: "Fira Sans")
#set outline(title: text(size: 24pt, fill: color-dark-blue, weight: "regular")[Spis treści])
#show outline.entry: it => {
let is-lvl-1 = it.level == 1
let num = it.prefix()
let title = it.body()
let page-num = it.page()
let num-style = if is-lvl-1 {
text(size: 14pt, fill: color-dark-blue, num)
} else {
text(size: 12pt, fill: black, num)
}
let title-style = if is-lvl-1 {
text(size: 14pt, fill: color-dark-blue, title)
} else {
text(size: 12pt, fill: black, title)
}
let page-style = text(size: 10pt, fill: color-page-num, weight: "medium", page-num)
v(if is-lvl-1 { 14pt } else { 6pt }, weak: true)
link(it.element.location())[
#grid(
columns: (3em, 1fr, auto),
align: (left, left, right),
// Kolumna 1: Numery rozdziałów w jednej linii
num-style,
// Kolumna 2: Tytuł oraz kropki
[
#title-style
#box(width: 1fr, inset: (x: 5pt))[
#text(fill: color-dots)[#repeat[ . ]]
]
],
// Kolumna 3: Numer strony
page-style,
)
]
}
#outline() #outline()
#pagebreak()