Skip to content

Commit b2f7005

Browse files
authored
kantan:0.1.0 (#3179)
1 parent 815ca73 commit b2f7005

File tree

10 files changed

+642
-0
lines changed

10 files changed

+642
-0
lines changed

packages/preview/kantan/0.1.0/LICENSE

Lines changed: 235 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# [Kantan][kantan] (Typst package)
2+
3+
[Kantan][kantan] (<ruby>簡単<rt>かんたん</rt></ruby>) is a package to _easily_
4+
create a kanban board (<ruby>看板<rt>かんばん</rt></ruby>) of any scale.
5+
6+
A bonus, is that the source code is so small, you can quickly modify any aspect
7+
of it, to make the board look the way you want. Because of composability, you
8+
can mix package functions with locally edited ones.
9+
10+
## Usage
11+
12+
### [Example 1]
13+
14+
```typ
15+
#import "@preview/kantan:0.1.0": *
16+
// #set page(width: 16cm, height: auto, margin: 2pt)
17+
18+
// Dark theme
19+
#set page(fill: black)
20+
#set text(fill: white)
21+
#let kanban-item = kanban-item.with(fill: black)
22+
23+
#kanban(
24+
font-size: 0.80em,
25+
font: "Liberation Sans",
26+
kanban-column("Backlog", color: red,
27+
kanban-item(stroke: rgb("#FF5733"))[41][high][Authorization and data validation],
28+
kanban-item(stroke: rgb("#33FF57"))[18][high][Cart API integration],
29+
kanban-item(stroke: rgb("#8D33FF"))[18][medium][City dropdown menu],
30+
kanban-item(stroke: rgb("#FF33A1"))[7][medium][Dynamic cart item count],
31+
kanban-item(stroke: rgb("#33C1FF"))[5][medium][Main page prototype],
32+
kanban-item(stroke: rgb("#8D33FF"))[1][low][Tests for cart API],
33+
),
34+
kanban-column("Work in progress", color: yellow,
35+
kanban-item(stroke: rgb("#FF5733"))[7][medium][John][Checkout page],
36+
kanban-item(stroke: rgb("#FF0000"))[18][medium][John][Stock availability check],
37+
kanban-item(stroke: rgb("#33FF57"))[18][medium][Olivia][Add/remove book tests],
38+
kanban-item(stroke: rgb("#33C1FF"))[7][medium][Stephen]["About Us" page layout],
39+
),
40+
kanban-column("Testing", color: aqua,
41+
kanban-item(stroke: rgb("#FF5733"))[18][high][John][Add-to-cart API],
42+
kanban-item(stroke: rgb("#33C1FF"))[5][medium][Emily]["Contact Us" page],
43+
kanban-item(stroke: rgb("#FFC300"))[5][medium][Alex]["News" page mockup],
44+
),
45+
kanban-column("Done", color: green,
46+
kanban-item(stroke: rgb("#FFC300"))[50][high][Michael][Books database],
47+
kanban-item(stroke: rgb("#FF33A1"))[32][high][Stephen][Books catalog with filters],
48+
kanban-item(stroke: rgb("#33FF57"))[1][low][Arthur]["About Us" page mockup],
49+
),
50+
)
51+
```
52+
53+
<picture>
54+
<source
55+
media="(prefers-color-scheme: light)"
56+
srcset="./tests/example-en/ref/1.png">
57+
<img alt="Kanban board in English" src="./tests/example-en/ref/2.png">
58+
</picture>
59+
60+
---
61+
62+
### [Example 2]
63+
64+
```typ
65+
#import "@preview/kantan:0.1.0": *
66+
// #set page(width: 17cm, height: auto, margin: 2pt)
67+
68+
// Dark theme
69+
#set page(fill: black)
70+
#set text(fill: white)
71+
#let kanban-item = kanban-item.with(fill: black)
72+
73+
#kanban(
74+
font-size: 0.80em,
75+
font: "Liberation Sans",
76+
kanban-column("Backlog", color: red,
77+
kanban-item(stroke: rgb("#FF5733"))[41][высокий][Авторизация с проверкой данных],
78+
kanban-item(stroke: rgb("#33FF57"))[18][высокий][Интеграция API корзины],
79+
kanban-item(stroke: rgb("#8D33FF"))[18][средний][Выпадающее меню города],
80+
kanban-item(stroke: rgb("#FF33A1"))[7][средний][Динамическое число товаров в корзине],
81+
kanban-item(stroke: rgb("#33C1FF"))[5][средний][Прототип главной страницы],
82+
kanban-item(stroke: rgb("#33C1FF"))[5][средний][Страница "Контакты"],
83+
kanban-item(stroke: rgb("#FFC300"))[5][средний][Макет страницы "Новости"],
84+
kanban-item(stroke: rgb("#8D33FF"))[1][низкий][Олеся][Тесты для API корзины],
85+
),
86+
kanban-column("Work in progress", color: yellow,
87+
kanban-item(stroke: rgb("#FF5733"))[7][средний][Иван][Оформление заказа],
88+
kanban-item(stroke: rgb("#FF0000"))[18][средний][Иван][Проверка наличия книг на складе],
89+
kanban-item(stroke: rgb("#33FF57"))[18][средний][Олеся][Тесты для добавления/удаления книг],
90+
kanban-item(stroke: rgb("#33C1FF"))[7][средний][Степан][Вёрстка страницы "О~нас"],
91+
),
92+
kanban-column("Testing", color: aqua,
93+
kanban-item(stroke: rgb("#FF5733"))[18][высокий][Иван][API для добавления книг в корзину],
94+
),
95+
kanban-column("Done", color: green,
96+
kanban-item(stroke: rgb("#FFC300"))[50][высокий][Михаил][База данных для книг],
97+
kanban-item(stroke: rgb("#FF33A1"))[32][высокий][Степан][Каталог книг с фильтрацией],
98+
kanban-item(stroke: rgb("#33FF57"))[1][низкий][Артём][Макет страницы "О~нас"],
99+
),
100+
)
101+
```
102+
103+
<picture>
104+
<source
105+
media="(prefers-color-scheme: light)"
106+
srcset="./tests/example-ru/ref/1.png">
107+
<img alt="Kanban board in Russian" src="./tests/example-ru/ref/2.png">
108+
</picture>
109+
110+
## API
111+
112+
### `kanban-item`
113+
114+
```typ
115+
/// Create a single kanban board item that can be placed in `kanban-column`.
116+
///
117+
/// - hardness-level (any): How hard the task is, its cost (usually a number).
118+
/// - priority-level (any): For example, can be "low", "medium", "high".
119+
/// - inset (relative, dictionary): Inset for: hardness, priority, assignee.
120+
/// - stroke (color, gradient, tiling, length, stroke): Stroke for item box.
121+
/// - height (auto, relative): Item height.
122+
/// - args (arguments): 1 positional argument is item name, 2 positional
123+
/// arguments is assignee and item name.
124+
#let kanban-item(
125+
hardness-level,
126+
priority-level,
127+
inset: 0.27em,
128+
stroke: 0.05em,
129+
height: auto,
130+
..args,
131+
)
132+
```
133+
134+
---
135+
136+
### `kanban-column`
137+
138+
```typ
139+
/// Create a single kanban board column that can be placed in `kanban`.
140+
///
141+
/// - name (str, content): Column name.
142+
/// - color (color, gradient, tiling): Column color.
143+
/// - items (arguments): Column items created with `kanban-item`.
144+
#let kanban-column(name, color: auto, ..items)
145+
```
146+
147+
---
148+
149+
### `kanban`
150+
151+
```typ
152+
/// Create a single kanban board item that can be placed in `kanban-column`.
153+
///
154+
/// - width (auto, relative): Kanban board width. Default is `100%`.
155+
/// - item-spacing (relative): Spacing between items in a column.
156+
/// - leading (length): Paragraph leading to use inside the board.
157+
/// - font-size (length): Font size to use inside the board.
158+
/// - font (str, array, dictionary): Font to use inside the board.
159+
/// - args (arguments): Columns created with `kanban-column`.
160+
#let kanban(
161+
width: 100%,
162+
item-spacing: 0.5em,
163+
leading: 0.5em,
164+
font-size: 1em,
165+
font: (),
166+
..args,
167+
)
168+
```
169+
170+
## License
171+
172+
This Typst package is licensed under AGPL-3.0-only license. You can view the
173+
license in the [`LICENSE`] file in the root of the project or at
174+
<https://www.gnu.org/licenses/agpl-3.0.txt>.
175+
176+
[kantan]: https://codeberg.org/Andrew15-5/kantan
177+
[Example 1]: ./tests/example-en/test.typ
178+
[Example 2]: ./tests/example-ru/test.typ
179+
[`LICENSE`]: ./LICENSE
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// SPDX-FileCopyrightText: Copyright (C) 2025 Andrew Voynov
2+
//
3+
// SPDX-License-Identifier: AGPL-3.0-only
4+
5+
/// Create a single kanban board item that can be placed in `kanban-column`.
6+
///
7+
/// - hardness-level (any): How hard the task is, its cost (usually a number).
8+
/// - priority-level (any): For example, can be "low", "medium", "high".
9+
/// - inset (relative, dictionary): Inset for: hardness, priority, assignee.
10+
/// - stroke (color, gradient, tiling, length, stroke): Stroke for item box.
11+
/// - fill (none, color, gradient, tiling): Item background fill color.
12+
/// - height (auto, relative): Item height.
13+
/// - args (arguments): 1 positional argument is item name, 2 positional
14+
/// arguments is assignee and item name.
15+
#let kanban-item(
16+
hardness-level,
17+
priority-level,
18+
inset: 0.27em,
19+
stroke: 0.05em,
20+
fill: white,
21+
height: auto,
22+
..args,
23+
) = {
24+
let assignee
25+
let name
26+
if args.pos().len() == 1 {
27+
name = args.pos().first()
28+
} else {
29+
(assignee, name) = args.pos()
30+
}
31+
let rect(fill: gray.darken(50%), color: white, body) = std.rect(
32+
fill: fill,
33+
inset: inset,
34+
radius: 0.2em,
35+
text(color, body),
36+
)
37+
assignee = if assignee != none { rect.with(assignee) } else { (..a) => none }
38+
let stroke = if type(stroke) == color { std.stroke(stroke + 0.05em) } else {
39+
std.stroke(stroke)
40+
}
41+
let left-stroke = std.stroke(
42+
paint: stroke.paint,
43+
thickness: stroke.thickness + 0.5em,
44+
cap: stroke.cap,
45+
join: stroke.join,
46+
dash: stroke.dash,
47+
miter-limit: stroke.miter-limit,
48+
)
49+
grid.cell(
50+
box(
51+
stroke: (left: left-stroke, rest: stroke),
52+
inset: (left: stroke.thickness / 2),
53+
fill: stroke.paint,
54+
radius: 0.3em,
55+
box(
56+
width: 100%,
57+
height: height,
58+
fill: fill,
59+
stroke: (rest: stroke),
60+
inset: 0.5em,
61+
radius: 0.3em,
62+
align(
63+
horizon,
64+
stack(
65+
spacing: 0.5em,
66+
name,
67+
stack(
68+
dir: ltr,
69+
spacing: 0.5em,
70+
rect(fill: aqua.darken(20%))[#hardness-level],
71+
rect(fill: green.lighten(10%))[#priority-level],
72+
assignee(fill: blue),
73+
),
74+
),
75+
),
76+
),
77+
),
78+
)
79+
}
80+
81+
/// Create a single kanban board column that can be placed in `kanban`.
82+
///
83+
/// - name (str, content): Column name.
84+
/// - color (color, gradient, tiling): Column color.
85+
/// - items (arguments): Column items created with `kanban-item`.
86+
#let kanban-column(name, color: auto, ..items) = {
87+
(name: name, color: color, items: items.pos())
88+
}
89+
90+
/// Create a single kanban board item that can be placed in `kanban-column`.
91+
///
92+
/// - width (auto, relative): Kanban board width. Default is `100%`.
93+
/// - item-spacing (relative): Spacing between items in a column.
94+
/// - leading (length): Paragraph leading to use inside the board.
95+
/// - font-size (length): Font size to use inside the board.
96+
/// - font (str, array, dictionary): Font to use inside the board.
97+
/// - args (arguments): Columns created with `kanban-column`.
98+
#let kanban(
99+
width: 100%,
100+
item-spacing: 0.5em,
101+
leading: 0.5em,
102+
font-size: 1em,
103+
font: (),
104+
..args,
105+
) = {
106+
let columns = args.pos()
107+
let column-names = columns
108+
.enumerate()
109+
.map(((i, x)) => table.cell(
110+
stroke: (bottom: stroke(paint: columns.at(i).color, thickness: 1pt)),
111+
align: left,
112+
inset: (bottom: 0.5em, rest: 0pt),
113+
[#x.name (#columns.at(i).items.len())],
114+
))
115+
let column-items = columns.map(x => x.items)
116+
set text(size: font-size, font: font)
117+
set par(leading: leading)
118+
show table: set par(justify: false)
119+
block(
120+
width: width,
121+
table(
122+
columns: (1fr,) * columns.len(),
123+
align: left + top,
124+
stroke: none,
125+
column-gutter: 1.5em,
126+
inset: 0pt,
127+
row-gutter: item-spacing,
128+
table.header(..column-names),
129+
..column-items
130+
.map(items => grid(row-gutter: item-spacing, ..items))
131+
.flatten(),
132+
),
133+
)
134+
}
75.2 KB
Loading
76.3 KB
Loading
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#import "/lib.typ": *
2+
#set page(width: 16cm, height: auto, margin: 2pt)
3+
4+
#let kanban-board(kanban-item) = kanban(
5+
font-size: 0.80em,
6+
font: "Liberation Sans",
7+
kanban-column("Backlog", color: red,
8+
kanban-item(stroke: rgb("#FF5733"))[41][high][Authorization and data validation],
9+
kanban-item(stroke: rgb("#33FF57"))[18][high][Cart API integration],
10+
kanban-item(stroke: rgb("#8D33FF"))[18][medium][City dropdown menu],
11+
kanban-item(stroke: rgb("#FF33A1"))[7][medium][Dynamic cart item count],
12+
kanban-item(stroke: rgb("#33C1FF"))[5][medium][Main page prototype],
13+
kanban-item(stroke: rgb("#8D33FF"))[1][low][Tests for cart API],
14+
),
15+
kanban-column("Work in progress", color: yellow,
16+
kanban-item(stroke: rgb("#FF5733"))[7][medium][John][Checkout page],
17+
kanban-item(stroke: rgb("#FF0000"))[18][medium][John][Stock availability check],
18+
kanban-item(stroke: rgb("#33FF57"))[18][medium][Olivia][Add/remove book tests],
19+
kanban-item(stroke: rgb("#33C1FF"))[7][medium][Stephen]["About Us" page layout],
20+
),
21+
kanban-column("Testing", color: aqua,
22+
kanban-item(stroke: rgb("#FF5733"))[18][high][John][Add-to-cart API],
23+
kanban-item(stroke: rgb("#33C1FF"))[5][medium][Emily]["Contact Us" page],
24+
kanban-item(stroke: rgb("#FFC300"))[5][medium][Alex]["News" page mockup],
25+
),
26+
kanban-column("Done", color: green,
27+
kanban-item(stroke: rgb("#FFC300"))[50][high][Michael][Books database],
28+
kanban-item(stroke: rgb("#FF33A1"))[32][high][Stephen][Books catalog with filters],
29+
kanban-item(stroke: rgb("#33FF57"))[1][low][Arthur]["About Us" page mockup],
30+
),
31+
)
32+
33+
// Light theme.
34+
#kanban-board(kanban-item)
35+
36+
#set page(fill: black)
37+
#set text(fill: white)
38+
#let kanban-item = kanban-item.with(fill: black)
39+
40+
// Dark theme.
41+
#kanban-board(kanban-item)
91.3 KB
Loading
92.9 KB
Loading
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#import "/lib.typ": *
2+
#set page(width: 17cm, height: auto, margin: 2pt)
3+
4+
#let kanban-board(kanban-item) = kanban(
5+
font-size: 0.80em,
6+
font: "Liberation Sans",
7+
kanban-column("Backlog", color: red,
8+
kanban-item(stroke: rgb("#FF5733"))[41][высокий][Авторизация с проверкой данных],
9+
kanban-item(stroke: rgb("#33FF57"))[18][высокий][Интеграция API корзины],
10+
kanban-item(stroke: rgb("#8D33FF"))[18][средний][Выпадающее меню города],
11+
kanban-item(stroke: rgb("#FF33A1"))[7][средний][Динамическое число товаров в корзине],
12+
kanban-item(stroke: rgb("#33C1FF"))[5][средний][Прототип главной страницы],
13+
kanban-item(stroke: rgb("#33C1FF"))[5][средний][Страница "Контакты"],
14+
kanban-item(stroke: rgb("#FFC300"))[5][средний][Макет страницы "Новости"],
15+
kanban-item(stroke: rgb("#8D33FF"))[1][низкий][Олеся][Тесты для API корзины],
16+
),
17+
kanban-column("Work in progress", color: yellow,
18+
kanban-item(stroke: rgb("#FF5733"))[7][средний][Иван][Оформление заказа],
19+
kanban-item(stroke: rgb("#FF0000"))[18][средний][Иван][Проверка наличия книг на складе],
20+
kanban-item(stroke: rgb("#33FF57"))[18][средний][Олеся][Тесты для добавления/удаления книг],
21+
kanban-item(stroke: rgb("#33C1FF"))[7][средний][Степан][Вёрстка страницы "О~нас"],
22+
),
23+
kanban-column("Testing", color: aqua,
24+
kanban-item(stroke: rgb("#FF5733"))[18][высокий][Иван][API для добавления книг в корзину],
25+
),
26+
kanban-column("Done", color: green,
27+
kanban-item(stroke: rgb("#FFC300"))[50][высокий][Михаил][База данных для книг],
28+
kanban-item(stroke: rgb("#FF33A1"))[32][высокий][Степан][Каталог книг с фильтрацией],
29+
kanban-item(stroke: rgb("#33FF57"))[1][низкий][Артём][Макет страницы "О~нас"],
30+
),
31+
)
32+
33+
// Light theme.
34+
#kanban-board(kanban-item)
35+
36+
#set page(fill: black)
37+
#set text(fill: white)
38+
#let kanban-item = kanban-item.with(fill: black)
39+
40+
// Dark theme.
41+
#kanban-board(kanban-item)

0 commit comments

Comments
 (0)