diff --git a/packages/preview/alertoni/1.0.0/LICENSE b/packages/preview/alertoni/1.0.0/LICENSE
new file mode 100644
index 0000000000..6d8cea430e
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/LICENSE
@@ -0,0 +1,190 @@
+EUROPEAN UNION PUBLIC LICENCE v. 1.2
+EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined below) which is provided under the
+terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such
+use is covered by a right of the copyright holder of the Work).
+The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following
+notice immediately following the copyright notice for the Work:
+ Licensed under the EUPL
+or has expressed by any other means his willingness to license under the EUPL.
+
+1.Definitions
+In this Licence, the following terms have the following meaning:
+— ‘The Licence’:this Licence.
+— ‘The Original Work’:the work or software distributed or communicated by the Licensor under this Licence, available
+as Source Code and also as Executable Code as the case may be.
+— ‘Derivative Works’:the works or software that could be created by the Licensee, based upon the Original Work or
+modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work
+required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in
+the country mentioned in Article 15.
+— ‘The Work’:the Original Work or its Derivative Works.
+— ‘The Source Code’:the human-readable form of the Work which is the most convenient for people to study and
+modify.
+— ‘The Executable Code’:any code which has generally been compiled and which is meant to be interpreted by
+a computer as a program.
+— ‘The Licensor’:the natural or legal person that distributes or communicates the Work under the Licence.
+— ‘Contributor(s)’:any natural or legal person who modifies the Work under the Licence, or otherwise contributes to
+the creation of a Derivative Work.
+— ‘The Licensee’ or ‘You’:any natural or legal person who makes any usage of the Work under the terms of the
+Licence.
+— ‘Distribution’ or ‘Communication’:any act of selling, giving, lending, renting, distributing, communicating,
+transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential
+functionalities at the disposal of any other natural or legal person.
+
+2.Scope of the rights granted by the Licence
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for
+the duration of copyright vested in the Original Work:
+— use the Work in any circumstance and for all usage,
+— reproduce the Work,
+— modify the Work, and make Derivative Works based upon the Work,
+— communicate to the public, including the right to make available or display the Work or copies thereof to the public
+and perform publicly, as the case may be, the Work,
+— distribute the Work or copies thereof,
+— lend and rent the Work or copies thereof,
+— sublicense rights in the Work or copies thereof.
+Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the
+applicable law permits so.
+In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed
+by law in order to make effective the licence of the economic rights here above listed.
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the
+extent necessary to make use of the rights granted on the Work under this Licence.
+
+3.Communication of the Source Code
+The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as
+Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with
+each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to
+the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to
+distribute or communicate the Work.
+
+4.Limitations on copyright
+Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the
+exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations
+thereto.
+
+5.Obligations of the Licensee
+The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those
+obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to
+the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the
+Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work
+to carry prominent notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this
+Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless
+the Original Work is expressly distributed only under this version of the Licence — for example by communicating
+‘EUPL v. 1.2 only’. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the
+Work or Derivative Work that alter or restrict the terms of the Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both
+the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done
+under the terms of this Compatible Licence. For the sake of this clause, ‘Compatible Licence’ refers to the licences listed
+in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with
+his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide
+a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available
+for as long as the Licensee continues to distribute or communicate the Work.
+Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names
+of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6.Chain of Authorship
+The original Licensor warrants that the copyright in the Original Work granted hereunder is owned by him/her or
+licensed to him/her and that he/she has the power and authority to grant the Licence.
+Each Contributor warrants that the copyright in the modifications he/she brings to the Work are owned by him/her or
+licensed to him/her and that he/she has the power and authority to grant the Licence.
+Each time You accept the Licence, the original Licensor and subsequent Contributors grant You a licence to their contributions
+to the Work, under the terms of this Licence.
+
+7.Disclaimer of Warranty
+The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work
+and may therefore contain defects or ‘bugs’ inherent to this type of development.
+For the above reason, the Work is provided under the Licence on an ‘as is’ basis and without warranties of any kind
+concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or
+errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this
+Licence.
+This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work.
+
+8.Disclaimer of Liability
+Except in the cases of wilful misconduct or damages directly caused to natural persons, the Licensor will in no event be
+liable for any direct or indirect, material or moral, damages of any kind, arising out of the Licence or of the use of the
+Work, including without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, loss
+of data or any commercial damage, even if the Licensor has been advised of the possibility of such damage. However,
+the Licensor will be liable under statutory product liability laws as far such laws apply to the Work.
+
+9.Additional agreements
+While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services
+consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole
+responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify,
+defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by
+the fact You have accepted any warranty or additional liability.
+
+10.Acceptance of the Licence
+The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ placed under the bottom of a window
+displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of
+applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms
+and conditions.
+Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You
+by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution
+or Communication by You of the Work or copies thereof.
+
+11.Information to the public
+In case of any Distribution or Communication of the Work by means of electronic communication by You (for example,
+by offering to download the Work from a remote location) the distribution channel or media (for example, a website)
+must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence
+and the way it may be accessible, concluded, stored and reproduced by the Licensee.
+
+12.Termination of the Licence
+The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms
+of the Licence.
+Such a termination will not terminate the licences of any person who has received the Work from the Licensee under
+the Licence, provided such persons remain in full compliance with the Licence.
+
+13.Miscellaneous
+Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the
+Work.
+If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or
+enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid
+and enforceable.
+The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of
+the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence.
+New versions of the Licence will be published with a unique version number.
+All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take
+advantage of the linguistic version of their choice.
+
+14.Jurisdiction
+Without prejudice to specific agreement between parties,
+— any litigation resulting from the interpretation of this License, arising between the European Union institutions,
+bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice
+of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union,
+— any litigation arising between other parties and resulting from the interpretation of this License, will be subject to
+the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business.
+
+15.Applicable Law
+Without prejudice to specific agreement between parties,
+— this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat,
+resides or has his registered office,
+— this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside
+a European Union Member State.
+
+
+ Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+— GNU General Public License (GPL) v. 2, v. 3
+— GNU Affero General Public License (AGPL) v. 3
+— Open Software License (OSL) v. 2.1, v. 3.0
+— Eclipse Public License (EPL) v. 1.0
+— CeCILL v. 2.0, v. 2.1
+— Mozilla Public Licence (MPL) v. 2
+— GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+— Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software
+— European Union Public Licence (EUPL) v. 1.1, v. 1.2
+— Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+).
+
+The European Commission may update this Appendix to later versions of the above licences without producing
+a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the
+covered Source Code from exclusive appropriation.
+All other changes or additions to this Appendix require the production of a new EUPL version.
diff --git a/packages/preview/alertoni/1.0.0/README.md b/packages/preview/alertoni/1.0.0/README.md
new file mode 100644
index 0000000000..c0d6d2a1fb
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/README.md
@@ -0,0 +1,69 @@
+
+
+# Alertoni
+
+A Typst package that introduces callouts with three different styles and various types. In addition, the package also supports custom styles, types and icon sets.
+
+
+- Read more on how to use it and other functionality in the [Manual](./docs/manual.pdf).
+
+## Quick Examples
+
+```typst
+#import "@preview/alertoni:1.0.0" as at
+```
+
+### All Predefined Types
+
+```typst
+#at.callout(type: "info", [])
+#at.callout(type: "warning", [])
+#at.callout(type: "important", [])
+#at.callout(type: "caution", [])
+#at.callout(type: "tip", [])
+#at.callout(type: "correct", [])
+#at.callout(type: "incorrect", [])
+#at.callout(type: "example", [])
+```
+
+
+
+### All Predefined Styles
+
+**Note**: you can add your own style. Refer to the manual.
+
+```typst
+#at.callout(
+ style: "minimal", [Style `"minimal"`]
+)
+
+#at.callout(
+ style: "quarto", [Style `"quarto"`]
+)
+
+#at.callout(
+ style: "compact", [Style `"compact"`]
+) -- it is also an inline style.
+```
+
+
+
+### A Custom Type
+
+```typst
+#at.new-type(
+ name: "hey",
+ color: olive,
+ placeholder: "Hello There!",
+ icon: emoji.hand.wave
+)
+
+#at.callout(type: "hey", [
+ #lorem(20)
+])
+```
+
+
+
+
+Types can also be langnuage specific and is explained in the manual.
diff --git a/packages/preview/alertoni/1.0.0/docs/banner.svg b/packages/preview/alertoni/1.0.0/docs/banner.svg
new file mode 100644
index 0000000000..a758b29e20
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/docs/banner.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/preview/alertoni/1.0.0/docs/banner.typ b/packages/preview/alertoni/1.0.0/docs/banner.typ
new file mode 100644
index 0000000000..b1ace3679b
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/docs/banner.typ
@@ -0,0 +1,98 @@
+#import "@preview/alertoni:1.0.0" as at
+
+#let radius = 3pt
+#let inset = (top: 8pt, rest: 6pt)
+
+#let callout-style(title, icon, content, paint, height, width) = align(
+ center,
+ block(
+ above: 1.5em,
+ below: 1.5em,
+ width: width,
+ height: height,
+ stroke: paint + 1pt,
+ inset: inset,
+ fill: white,
+ radius: radius,
+ {
+ set align(left)
+ // title block
+
+ if icon != none or title != none {
+ place(top + left, dy: -inset.top - 0.5em, dx: -1pt, box(
+ fill: white,
+ inset: if icon == none {
+ (x: 2pt)
+ } else if title == none {
+ (x: 0pt)
+ } else {
+ (left: 1pt, right: 2pt)
+ },
+ outset: (y: 1pt),
+ grid(
+ align: center + horizon,
+ ..if icon != none and title != none { (column-gutter: 0.2em) },
+ columns: if icon == none or title == none {
+ auto
+ } else {
+ (1em, auto)
+ }, rows: 1em,
+ ..(
+ if icon != none {
+ (text(paint, icon),)
+ }
+ + if title != none {
+ (text(weight: "bold", paint, title),)
+ }
+ )
+ ),
+ ))
+ }
+ content
+ },
+ ),
+)
+
+#let callout = at.callout.with(style: callout-style)
+
+#set page(width: 21cm, height: 6.8cm, margin: 5mm)
+#set text(21pt)
+
+#let typst-toml = toml("../typst.toml")
+
+#block(width: 100%, height: 100%, [
+ #place(top, {
+ callout(pad(1.5em, text(5.5em)[A]), width: 40%)
+ })
+
+ #place(
+ top,
+ {
+ callout(type: "tip", pad(1em, text(5.5em)[to]), width: auto)
+ },
+ dx: 13.5em,
+ dy: 0.8em,
+ )
+
+ #place(
+ top,
+ {
+ callout(type: "caution", pad(1em, text(5.5em)[ler]), width: auto)
+ },
+ dx: 6em,
+ dy: 1.6em,
+ )
+
+ #place(
+ top,
+ {
+ callout(type: "important", pad(1em, text(5.5em)[ni]), width: auto)
+ },
+ dx: 20em,
+ dy: 0.4em,
+ )
+
+ #place(right+bottom, text(0.7em)[Version #typst-toml.package.version], dy: -0.3em, dx: 0em)
+])
+
+
diff --git a/packages/preview/alertoni/1.0.0/docs/images/all-styles.png b/packages/preview/alertoni/1.0.0/docs/images/all-styles.png
new file mode 100644
index 0000000000..65bbe066be
Binary files /dev/null and b/packages/preview/alertoni/1.0.0/docs/images/all-styles.png differ
diff --git a/packages/preview/alertoni/1.0.0/docs/images/all-types.png b/packages/preview/alertoni/1.0.0/docs/images/all-types.png
new file mode 100644
index 0000000000..c90d0b79f0
Binary files /dev/null and b/packages/preview/alertoni/1.0.0/docs/images/all-types.png differ
diff --git a/packages/preview/alertoni/1.0.0/docs/images/burger.png b/packages/preview/alertoni/1.0.0/docs/images/burger.png
new file mode 100644
index 0000000000..59c653905b
Binary files /dev/null and b/packages/preview/alertoni/1.0.0/docs/images/burger.png differ
diff --git a/packages/preview/alertoni/1.0.0/docs/images/little-kitty.jpg b/packages/preview/alertoni/1.0.0/docs/images/little-kitty.jpg
new file mode 100644
index 0000000000..c18610b14a
Binary files /dev/null and b/packages/preview/alertoni/1.0.0/docs/images/little-kitty.jpg differ
diff --git a/packages/preview/alertoni/1.0.0/docs/images/new-type.png b/packages/preview/alertoni/1.0.0/docs/images/new-type.png
new file mode 100644
index 0000000000..42e06ae0c1
Binary files /dev/null and b/packages/preview/alertoni/1.0.0/docs/images/new-type.png differ
diff --git a/packages/preview/alertoni/1.0.0/docs/manual.pdf b/packages/preview/alertoni/1.0.0/docs/manual.pdf
new file mode 100644
index 0000000000..8ff909393e
Binary files /dev/null and b/packages/preview/alertoni/1.0.0/docs/manual.pdf differ
diff --git a/packages/preview/alertoni/1.0.0/docs/manual.typ b/packages/preview/alertoni/1.0.0/docs/manual.typ
new file mode 100644
index 0000000000..9383a668cb
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/docs/manual.typ
@@ -0,0 +1,746 @@
+#import "@preview/alertoni:1.0.0"
+#import "@preview/tableau-icons:0.344.0": ti-icon
+#import "@preview/shadowed:0.3.0": shadow
+#import "@preview/tidy:0.4.3"
+
+#let package-name = "Alertoni"
+
+#let typst-toml = toml("../typst.toml")
+
+#set smartquote(
+ quotes: (
+ double: (sym.quote.chevron.double.l, sym.quote.chevron.double.r),
+ single: (sym.quote.chevron.l, sym.quote.chevron.r),
+ ),
+)
+
+#let my-link(link, body) = {
+ underline(offset: 0.15em, text(blue, std.link(link, body)))
+}
+
+#show `#callout`.text: my-link(label("-callout()"), `#callout`)
+#show `#new-type`.text: my-link(label("-new-type()"), `#new-type`)
+#show `#set-icons`.text: my-link(label("-set-icons()"), `#set-icons`)
+
+#show raw.where(block: true): it => {
+ show `callout`.text: set text(9.5pt)
+ show `new-type`.text: set text(9.5pt)
+ show `set-icons`.text: set text(9.5pt)
+
+ show `callout`.text: link(label("-callout()"), `callout`)
+ show `new-type`.text: link(label("-new-type()"), `new-type`)
+ show `set-icons`.text: link(label("-set-icons()"), `set-icons`)
+
+ show `callout`.text: underline(offset: 0.2em, "callout")
+ show `new-type`.text: underline.with(offset: 0.2em)
+ show `set-icons`.text: underline.with(offset: 0.2em)
+ it
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* Show/Set Rules */
+/* -------------------------------------------------------------------------- */
+
+
+#alertoni.new-type(
+ name: "package",
+ color: blue,
+ icon: ti-icon("package"),
+ placeholder: raw(package-name),
+)
+
+#let package-func(title, icon, content, paint, height, width) = {
+ box(fill: paint.lighten(80%), outset: (y: 0.15em), inset: (right: 0.25em), radius: 0.2em, grid(
+ columns: 2,
+ align: horizon,
+ gutter: 0.25em,
+ text(top-edge: "bounds", bottom-edge: "bounds", white, box(
+ grid(
+ columns: 2,
+ gutter: 0.25em,
+ icon, strong(title),
+ ),
+ fill: paint,
+ outset: (y: 0.15em),
+ inset: (x: 0.15em),
+ radius: 0.2em,
+ )),
+ content,
+ ))
+}
+
+
+#set page(
+ paper: "a4",
+ margin: 2.5cm,
+ footer: block(width: 100%, stroke: (top: (paint: gray, thickness: 0.5pt, dash: "dashed")), inset: (top: 0.5em), align(
+ center,
+ context [#counter(page).at(here()).first() #text(gray, [/]) #counter(page).final().first()],
+ )),
+ header: context if here().page() != 1 {
+ block(width: 100%, stroke: (bottom: (paint: gray, thickness: 0.5pt, dash: "dashed")), inset: (bottom: 0.5em))[
+ #alertoni.callout(
+ type: "package",
+ text(number-width: "tabular", raw(typst-toml.package.version)),
+ style: package-func,
+ )
+ #h(1fr)
+ _Package Documentation_
+ ]
+ },
+)
+
+#set text(lang: "en", region: "CH", font: ("Atkinson Hyperlegible Next", "Noto Color Emoji"), 11pt)
+
+
+
+#show heading.where(level: 1): set text(20pt)
+#show heading.where(level: 1): set block(above: 1em, below: 1em)
+#show heading.where(level: 1, outlined: true): set heading(numbering: (..n) => (
+ text(blue, numbering("I", ..n)) + text(gray, weight: "regular", [ \\])
+))
+
+#show heading.where(level: 2): set heading(numbering: (..n) => {
+ [#text(gray, weight: "regular", numbering("I.", n.at(0)))#text(blue, numbering("1", n.at(1)))]
+})
+
+#show heading.where(level: 3): set heading(numbering: (..n) => {
+ [#text(gray, weight: "regular", numbering("I.1.", ..n.pos().slice(0, 2)))#text(blue, numbering("a", ..n
+ .pos()
+ .slice(2, 3)))]
+})
+
+
+
+#set list(marker: text(blue, sym.bullet))
+
+#set enum(numbering: n => box(fill: blue, outset: 2pt, radius: 0.2em, text(
+ white,
+ weight: "bold",
+ top-edge: "bounds",
+ bottom-edge: "bounds",
+ number-width: "tabular",
+ numbering("1.", n),
+)))
+
+
+
+#show raw: set text(font: "Fantasque Sans Mono", 9.5pt)
+#show raw.where(block: false): set text(11pt)
+
+#let my-style(title, _, body, paint, _, _) = {
+ text(paint, strong[#title ]) + [#body]
+}
+
+#show raw.where(block: true, lang: "example").or(raw.where(block: true, lang: "vexample")): it => {
+ show grid: set block(sticky: true)
+
+ let inner-inset = if it.lang == "example" { 6pt } else { 6pt }
+ let outer-inset = if it.lang == "example" { 3pt } else { 3pt }
+ let radius = 4pt
+ let spacing = if it.lang == "example" { 5pt } else { 7pt }
+ let dir = if it.lang == "example" { ltr } else { ttb }
+
+ let hide-hidden = ()
+ let apply-hidden = ()
+
+ for l in it.lines {
+ if l.text.starts-with("///") {
+ apply-hidden += ((text: l.text.slice(3).trim()),)
+ } else if l.text.starts-with("//!") {
+ hide-hidden += ((text: l.text.slice(3).trim()),)
+ } else {
+ hide-hidden += (l,)
+ apply-hidden += (l,)
+ }
+ }
+
+ let arrangement(width: 100%, height: auto) = stack(
+ dir: dir,
+ spacing: spacing,
+ block(
+ ..if it.lang == "example" { (width: width / 2 - spacing / 2, inset: (left: outer-inset)) },
+ height: height,
+ block(
+ stroke: rgb("#e2e3e8") + 1pt,
+ radius: radius,
+ width: 100%,
+ height: height,
+ inset: inner-inset,
+ {
+ let lines = it.lines
+
+ raw(hide-hidden.map(x => x.text).join("\n"), lang: "typst", block: true)
+ },
+ ),
+ ),
+ block(
+ ..if it.lang == "example" { (width: width / 2 - spacing / 2) } else { (width: 100%) },
+ inset: inner-inset,
+ height: height,
+ stroke: (paint: rgb("#e2e3e8"), thickness: 1pt, dash: "dashed"),
+ radius: radius,
+ {
+ set text(font: "Atkinson Hyperlegible Next", 9.5pt)
+ eval(apply-hidden.map(x => x.text).join("\n"), mode: "markup", scope: (
+ at: alertoni,
+ my-style: my-style,
+ ti-icon: ti-icon,
+ ))
+ },
+ ),
+ )
+
+ if it.lang == "example" {
+ layout(size => {
+ arrangement(height: measure(arrangement(width: size.width)).height)
+ })
+ } else {
+ block(arrangement(), inset: outer-inset)
+ }
+}
+
+
+
+#show divider: set align(center)
+#show divider: block(above: 1cm, below: 1cm, text(
+ blue,
+ top-edge: "bounds",
+ bottom-edge: "bounds",
+)[`<`$ast.op$`>` #box(line(length: 60%, stroke: blue + 0.75pt), baseline: -0.24em) `<`$ast.op$`>`])
+
+
+
+
+/* -------------------------------------------------------------------------- */
+/* Functions */
+/* -------------------------------------------------------------------------- */
+
+#let pill(content, fill) = {
+ box(text(font: "Fantasque Sans Mono", content), inset: (x: 3pt), outset: (y: 3pt), fill: fill, radius: 3pt)
+}
+
+#let tytyp = (
+ content: pill([content], rgb("#a6ebe6")),
+ array: pill([array], rgb("#f9dfff")),
+ dictionary: pill([dictionary], rgb("#f9dfff")),
+ arguments: pill([arguments], rgb("#ffdfdf")),
+ integer: pill([integer], rgb("#ffecbf")),
+ datetime: pill([datetime], rgb("#b7daec")),
+ color: pill([color], gradient.linear(
+ angle: 7deg,
+ (rgb("#7cd5ff"), 0%),
+ (rgb("#a6fbca"), 33%),
+ (rgb("#fff37c"), 66%),
+ (rgb("#ffa49d"), 100%),
+ )),
+ string: pill([string], rgb("#d1ffe2")),
+ length: pill([length], rgb("#ffecbf")),
+ function: pill([function], rgb("#d1d4fd")),
+)
+
+#let default-red(value) = {
+ text(0.8em)[default: #text(red, value)]
+}
+#let default-normal(cont) = {
+ text(0.8em)[default: #cont]
+}
+
+#let typst-toml = toml("../typst.toml")
+
+#let callout-types = ("info", "warning", "important", "caution", "tip", "correct", "incorrect", "example")
+
+#let code-block = block.with(width: 100%, inset: 0.5em, stroke: gray.lighten(50%), radius: 0.3em)
+
+
+#let argument(content, prefix: none) = {
+ show terms: it => pad(left: it.indent + it.hanging-indent, stack(
+ ..it.children.map(item => {
+ h(-it.hanging-indent)
+ text(font: "Fantasque Sans Mono", if prefix == none [#strong(item.term)] else {
+ assert(type(prefix) == str, message: "prefix must be a string")
+ let label = ("param", prefix, item.term.text)
+ [#strong(item.term) #metadata(label) #std.label(label.join(":"))]
+ })
+ it.separator
+ item.description
+ }),
+ spacing: 1.2em,
+ ))
+
+ set text(0.9em)
+ block(
+ above: 1.5em,
+ below: 1.5em,
+ width: 100%,
+ height: auto,
+ stroke: gray + 0.5pt,
+ inset: (top: 8pt, rest: 6pt),
+ radius: 3pt,
+ {
+ set align(left)
+ // title block
+ place(top + left, dy: -8pt - 0.5em, dx: -2pt, box(fill: white, inset: (x: 2pt), outset: (y: 1pt), text(
+ gray,
+ "Arguments",
+ )))
+ content
+ },
+ )
+}
+
+
+
+/* -------------------------------------------------------------------------- */
+/* Content */
+/* -------------------------------------------------------------------------- */
+
+
+
+
+#place(
+ top + center,
+ scope: "parent",
+ float: true,
+ {
+ v(1cm)
+ image("banner.svg")
+ },
+)
+#v(2cm)
+
+#divider()
+
+#[
+ #set heading(outlined: false)
+ = About
+]
+#emph(package-name) is a package that introduces various callouts types with three different styles. In addition the package supports custom callout types, custom styling and switching icon sets.
+
+
+
+
+#divider()
+
+#{
+ show "": typst-toml.package.name
+ show "": typst-toml.package.version
+ ```example
+ //! #import "@preview/:" as at
+
+ #at.callout(
+ type: "important",
+ title: [Kitty!],
+ [
+ #image("./images/little-kitty.jpg")
+ ]
+ )
+ ```
+}
+
+#place(right, dy: 0.6em, dx: -0.5em, {
+ show heading.where(level: 1): set block(above: 2em, below: 1em)
+ show link: underline.with(offset: 0.15em)
+ show link: set text(blue)
+
+ text(
+ 0.8em,
+ )[Photo by #my-link("https://unsplash.com/@kotecinho?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText")[Kote Puerto] on #my-link("https://unsplash.com/photos/white-and-gray-kitten-on-white-textile-so5nsYDOdxw?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText")[Unsplash]]
+})
+
+#pagebreak()
+
+#outline()
+
+#pagebreak()
+/* -------------------------------------------------------------------------- */
+/* Main Content */
+/* -------------------------------------------------------------------------- */
+
+#show heading.where(level: 1): set block(above: 2em, below: 1em)
+
+= Installation
+
+#set footnote(numbering: n => text(red, font: "Fantasque Sans Mono", strong[#n]))
+
+
+#[
+ #show ``.text: typst-toml.package.version
+ #show ``.text: typst-toml.package.name
+
+
+
+ 1. / Install Tabler.io font:
+ - Tabler.io Icons (#my-link("https://tabler.io/icons", [Webpage Link]) or #my-link("https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/dist/fonts/", [CDN JsDelivr Page])#footnote[You can build the font yourself, the building scripts are available at #my-link("https://github.com/tabler/tabler-icons", "https://github.com/tabler/tabler-icons"). Thus I believe you should have access to these files as well. *But support the icon designers if you can!*])
+
+ #alertoni.callout(
+ type: "important",
+ width: auto,
+ )[At default settings, this font *is required*!]
+
+ 2. / Import the package: in three different ways
+
+ - Via Typst Universe\
+
+ #code-block(```typ
+ #import "@preview/:" as at
+ ```)
+
+ - Downloading or cloning the repository #raw(lang: "bash", "\"" + typst-toml.package.repository + "\"") and then including the `exports.typ` file.\
+
+ #code-block(```typ
+ #import "./path/to/typst-alertoni/exports.typ" as at
+ ```)
+ - Via `@local` namespace\
+
+ #code-block(```typ
+ #import "@local/:" as at
+ ```)
+]
+
+
+
+= Usage
+
+== Callout Styles
+
+_Styles_ in the context of #emph(package-name) is how the callout look, so the drawing style. The package comes with three predefined styles and allows for user defined styles.
+
+=== Predefined Styles
+
+The three predefined styles are #(`"minimal"`, `"compact"`, `"quarto"`).map(x => x.text).map(raw.with(lang: "typc")).join([, ]). The last style #raw(`"quarto"`.text, lang: "typc") is inspired by (aka. almost identical copy of) Quarto's #my-link("https://quarto.org/docs/authoring/callouts.html")[callout blocks].
+
+```example
+/// #set raw(lang: "typc")
+#at.callout(
+ style: "minimal", [Style `"minimal"`]
+)
+```
+
+```example
+/// #set raw(lang: "typc")
+#at.callout(
+ style: "quarto", [Style `"quarto"`]
+)
+```
+
+```example
+/// #set raw(lang: "typc")
+#at.callout(
+ style: "compact", [Style `"compact"`]
+) -- it is also an inline style.
+```
+
+
+#pagebreak()
+
+=== Creating & Using Custom Callout Styles
+
+To allow for a more individual customization of the style, a custom callout style can be defined. To "assign" a custom style, a function in the shape of
+
+#code-block(```typc
+(title, icon, content, paint, height, width) => {...}
+```)
+
+
+is passed onto the #my-link(<-callout.style>, `style`) parameter of the `#callout` function.
+
+```example
+#let my-style(title,_,body,paint,_,_) = {
+ text(paint, strong[#title ]) + [#body]
+}
+
+#at.callout(style: my-style, [
+ about a new style!
+])
+```
+
+#alertoni.callout(
+ type: "important",
+ title: [Global Configuration?],
+ [
+ The function is only applied to the callout function it was passed into. To "globally" set a style, see #my-link(, [Tips & Tricks -- Global Configuration]).
+
+ ],
+ width: 80%,
+)
+
+== Callout Types
+
+Callout types define the kind of callouts. As with the styles, the package comes with various predefined types and allows for user defined ones to be added.
+
+=== Predefined Types
+
+#raw(
+ lang: "example",
+ callout-types
+ .map(x => {
+ (
+ `#at.callout(type: "`.text
+ + x
+ + `",`.text
+ + " " * (calc.max(..callout-types.map(x => x.len())) - x.len())
+ + ` [])`.text
+ )
+ })
+ .join("\n"),
+ block: true,
+)
+
+=== Creating & Using Custom Callout Types
+
+To add custom callout types, the function #my-link(label("-new-type()"), `#new-type()`) is used. Calling this function places the configuration as a state at the call location, meaning you won't be able to use the type BEFORE the call. I recommend setting the types before the overall content!
+
+Each callout type has an "ID" associated to a couple of configurations: `color`, `icon` and `placeholder`. The term _placeholder_ is used, because the title of the callout is using a placeholder title when no title is specified!
+
+Now let's create a callout type #raw(`"pizza"`.text, lang: "typc"):
+
+#code-block(```typst
+#at.new-type(
+ name: "pizza",
+ color: red,
+ icon: [🍕],
+ placeholder: "Pizza Time!"
+)
+```)
+
+#let type-name = "pizza"
+#let paint = red
+#let icon = [🍕]
+#let placeholder = "Pizza Time!"
+
+#alertoni.new-type(
+ name: "pizza",
+ color: red,
+ icon: [🍕],
+ placeholder: "Pizza Time!",
+)
+
+
+With the type added, you can now create callouts and use #raw(`"pizza"`.text, lang: "typc") as type to use it.
+
+```example
+#at.callout(type: "pizza")[#lorem(10)]
+```
+
+#alertoni.callout(type: "important", width: auto, [
+ `#new-type` will overwrite existing entries.
+])
+
+== Language Context
+
+The predefined types and, if configured, user defined types can have language specific titles. These get automatically selected when setting the respective language via #raw(`#set text(lang: "..."))`.text, lang: "typst").
+
+#alertoni.callout(
+ type: "caution",
+ width: auto,
+ [If no title is found, `#callout` will throw an error, unless a #box(stroke: gray + 0.5pt, outset: (y: 0.3em), inset: (x: 0.2em), radius: 0.2em, `fallback`) entry exists!],
+)
+
+#code-block({
+ show "cal!lout": "cal" + sym.zwj + "lout"
+ ```typst
+ #let type-name = "pizza"
+ #let paint = red
+ #let icon = [🍕]
+ #let placeholder = (
+ fallback: "Pizza Time?" // required if other languages besides the ones below are used
+ en: "Pizza Time!",
+ de: "Pizza Zeit!"
+ )
+
+ #at.new-type(
+ name: type-name,
+ color: paint,
+ icon: icon,
+ placeholder: placeholder
+ )
+ ```
+})
+
+#let type-name = "pizza"
+#let paint = red
+#let icon = [🍕]
+#let placeholder = (
+ en: "Pizza Time!",
+ de: "Pizza Zeit!",
+ fallback: "Pizza Time?",
+)
+
+#alertoni.new-type(
+ name: type-name,
+ color: paint,
+ icon: icon,
+ placeholder: placeholder,
+)
+
+With the type added, you can now create callouts and use #raw(`"pizza"`.text, lang: "typc") as type to use it. Since the placeholder has translations, the callout function will try to select the respective one.
+
+#colbreak()
+
+```example
+#set text(lang: "en")
+#at.callout(type: "pizza")[#lorem(6)]
+
+#set text(lang: "de")
+#at.callout(type: "pizza", [#lorem(6)])
+
+#set text(lang: "es")
+#at.callout(type: "pizza", lorem(6))
+```
+
+
+== Modifying the Icon Set
+
+Per default #emph(package-name) uses the package #my-link("https://typst.app/universe/package/tableau-icons/")[`tableau-icons`] for drawing the icons in the callout. This is internally done via a lookup table (LUT), where each style is assigned an icon as `content`. This of course can be changed via the `#set-icons` function.
+
+```example
+#let icon-set = (
+ "info": [*i*],
+ "warning": [*!*],
+ "important": [*!!!*],
+)
+
+#at.set-icons(icon-set)
+
+#at.callout(type: "info", [])
+#at.callout(type: "warning", [])
+#at.callout(type: "important", [])
+```
+
+#alertoni.set-icons(auto)
+
+#alertoni.callout(
+ type: "info",
+ width: auto,
+ [
+ When setting icons, existing entries in the internal dictionary\ are updated and new entries are appended.
+ ],
+)
+
+#let icon-set = (
+ "info": [*i*],
+ "warning": [*!*],
+ "important": [*!!!*],
+)
+#alertoni.set-icons(icon-set)
+
+The `#set-icons` function also supports reseting the icons back to default by passing #raw("auto", lang: "typc"). This also clears #text(red, [all]) user defined icons.
+
+```example
+#at.callout(type: "info", [])
+#at.set-icons(auto)
+#at.callout(type: "info", [])
+```
+
+#pagebreak()
+
+= Tips & Tricks
+
+== Global Configuration
+
+To globally change the callout style, default type, you can overload the `#callout` function using #raw(`#at.callout.with(..)`.text, lang: "typst"):
+
+```example
+#let quarto-tip = at.callout.with(style: "quarto", type: "tip")
+
+#quarto-tip[Hello!]
+```
+
+#alertoni.callout(type: "caution", width: 80%)[
+ If you have a multi file project, place it in a "preamble" file, that gets imported in every subdocument that requires callouts.
+]
+
+#alertoni.callout(type: "important", width: 80%)[
+ The reason for this kind of implementation is, that I don't want to use custom type packages like #my-link("https://typst.app/universe/package/elembic/", `elembic`) (for now), as I'm waiting for Typst to officially support custom types.
+
+
+ It's not the best solution, but a useable workaround until Typst supports custom types. Once these are added, the callout configuration will be configurable via (hopefully):
+
+ #code-block(```typst
+ #set at.callout(style: my-style, type: "tip")
+ ```)
+]
+
+
+== Writing Shortcut
+
+To make writing a bit easier or flow nicer, the `#callout` function has a little trick up its sleeve using positonal arguments. By passing an additional positional argument, the first one will be used for the title and the second one as body.
+
+#align(center, table(
+ stroke: 0.5pt,
+ align: (center, left),
+ columns: 2,
+ table.header(strong[$\#$ of `pos()`], strong[Effect]),
+ [$1$], [`[0]`: Body of callout],
+ [$2$], [`[0]`: Title of callout\ `[1]`: Body of callout],
+ [$"otherwise"$], [Error is thrown],
+))
+
+The argument switchup was done to make it easier to read the code line. When reading callouts, usually title is read first, then body.
+
+```example
+#at.callout[No shorthand version]
+
+#at.callout[Shorthand][Version!]
+```
+
+#pagebreak()
+
+== Function Shortcuts
+
+Another handy use of #raw(`#at.callout.with(..)`.text, lang: "typst") is to create functions for each callout type. For a #raw(`#info`.text, lang: "typst") callout function, you'd declare
+
+```example
+#let info = at.callout.with(type:"info")
+
+#info(title: [Lorem Ipsum!])[#lorem(10)]
+```
+
+Function shortcuts were not implemented in the package, as it might conflict with functions in your document. But to make life a bit easier, below are all the predefined types as functions you can copy into your project!
+
+#code-block(inset: 1em, raw(
+ block: true,
+ lang: "typst",
+ `#import "@preview/alertoni:1.0.0" as at`.text
+ + "\n\n"
+ + callout-types
+ .map(t => {
+ str(`#let = at.callout.with(type: "")`.text.replace("", t))
+ })
+ .join("\n"),
+))
+
+#pagebreak()
+
+= API Reference
+
+#alertoni.set-icons(auto) // just so docs are clean of any modifications!
+#let docs = tidy.parse-module(read("../src/callouts.typ"), scope: (
+ at: alertoni,
+ tytyp: tytyp,
+ code-block: code-block,
+ burger-image: image.with("./images/burger.png"),
+))
+
+#context outline(target: heading.where(level: 2).after(here()), title: none)
+#v(2em)
+
+#tidy.show-module(docs, style: tidy.styles.default, first-heading-level: 1, show-outline: false)
+
+
+= Changelog
+
+
+#show heading.where(level: 2): set heading(numbering: none, outlined: false)
+#show heading.where(level: 2): it => {
+ show regex(`\d\.\d\.\d`.text): set text(blue)
+ show regex(`\\`.text): set text(gray, weight: "regular")
+
+ it
+}
+
+== 1.0.0 \\ Initial Release
+
+- Added functions `#callout`, `#new-type`, `#set-icons` with documentation!
diff --git a/packages/preview/alertoni/1.0.0/exports.typ b/packages/preview/alertoni/1.0.0/exports.typ
new file mode 100644
index 0000000000..f139d6feb5
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/exports.typ
@@ -0,0 +1 @@
+#import "src/callouts.typ": callout, new-type, set-icons
\ No newline at end of file
diff --git a/packages/preview/alertoni/1.0.0/src/callouts.typ b/packages/preview/alertoni/1.0.0/src/callouts.typ
new file mode 100755
index 0000000000..f3dd4237f3
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/src/callouts.typ
@@ -0,0 +1,452 @@
+#import "predefined.typ": default-callout-types, default-icon-set
+#import "@preview/tableau-icons:0.344.0": ti-icon
+
+#let icon-state = state("alertoni-icon-state", default-icon-set)
+#let callout-types = state("callout-types", default-callout-types)
+
+
+
+#let radius = 3pt
+#let inset = (top: 8pt, rest: 6pt)
+
+#let callout-styles = (
+ "minimal": (title, icon, content, paint, height, width) => align(
+ center,
+ block(
+ above: 1.5em,
+ below: 1.5em,
+ width: width,
+ height: height,
+ stroke: paint + 0.5pt,
+ inset: inset,
+ radius: radius,
+ {
+ set align(left)
+ // title block
+
+ if icon != none or title != none {
+ place(top + left, dy: -inset.top - 0.5em, dx: -1pt, box(
+ fill: white,
+ inset: if icon == none {
+ (x: 2pt)
+ } else if title == none {
+ (x: 0pt)
+ } else {
+ (left: 1pt, right: 2pt)
+ },
+ outset: (y: 1pt),
+ grid(
+ align: center + horizon,
+ ..if icon != none and title != none { (column-gutter: 0.2em) },
+ columns: if icon == none or title == none {
+ auto
+ } else {
+ (1em, auto)
+ }, rows: 1em,
+ ..(
+ if icon != none {
+ (text(paint, icon),)
+ }
+ + if title != none {
+ (text(weight: "bold", paint, title),)
+ }
+ )
+ ),
+ ))
+ }
+ content
+ },
+ ),
+ ),
+ // inline version
+ "compact": (title, icon, content, paint, _, _) => {
+ let inset = 0.3em
+
+ (
+ box(
+ fill: paint.lighten(85%),
+ outset: inset,
+ radius: inset,
+ baseline: inset / 2,
+ grid(
+ rows: 1em,
+ columns: (1em,) * int(icon != none) + (auto,) * int(title != none), align: horizon, gutter: inset,
+ ..if icon != none {
+ (text(paint, icon),)
+ },
+ ..if title != none {
+ (text(strong(title), rgb("#343a40")),)
+ }
+ ),
+ )
+ + h(2 * inset)
+ + content
+ )
+ },
+ // the callout styling from the extended Markdown format "Quarto" (https://quarto.org/docs/authoring/callouts.html)
+ "quarto": (title, icon, content, paint, height, width) => {
+ let column-count = if title == none or icon == none {
+ 1
+ } else if title != none and icon != none {
+ 2
+ }
+
+ align(
+ center,
+ block(
+ width: width,
+ height: height,
+ stroke: (left: paint + 3pt, rest: paint + 0.5pt),
+ radius: 3pt,
+ clip: true,
+ inset: (left: 1.5pt, right: 0.25pt),
+ grid(
+ rows: (1.5em, height),
+ fill: (x, y) => if y == 0 { paint.lighten(85%) } else { none },
+ ..if column-count == 2 {(
+ columns: (1.5em, 1fr),
+ align: (center + horizon, left + horizon)
+ )} else {(
+ columns: (1fr),
+ align: (left + horizon),
+ inset: (left: 0.25em)
+ )},
+ ..if icon != none {
+ (
+ text(paint, icon),
+ )
+ },
+ ..if title != none {
+ (
+ text(strong(title), rgb("#343a40")),
+ )
+ },
+ grid.cell(colspan: column-count, align: left + top, block(
+ width: 100%,
+ content,
+ inset: 0.5em,
+ )),
+ ),
+ ),
+ )
+ },
+)
+
+
+
+
+
+#let callout-invalid-type = (
+ color: gray,
+ placeholder: (de: "Kein Zugehöriger Titel", en: "No Associated Title"),
+)
+
+
+///
+/// #example(`#at.callout(title: [Title], [Content])`, scale-preview: 100%)
+///
+/// #example(`#at.callout([Content with automatic Title])`, scale-preview: 100%)
+///
+///
+/// -> content
+#let callout(
+ /// #let types = ("info", "warning", "important", "tip", "caution", "correct", "incorrect", "example")
+ ///
+ /// Type of the callout. Predefined styles are #types.map(x => raw(`"`.text + x + `"`.text, lang: "typc")).join([, ]).
+ ///
+ /// If user defined types have been set via #link(label("-new-type()"),`#new-type`), can also contain the respective type name.
+ ///
+ /// #example(```
+ /// #at.callout(type: "info", lorem(5))
+ ///
+ /// #at.callout(type: "caution", lorem(5))
+ ///
+ /// #at.callout(type: "tip", lorem(5))
+ /// ```, scale-preview: 100%)
+ ///
+ /// -> string
+ type: "info",
+
+ /// Rendering style of the callout. Predefined styles are #raw(lang:"typc", `"minimal"`.text), #raw(lang:"typc", `"compact"`.text) and #raw(lang:"typc", `"minimal"`.text).
+ ///
+ /// #example(```
+ /// #at.callout(style: "minimal", lorem(5))
+ /// #at.callout(style: "quarto", lorem(5))
+ /// #at.callout(style: "compact", lorem(5))
+ /// ```, scale-preview: 100%)
+ ///
+ ///
+ /// Passing a function in the shape of
+ ///
+ /// #{
+ /// show raw: set text(1.15em)
+ /// code-block(```typc
+ /// (title, icon, content, paint, height, width) => {...}
+ /// ```)
+ /// }
+ ///
+ /// allows for a user defined style.
+ ///
+ /// #example(```
+ /// #at.callout(style:
+ /// (title,_,body,paint,_,_) => {
+ /// [*#text(paint, title)* #body]
+ /// },
+ /// lorem(5)
+ /// )
+ /// ```, scale-preview: 100%)
+ ///
+ ///
+ /// -> string | function
+ style: "minimal",
+
+ /// Title of the callout.
+ ///
+ /// When set to #raw(`auto`.text,lang:"typc") the title is automatically chosen from the (user- or pre-) assigned placeholder title.
+ ///
+ /// When set to #raw(`none`.text,lang:"typc"), hides title. If set to anything else, callout title is overwritten. *This applies but is not limited to the predefined styles.*
+ ///
+ /// #example(```
+ /// #at.callout(icon: auto, lorem(5))
+ ///
+ /// #at.callout(icon: [i], lorem(5))
+ ///
+ ///
+ /// #at.callout(icon: none, lorem(5))
+ /// ```, scale-preview: 100%)
+ ///
+ ///
+ /// -> auto | none |
+ title: auto,
+
+ /// Width of the callout, but depends on the style. Style #raw(`"compact"`.text,lang: "typc") for
+ /// example ignores this parameter.
+ ///
+ /// -> auto | relative | fraction
+ width: 100%,
+
+ /// Height of the callout, but depends on the style. Style #raw(`"compact"`.text,lang: "typc") for
+ /// example ignores this parameter.
+ ///
+ /// -> auto | relative | fraction
+ height: auto,
+
+ /// The icon of the callout. Per default the icon is automatically selected from
+ /// the respective type configuration. Passing anything that can render as content,
+ /// overwrites the "default" icon.
+ ///
+ /// When set to #raw(`none`.text,lang:"typc"), does not render any icons. *This applies but is not limited to the predefined styles.*
+ ///
+ /// #example(```
+ /// #at.callout(icon: auto, lorem(5))
+ ///
+ /// #at.callout(icon: [i], lorem(5))
+ ///
+ ///
+ /// #at.callout(icon: none, lorem(5))
+ /// ```, scale-preview: 100%)
+ ///
+ /// -> content | auto
+ icon: auto,
+
+ /// The color of the callout. Per default the color is automatically selected from
+ /// the respective type configuration. Passing a color, overwrites the "default"
+ /// color.
+ ///
+ /// #example(```
+ /// #at.callout(color: auto, lorem(5))
+ ///
+ ///
+ /// #at.callout(color: purple, lorem(5))
+ /// ```, scale-preview: 100%)
+ ///
+ /// -> color | auto
+ color: auto,
+
+ /// The body of the calloutm, *IF* only one position item is passed. If two
+ /// position items are passed, the first item is the callout, the second one
+ /// is the callout body.
+ ///
+ /// #example(```
+ /// #at.callout[No shorthand version]
+ /// #at.callout[Shorthand][Version!]
+ /// ```, scale-preview: 100%)
+ ///
+ /// This improves writing callouts slightly, as in doesn't break writing flow as much.
+ ..content,
+) = context {
+ assert(
+ (std.type(style) == function) or (std.type(style) == str and style in (callout-styles.keys())),
+ message: "`style` is neither a function or of a valid string: \"minimal\", \"compact\", \"quarto\".",
+ )
+ assert(
+ content.pos().len() <= 2,
+ message: "Only one (for content only) or two (for [0] title and [1] content) positonal arguments are accepted!",
+ )
+
+ let types = callout-types.get()
+ let icon-state = icon-state.get()
+
+ assert(
+ type in types.keys() and type in icon-state.keys(),
+ message: "The callout type '"
+ + type
+ + "' doesn't exist in either type collection or icon set. Have forgotten to add it via 'alertoni.new-type' or 'alertoni.set-icons'?",
+ )
+ let config = callout-types.get().at(type)
+
+ let color = if color == auto { config.color } else { color }
+ let icon = if icon == auto { icon-state.at(type) } else { icon }
+
+ let title = if content.pos().len() == 2 {
+ content.pos().first()
+ } else if title == auto {
+ if std.type(config.placeholder) == dictionary {
+ assert(
+ text.lang in config.placeholder or "fallback" in config.placeholder,
+ message: "No callout title for language '"
+ + text.lang
+ + "' found. Did you forget to add it or a 'fallback' entry?",
+ )
+
+ let key = if text.lang not in config.placeholder { "fallback" } else { text.lang }
+
+ config.placeholder.at(key) // the user has to deal with the correct fallback on their own.
+ } else {
+ config.placeholder
+ }
+ } else {
+ title
+ }
+
+ let content = if content.pos().len() == 2 {
+ content.pos().last()
+ } else {
+ content.pos().first()
+ }
+
+ if std.type(style) == function {
+ // calls custom function
+ return style(title, icon, content, color, height, width)
+ } else {
+ // Callout Library predefined styles
+ return (callout-styles.at(style))(title, icon, content, color, height, width)
+ }
+}
+
+/// Configures the icons by passing a dictionary, which assigns a content value to the respective callout type.
+///
+/// #example(```
+/// #let new-set = (
+/// "info": [*i*],
+/// "warning": burger-image(width: 100%)
+/// )
+/// #at.set-icons(new-set)
+/// #at.callout(type: "info", [Hello])
+/// #at.callout(type: "warning", [World])
+///
+/// #at.set-icons(auto)
+/// #at.callout(type: "info", [Hello])
+/// #at.callout(type: "warning", [World])
+/// ```, scale-preview: 100%)
+///
+#let set-icons(
+ /// Passing a dictionary in the format of `( : , ...)`, allows you to add or overwrite the icon assignments for specific callout types.
+ ///
+ ///
+ /// Passing #raw(`auto`.text,lang:"typc"), resets all the default types.\
+ /// Passing #raw(`none`.text,lang:"typc"), resets all the default types *and* clears entries of user defined types.
+ ///
+ /// -> dictionary | auto | none
+ new-set,
+) = {
+ icon-state.update(x => {
+ if new-set == auto {
+ // reset default, keep user defined
+ return x + default-icon-set
+ } else if new-set == none {
+ // reset and clear
+ return default-icon-set
+ }
+
+ return x + new-set // add/overwrite new items
+ })
+}
+
+
+/// #example(```
+/// #at.new-type(
+/// name: "test",
+/// color: red,
+/// icon: text(0.8em)[#emoji.croissant],
+/// placeholder: (
+/// fallback: "Title?",
+/// en: "A Title",
+/// de: "Ein Titel"
+/// )
+/// )
+///
+/// #set text(lang: "en")
+/// #at.callout(type: "test", [In English])
+///
+/// #set text(lang: "de")
+/// #at.callout(type: "test", [In Deutsch])
+///
+/// #set text(lang: "fr")
+/// #at.callout(type: "test", [En français?])
+/// ```, scale-preview: 100%)
+///
+/// -> none
+#let new-type(
+ /// Name of the new callout type which is also to be used in the #link(label("-callout()"),`#callout`) function.
+ /// -> str
+ name: none,
+
+ /// The color of the callout. Depends on the style on how it is used.
+ ///
+ /// -> color
+ color: none,
+
+ /// The icon to be associated with the callout. Everything not #raw(lang: "typc", `none`.text)
+ /// will be added to the icon-set via #link(label("-set-icons()"),`#set-icons()`). Passing
+ /// #raw(lang: "typc", `none`.text) skips this step.
+ ///
+ /// -> content | str | none
+ icon: none,
+
+ /// The fallback/automatic title used when no title is given when calling #link(label("-callout()"),`#callout`).
+ /// Passing a dictionary with the key-value shape of `( : )` allows for language dependent titles (for the languages in the dictionary).
+ ///
+ /// #at.callout(type: "important", width: 80%)[If a dictionary is used, #link(label("-callout()"), [\#callout]) will throw an error, if the respective title cannot be found.
+ ///
+ /// This can be circumvented via an #raw("\"fallback\"", lang: "typc") entry!
+ /// ]
+ ///
+ ///
+ /// -> dictionary | content | str
+ placeholder: none,
+) = {
+ assert(type(name) == str, message: "template name must be a string")
+ assert(type(color) == std.color, message: "'color' must be of type 'color'.")
+
+ assert(type(icon) in (content, str, symbol) or icon == none, message: "'icon' must be a type of content.")
+ assert(
+ type(placeholder) in (dictionary, content, str),
+ message: "config.placeholder must be either a string/content or a language dictionary '(en: \"..\", de: \"..\")'.",
+ )
+
+ if icon != none {
+ set-icons(((name, icon),).to-dict())
+ }
+
+ let config = (
+ color: color,
+ placeholder: placeholder,
+ )
+
+ callout-types.update(old => {
+ old.insert(name, config)
+ old
+ })
+}
+
diff --git a/packages/preview/alertoni/1.0.0/src/predefined.typ b/packages/preview/alertoni/1.0.0/src/predefined.typ
new file mode 100644
index 0000000000..2661631538
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/src/predefined.typ
@@ -0,0 +1,55 @@
+#import "@preview/tableau-icons:0.344.0": ti-icon
+
+#let ti-icon = ti-icon.with(top-edge: "bounds", bottom-edge: "bounds")
+
+// NOTE: the .with is only used, so additional configuraiton using .map can be done ==> .map(v => v()) IS REQUIRED!
+#let default-icon-set = (
+ "info": ti-icon.with("info-circle"),
+ "warning": ti-icon.with("alert-triangle"),
+ "important": ti-icon.with("exclamation-circle"),
+ "tip": ti-icon.with("bulb"),
+ "caution": ti-icon.with("traffic-cone"),
+ "correct": ti-icon.with("check"),
+ "incorrect": ti-icon.with("x"),
+ "example": ti-icon.with("tools"),
+).map(v => v(top-edge: "bounds", bottom-edge: "bounds"))
+
+
+
+
+#let default-callout-types = (
+ // quarto based callouts
+ info: (
+ color: rgb("#2780e3"),
+ placeholder: (de: "Information", en: "Information", fallback: "Information"),
+ ),
+ warning: (
+ color: rgb("#ff7518"),
+ placeholder: (de: "Warnung", en: "Warning", fallback: "Warning"),
+ ),
+ important: (
+ color: rgb("#ff0039"),
+ placeholder: (de: "Wichtig", en: "Important", fallback: "Important"),
+ ),
+ tip: (
+ color: rgb("#3fb618"),
+ placeholder: (de: "Tipp", en: "Tip", fallback: "Tip"),
+ ),
+ caution: (
+ color: rgb("#f0ad4e"),
+ placeholder: (de: "Vorsicht", en: "Caution", fallback: "Caution"),
+ ),
+ // my callouts
+ correct: (
+ color: green.darken(5%),
+ placeholder: (de: "Korrekt", en: "Correct", fallback: "Correct"),
+ ),
+ incorrect: (
+ color: red.darken(5%),
+ placeholder: (de: "Inkorrekt", en: "Incorrect", fallback: "Incorrect"),
+ ),
+ example: (
+ color: rgb("#966FD6"),
+ placeholder: (de: "Beispiel", en: "Example", fallback: "Example"),
+ ),
+)
\ No newline at end of file
diff --git a/packages/preview/alertoni/1.0.0/typst.toml b/packages/preview/alertoni/1.0.0/typst.toml
new file mode 100644
index 0000000000..9ae7affb23
--- /dev/null
+++ b/packages/preview/alertoni/1.0.0/typst.toml
@@ -0,0 +1,11 @@
+[package]
+name = "alertoni"
+version = "1.0.0"
+entrypoint = "exports.typ"
+authors = [ "Joel von Rotz "]
+license = "EUPL-1.2"
+description = "A package for callouts/alerts/alert boxes with support for custom styles & types."
+keywords = ["compact", "callouts", "custom callouts"]
+categories = ["components", "layout", "utility"]
+exclude = [ "docs", ".gitignore",]
+repository = "https://codeberg.org/joelvonrotz/typst-alertoni"