Skip to content

Commit 80f31d3

Browse files
Otto-AAelegaanz
andauthored
dashy-todo:0.0.2 (#1561)
Co-authored-by: Ana Gelez <[email protected]>
1 parent 30ad611 commit 80f31d3

File tree

8 files changed

+2285
-0
lines changed

8 files changed

+2285
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
MIT No Attribution
2+
3+
Copyright 2024-2025 Otto-AA
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
6+
software and associated documentation files (the "Software"), to deal in the Software
7+
without restriction, including without limitation the rights to use, copy, modify,
8+
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9+
permit persons to whom the Software is furnished to do so.
10+
11+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Dashy TODO
2+
3+
Create simple TODO comments, which are displayed at the sides of the page.
4+
5+
I suggest to take a look at the [drafting package](https://typst.app/universe/package/drafting), which is a more feature-complete annotation library, but also suitable for simple TODO comments.
6+
7+
![Screenshot](example.svg)
8+
9+
## Limitations
10+
11+
Currently, there is no prevention of TODOs being rendered on top of each other. See [here](https://github.com/Otto-AA/dashy-todo/issues/1) for more information.
12+
13+
## Usage
14+
15+
The package provides a `todo(message, position: auto | left | right)` method. Call it anywhere you need a todo message.
16+
17+
```typst
18+
#import "@preview/dashy-todo:0.0.2": todo
19+
20+
// It automatically goes to the closer side (left or right)
21+
A todo on the left #todo[On the left].
22+
23+
// You can specify a side if you want to
24+
#todo(position: right)[Also right]
25+
26+
// You can add arbitrary content
27+
#todo[We need to fix the $lim_(x -> oo)$ equation. See #link("https://example.com")[example.com]]
28+
29+
// And you can create an outline for the TODOs
30+
#outline(title: "TODOs", target: figure.where(kind: "todo"))
31+
```
32+
33+
## Styling
34+
35+
You can modify the text by wrapping it, e.g.:
36+
37+
```
38+
#let small-todo = (..args) => text(size: 0.6em)[#todo(..args)]
39+
40+
#small-todo[This will be in fine print]
41+
```

packages/preview/dashy-todo/0.0.2/example.svg

Lines changed: 2053 additions & 0 deletions
Loading
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#import "lib/todo.typ": todo
2+
3+
#set page(width: 16cm, height: 10cm, margin: (left: 20%, right: 20%), fill: white)
4+
#show link: underline
5+
6+
= Dashy TODOs
7+
8+
TODOs are automatically positioned on the closer#todo[On the right] side to the method call.#todo[On the left] If it doesn't fit, you can manually override it.
9+
10+
You can add custom content.#todo(position: right)[We need to fix the $lim_(x -> oo)$ equation. See #link("https://example.com")[example.com]]
11+
12+
#let small-todo = (..args) => text(size: 0.6em)[#todo(..args)]
13+
14+
We can also control the text #small-todo[This will be in fine print]size if we wrap it in a `text` call.
15+
16+
And finally, you can create a table of all your TODOs:
17+
18+
#outline(title: "TODOs", target: figure.where(kind: "todo"))
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#import "side-margin.typ": calc-side-margin
2+
3+
#let place-in-page-margin(body, cur-pos: none, position: auto) = (
4+
box({
5+
let side = position
6+
if position == auto {
7+
if cur-pos.x > page.width / 2 {
8+
side = right
9+
} else {
10+
side = left
11+
}
12+
}
13+
14+
// caclulation based on https://typst.app/docs/reference/layout/page/#parameters-margin
15+
let page-side-margin = calc-side-margin(side)
16+
17+
let target-x = if side == left { 0pt } else { page.width - page-side-margin }
18+
let delta-x = target-x - cur-pos.x
19+
20+
place(dx: delta-x)[
21+
#box(body, width: page-side-margin)
22+
]
23+
})
24+
)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#let rel-to-abs = (rel, size) => rel.length + rel.ratio * size
2+
3+
// must run within a context
4+
#let calc-side-margin(side) = {
5+
// https://typst.app/docs/reference/layout/page/#parameters-margin
6+
let auto-margin = calc.min(page.width, page.height) * 2.5 / 21
7+
8+
if page.margin == auto {
9+
auto-margin
10+
} else if type(page.margin) == relative {
11+
rel-to-abs(page.margin, page.width)
12+
} else {
13+
if side == left and page.margin.left == auto or side == right and page.margin.right == auto {
14+
auto-margin
15+
} else {
16+
if side == left {
17+
rel-to-abs(page.margin.left, page.width)
18+
} else {
19+
rel-to-abs(page.margin.right, page.width)
20+
}
21+
}
22+
}
23+
}
24+
25+
// must run within a context
26+
#let calculate-page-margin-box(side) = {
27+
assert(side in (left, right))
28+
29+
let margin = calc-side-margin(side)
30+
31+
if side == left {
32+
(
33+
"x": 0pt,
34+
"y": 0pt,
35+
"width": margin,
36+
"height": page.height,
37+
)
38+
} else {
39+
(
40+
"x": page.width - margin,
41+
"y": 0pt,
42+
"width": margin,
43+
"height": page.height,
44+
)
45+
}
46+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#import "side-margin.typ": calculate-page-margin-box
2+
3+
#let to-string(content) = {
4+
if type(content) == str {
5+
content
6+
} else if content.has("text") {
7+
content.text
8+
} else if content.has("children") {
9+
content.children.map(to-string).join("")
10+
} else if content.has("body") {
11+
to-string(content.body)
12+
} else if content == [ ] {
13+
" "
14+
}
15+
}
16+
17+
#let todo(body, position: auto) = (
18+
context box({
19+
assert(position in (auto, left, right), message: "Can only position todo on the left or right side currently")
20+
21+
let text-position = here().position()
22+
23+
let side = position
24+
if position == auto {
25+
if text-position.x > page.width / 2 {
26+
side = right
27+
} else {
28+
side = left
29+
}
30+
}
31+
32+
let page-margin-box = calculate-page-margin-box(side)
33+
let shift-y = .5em
34+
let outer-box-inset = 4pt
35+
let dx = page-margin-box.x - text-position.x
36+
37+
place(dx: dx, dy: -shift-y)[
38+
#box(inset: outer-box-inset, width: page-margin-box.width)[
39+
#box(stroke: orange, width: 100%)[
40+
#place({
41+
// defaults for right side
42+
let line-size = dx
43+
let line-x = -line-size
44+
let tick-x = -line-size
45+
// overwrites for left side
46+
if side == left {
47+
line-size = calc.abs(dx) - page-margin-box.width + outer-box-inset
48+
line-x = page-margin-box.width - outer-box-inset * 2
49+
tick-x = calc.abs(dx) - outer-box-inset
50+
}
51+
52+
place(line(length: line-size, start: (line-x, shift-y), stroke: orange))
53+
place(line(length: 4pt, start: (tick-x, shift-y), angle: -90deg, stroke: orange))
54+
})
55+
// the todo message
56+
#box(body, inset: 0.2em)
57+
]
58+
// invisible figure, s.t. we can reference it in the outline
59+
// probably depends on https://github.com/typst/typst/issues/147 for a cleaner solution
60+
#hide(
61+
box(
62+
height: 0pt,
63+
width: 0pt,
64+
figure(
65+
none,
66+
kind: "todo",
67+
supplement: [TODO],
68+
caption: to-string(body),
69+
outlined: true,
70+
),
71+
),
72+
)
73+
]
74+
]
75+
})
76+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "dashy-todo"
3+
version = "0.0.2"
4+
entrypoint = "lib/todo.typ"
5+
authors = ["Otto-AA"]
6+
license = "MIT-0"
7+
description = "A method to display TODOs at the side of the page."
8+
repository = "https://github.com/Otto-AA/dashy-todo"
9+
keywords = ["todo"]
10+
categories = ["utility"]
11+
exclude = ["*.svg*"]

0 commit comments

Comments
 (0)