├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── help_needed.md
├── .gitignore
├── .typos.toml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.typ
├── justfile
├── src
├── bundled-layout.typ
├── inspect.typ
├── layout.typ
├── lib.typ
├── parse.typ
├── styles
│ ├── boxy.typ
│ ├── hint.typ
│ └── thmbox.typ
├── styling.typ
└── utils
│ ├── encode.typ
│ └── html.typ
└── typst.toml
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[ BUG ] …"
5 | labels: bug
6 | assignees: marc-thieme
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **Minimal reproducible example**
14 | - Please provide a small but sufficient code snippet.
15 | - Please also include the `import`–line and your frame–definitions.
16 |
17 | **Expected behavior**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Additional context**
24 | Add any other context about the problem here.
25 |
26 | ---
27 |
28 | - Feel free to delete sections which don't apply
29 | - Feel free to be brief. One sentence might suffice.
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[ Feature ] …"
5 | labels: ''
6 | assignees: marc-thieme
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe your solution with respect to the output/`pdf`**
14 | - What does your solution change/look like?
15 | - Please focus on the aspects visible in the generated output.
16 |
17 | **Describe how you expect the syntax to look like**
18 | - If you don't know how your feature could work syntactically, you can remove this section
19 | - If you come up with multiple different syntax ideas, please list them all
20 |
21 | **Additional context**
22 | Add any other context or screenshots about the feature request here.
23 |
24 | ---
25 |
26 | - Feel free to delete sections which don't apply
27 | - Feel free to be brief. One sentence might suffice.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/help_needed.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: I don't know how to do something
3 | about: Ask how to solve a specific problem
4 | title: "[ Help ] …"
5 | labels: ''
6 | assignees: marc-thieme
7 |
8 | ---
9 |
10 | **Code sample + explanation of what you would try to achieve**
11 | …
12 |
13 | **What have you tried so far?**
14 | …
15 |
16 | **How would you have expected it to work?**
17 | Feel free to provide ways you tried but didn't work or how you feel would be natural.
18 |
19 | If you know of other projects where the same thing is possible, I would be interested to know how they do it :)
20 |
21 | ---
22 |
23 | - Feel free to delete sections which don't apply
24 | - Feel free to be brief. One sentence might suffice.
25 |
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pdf
2 | *.svg
3 |
--------------------------------------------------------------------------------
/.typos.toml:
--------------------------------------------------------------------------------
1 | [default]
2 | extend-ignore-words-re = ['typ']
3 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.2.0
2 | ### Features
3 | - feat(layout): add frame function to create a single frame
4 | - docs(readme): showcase syntax for individual frame creation
5 |
6 | ### Fixes
7 | - fix(layout): `frame-style` only applies to specific kind
8 | - fix(styles): accept tags without title in thmbox
9 | - fix: polylux presentation compatibility
10 | - fix(inspection): `is-frame` works for all content
11 |
12 | ### Implementation
13 | - refactor(layout): ad–hoc style by placing it into metadata
14 |
15 | ## 1.1.2
16 | - Add inspection functions `lookup-frame-info` and `is-frame`
17 | - Add suggestions for abbreviations to readme
18 | - Fix compilation without feature flag html
19 |
20 | ## 1.1.1
21 | - Rework README building
22 | - Add abitlity to export to HTML
23 | - Support dark theme for thmbox styling
24 |
25 | ## 1.1.0
26 | - Add new styling
27 | - In the `(make-)frames`–function, allow supplement to be supplied as single value
28 | instead of array
29 | - Pass additional arguments in a frame function onto the figure function
30 | when placing it in the document
31 | - Change API to declare the styling function to use using a show rule
32 | - Refactor layouting system to be simpler and more robust
33 | - Make frames breakable across pages
34 | - Add version of readme for dark mode on GitHub
35 | - Influence the auto–generated colors for the frames using `base-color` parameter
36 | - Improve Readme
37 |
38 | ## 1.0.0
39 | - Design syntax which minimizes redundancy, is flexible and easy to use
40 | - Create default style `boxy` and `hint`
41 | - Separate components and identify easy api for styling functions
42 | - If colors are missing, generate colors spanning the rainbow
43 | - Add a Readme which is compiled from Typst
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Marc Thieme
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > [!NOTE]
2 | > This is the version of the readme adapted for the Github Readme.
3 | This adaption is less than ideal.
4 | If you want to copy text and have a faithful render, go to [this link](https://html-preview.github.io/?url=https://github.com/marc-thieme/frame-it/blob/assets/README.html).
5 | ## Introduction
6 |
7 | [Frame-It](https://github.com/marc-thieme/frame-it) offers a
8 | straightforward way to define and use custom environments in your
9 | documents. Its syntax is designed to integrate seamlessly with your
10 | source code.
11 |
12 | Two predefined styles are included by default. You can also create
13 | custom styling functions that use the same user-facing API while giving
14 | you complete control over the Typst elements in your document.
15 |
16 |
17 |
18 | In contrast:
19 |
20 |
21 |
22 | The default styles are merely functions with the correct signature. If
23 | they don't appeal to you, you have complete freedom to define custom
24 | styling functions yourself.
25 |
26 |
27 |
28 | ## Quick Start
29 |
30 | Import and define your desired frames:
31 |
32 | ``` typst
33 | #import "@preview/frame-it:1.2.0": *
34 |
35 | #let (example, feature, variant, syntax) = frames(
36 | feature: ("Feature",),
37 | // For each frame kind, you have to provide its supplement title to be displayed
38 | variant: ("Variant",),
39 | // You can provide a color or leave it out and it will be generated
40 | example: ("Example", gray),
41 | // You can add as many as you want
42 | syntax: ("Syntax",),
43 | )
44 | // This is necessary. Don't forget this!
45 | #show: frame-style(styles.boxy)
46 | ```
47 |
48 | How to use it is explained below. Here is a quick example:
49 |
50 | ``` typst
51 | #example[Title][Optional Tag][
52 | Body, i.e. large content block for the frame.
53 | ]
54 | ```
55 |
56 | which yields
57 |
58 |
59 |
60 | ## Feature List
61 |
62 | The following features are demonstrated in all predefined styles.
63 |
64 | ### Seamlessly hightight parts of your document
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | For brief elements, use \[\] as the body to omit the content.
79 |
80 |
81 |
82 | ### Highlight parts distinctively
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | For brief elements, use \[\] as the body to omit the content.
97 |
98 |
99 |
100 | ### A third Alternative
101 |
102 | We recently added third style, namely `styles.thmbox`:
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | For brief elements, use \[\] as the body to omit the content.
117 |
118 |
119 |
120 | ### Miscellaneous
121 |
122 | #### Syntax to create single frames
123 |
124 |
125 |
126 | #### HTML
127 |
128 | We were one of the first packages to add support for html!
129 | This means you can use our frames for example if you're writing an html
130 | wiki or blog in typst or using typst to get a headstart writing your
131 | website.
132 |
133 |
134 |
135 | #### General
136 |
137 | Internally, every frame is just a `figure` where the `kind` is set to
138 | `"frame"` (or a different custom value). As such, most things that can
139 | be done to a figure can be done with a frame as well. Whenever you would
140 | like to do something custom but don't know if it is supported, try
141 | achieving it with a normal figure first and then apply the same show
142 | rule to your frames. Here is a list of examples:
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 | For example, you can create an outline which only contains some
151 | intentional of your frames like so. The `figure` function includes a
152 | parameter for including a figure in the outline.
153 |
154 | ``` typst
155 | // By default, don't include frames in outlines by default
156 | #show figure.where(kind: "frame"): set figure(outlined: false)
157 | // Create the outline
158 | #outline(target: figure.where(kind: "frame"))
159 | // Explicitly include a frame in the outline with the `outlined` parameter.
160 | #example(outlined: true)[Important frame][For the outline]
161 | ```
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 | When you want to change the styling used for a passage of your document,
170 | you can just add more `show: frame-style()` rules:
171 |
172 | ``` typst
173 | #show: frame-style(styles.boxy)
174 | #example[In boxy style][]
175 | #show: frame-style(styles.hint)
176 | #example[In hint Style][]
177 | ```
178 |
179 | I usually define the abbreviations for the show rule:
180 |
181 | ``` typst
182 | // Define once
183 | #let boxy(document) = {show: frame-style(styles.boxy); document}
184 | #let hint(document) = {show: frame-style(styles.hint); document}
185 |
186 | // Use it for changing the style used
187 | #show: boxy
188 | #example[In boxy style]
189 | #example[Also in boxy style]
190 | #show: hint
191 | #example[In hint style]
192 | ```
193 |
194 | ## Custom Styling
195 |
196 | Internally, there is nothing special about the predefined styles. The
197 | only requirement for any styling function is to adhere to the following
198 | function signature interface:
199 |
200 |
201 |
202 | where `arg` is going to be the value passed behind the supplement for
203 | each frame variant in the `frames` function. For the predefined styles,
204 | this is the color of the frames. When defining your own styling
205 | function, it has to have the following signature:
206 |
207 | The content returned will be placed as–is in the document.
208 |
209 |
210 |
211 | For more information on how to define your own styling function, please
212 | look into the `styling` module.
213 |
214 | ## Experimentl APIs
215 |
216 | These APIs are still experimental and subject to change. Use sparingly.
217 |
218 |
219 |
220 | For example, you can use this to color the entries in a outline
221 | according to the color of the frame:
222 |
223 | ``` typst
224 | #show outline.entry: it => {
225 | let color = inspect.lookup-frame-info(it.element).color
226 | text(fill: color.saturate(70%), it)
227 | }
228 | #outline(target: figure.where(kind: "frame"))
229 | ```
230 |
231 |
232 |
233 | Whenever possible, try to discern it using the figures kind instead of
234 | this function.
235 |
236 | This can be useful, for example, when you want to format references in
237 | your document differently. For example, you can do something like this
238 | in order to display just title if the referenced element and link to it:
239 |
240 | ``` typst
241 | #show ref: it => {
242 | if inspect.is-frame(it.element) {
243 | link(it.element.location(), inspect.lookup-frame-info(it.element).title)
244 | } else {
245 | it
246 | }
247 | }
248 | ```
249 |
250 | ## Edge Cases
251 |
252 | Here are a few edge cases.
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
264 | Should be thmbox
265 | Other Frame 1
266 |
thmbox
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 | Some Additional Frame
275 | 1 Individual : Individual
276 |
--------------------------------------------------------------------------------
/README.typ:
--------------------------------------------------------------------------------
1 | #import "src/lib.typ": *
2 | #import "src/utils/html.typ": *
3 |
4 | #let base-color-arg = (:)
5 | #let text-color = black
6 | #let background-color = white
7 | #if sys.inputs.at("theme", default: "light") == "dark" {
8 | text-color = rgb(240, 246, 252)
9 | background-color = rgb("#0d1117")
10 | base-color-arg.base-color = blue.darken(40%).desaturate(25%)
11 | }
12 | #let example-color = text-color.mix((text-color.negate(), 590%)).mix(gray)
13 |
14 | #let (example, feature, variant, syntax) = frames(
15 | ..base-color-arg,
16 | feature: "Feature",
17 | variant: ("Feature Variant",),
18 | example: ("Example", example-color),
19 | syntax: ("Syntax",),
20 | )
21 |
22 | #set text(text-color)
23 | #set text(17pt)
24 |
25 | #let wants-svg-frames = sys.inputs.at("svg-frames", default: "false") != "false"
26 | #show figure.where(kind: "frame"): it => context if (
27 | wants-html() and wants-svg-frames
28 | ) {
29 | html.frame({
30 | v(2mm)
31 | block(width: 24cm, it)
32 | v(2mm)
33 | })
34 | } else { it }
35 |
36 | #show raw.where(lang: "typst"): code => context if wants-html() {
37 | html.elem(
38 | "pre",
39 | html.elem(
40 | "code",
41 | attrs: (class: "typst"),
42 | code,
43 | ),
44 | )
45 | } else { code }
46 |
47 | #show: it => context if not wants-html() {
48 | set page(fill: background-color)
49 | set page(height: auto, margin: 4mm)
50 | it
51 | } else { it }
52 |
53 | #show: frame-style(styles.boxy)
54 |
55 | = Introduction
56 | #link("https://github.com/marc-thieme/frame-it", text(blue)[Frame-It]) offers a straightforward way to define and use custom environments in your documents. Its syntax is designed to integrate seamlessly with your source code.
57 |
58 | Two predefined styles are included by default. You can also create custom styling functions that use the same user-facing API while giving you complete control over the Typst elements in your document.
59 |
60 | #feature[Distinct Highlight][Best for occasional use][More noticeable][
61 | The default style, `styles.boxy`, is eye-catching and intended to stand out from the surrounding text.
62 | ]
63 |
64 | In contrast:
65 |
66 | #feature(
67 | style: styles.hint,
68 | )[Unobtrusive Style][Ideal for frequent use][Blends into text flow][
69 | The alternative style `styles.hint` highlights text with a subtle colored line along the side, preserving the document's flow.
70 | ]
71 |
72 | The default styles are merely functions with the correct signature.
73 | If they don't appeal to you, you have complete freedom to define custom styling functions yourself.
74 |
75 | #example[A different frame kind][
76 | You can define different classes or types of frames, which alter the substitute and the frame's color. As shown here, this is an example frame.
77 | You can create as many different kinds as you want.
78 |
79 | As long as all kinds use the same identifier with `frames`, they share a common counter.
80 | ]
81 |
82 | = Quick Start
83 | Import and define your desired frames:
84 |
85 | ```typst
86 | #import "@preview/frame-it:1.2.0": *
87 |
88 | #let (example, feature, variant, syntax) = frames(
89 | feature: ("Feature",),
90 | // For each frame kind, you have to provide its supplement title to be displayed
91 | variant: ("Variant",),
92 | // You can provide a color or leave it out and it will be generated
93 | example: ("Example", gray),
94 | // You can add as many as you want
95 | syntax: ("Syntax",),
96 | )
97 | // This is necessary. Don't forget this!
98 | #show: frame-style(styles.boxy)
99 | ```
100 |
101 | How to use it is explained below. Here is a quick example:
102 | ```typst
103 | #example[Title][Optional Tag][
104 | Body, i.e. large content block for the frame.
105 | ]
106 | ```
107 | which yields
108 | #example[Title][Optional Tag][
109 | Body, i.e. large content block for the frame.
110 | ]
111 |
112 | = Feature List
113 |
114 | #let layout-features() = [
115 | #feature[Element with Title and Content][
116 | The simplest way to create an element is by providing a title as the first argument and content as the second.
117 | ]
118 |
119 | #variant[Element with Tags][Customizable Tags][Multiple][
120 | Elements can include multiple tags placed between the title and the content.
121 | ]
122 |
123 | #feature[][
124 | If you don’t require a custom title but still want to display the element type, use `[]` as the title placeholder.
125 | ]
126 |
127 | #variant[][Single Tag][Next tag][
128 | You can include tags even when no title is provided.
129 | ]
130 |
131 | #variant[
132 | To omit the header entirely, leave the title parameter empty.
133 | ]
134 |
135 | #feature[Element without Content][Optional Tags Only][]
136 | For brief elements, use [] as the body to omit the content.
137 |
138 | #feature[Element with Divider][
139 | Insert ```typst #divide()``` to add a divider within your content for a visual break:
140 | #divide()
141 | And then continue with your text below the divider.
142 | ]
143 | ]
144 |
145 | The following features are demonstrated in all predefined styles.
146 |
147 | == Seamlessly hightight parts of your document
148 | #[
149 | #show: frame-style(styles.hint)
150 | #layout-features()
151 | ]
152 | == Highlight parts distinctively
153 | #[
154 | #show: frame-style(styles.boxy)
155 | #layout-features()
156 | ]
157 | == A third Alternative
158 | #[
159 | #show: frame-style(styles.thmbox)
160 | We recently added third style, namely `styles.thmbox`:
161 | #layout-features()
162 | ]
163 | == Miscellaneous
164 | === Syntax to create single frames
165 | #syntax[Single–Frame–Creation][
166 | When the above method for creating frames is not flexible enough, you can use this alternative method
167 | for creating frames one–by–one:
168 | ```typ
169 | #let theorem = frame("Theorem", red)
170 | #let definition = frame(kind: "not-the-default", "Definition", blue)
171 | ```
172 | Contrary to the first method, you have to specify a color.
173 | ]
174 |
175 | === HTML
176 | We were one of the first packages to add support for html! \
177 | This means you can use our frames for example if you're writing an html wiki or blog in typst
178 | or using typst to get a headstart writing your website.
179 | #feature[HTML export][
180 | Due to the currently experimental nature of the feature, you need to pass two CLI–flags when
181 | compiling your document with the frames to html:
182 | ```
183 | typst compile --features html --input html-frames=true --format html FILE.typ
184 | ```
185 | ]
186 |
187 | === General
188 | Internally, every frame is just a `figure` where the `kind` is set to `"frame"` (or a different custom value).
189 | As such, most things that can be done to a figure can be done with a frame as well.
190 | Whenever you would like to do something custom but don't know if it is supported,
191 | try achieving it with a normal figure first and then apply the same show rule to your frames.
192 | Here is a list of examples:
193 |
194 | #variant[Labels and References][
195 | Elements can be referenced as expected by appending `