├── .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 `