Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kinase 0.1.0 #590

Merged
merged 6 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/preview/kinase/0.1.0/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Lennart Schuster

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
27 changes: 27 additions & 0 deletions packages/preview/kinase/0.1.0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Kinave

Package for easy styling of links. See [Docs](docs/manual.pdf) for a detailed guide. Below is an example of the functionality that is added.
The problem the package solves is that different link types cannot be styled seperatly, but are recognized as such. This package allows for easy styling of phone numbers, urls and mail addresses. It provides helper functions that return regex patterns for the most common use cases.


```typ
#import "@previes/kinase:0.0.1"

#show: make-link

// Insert some rules
#update-link-style(key: l-mailto(), value: it => strong(it), )
#update-link-style(key: l-url(base: "typst\.app"), value: it => emph(it))
#update-link-style(key: l-url(base: "google\.com"), before: l-url(base: "typst\.app"), value: it => highlight(it))
#update-link-style(key: l-url(base: "typst\.app/docs"), value: it => strong(it), before: l-url(base: "typst\.app"))

#link("mailto:john.smith@typst.org") \

#link("https://www.typst.app/docs")

#link("typst.app")

#link("+49 2422424422")
```

![](ressources/example.png)
Binary file added packages/preview/kinase/0.1.0/docs/manual.pdf
Binary file not shown.
60 changes: 60 additions & 0 deletions packages/preview/kinase/0.1.0/docs/manual.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#import "@preview/mantys:0.1.1": *
#import "@preview/tidy:0.2.0": *

#show: mantys.with(
name: "Link-Style Manual",
version: "0.1.0",
authors: ("Lennart Schuster",),
examples-scope: none,
license: "MIT",
description: "This packages provides helpers for styling link.",
repository: "https://github.com/indicatelovelace/link-style",
title: "Link-Style",
subtitle: "Manual",
date: datetime.today(),
abstract: [
Link Style solves the problem of styling different types of links which are not directly selectable as subelements. This includes Phone Numbers, Mail Addresses and URLs.
],
examples: none,
)

== About

A common use case for this package is styling emails, phone addresses, document links and internet links differently. Another one is styling different websites differenty. This is particular useful for replacing links to common platforms with icons (Github, LinkedIn, etc.).

== Usage
To use this package, first you have to put
#codesnippet[```typ
#show: make-ref
...
```]
in your document.
You can add styling rules:
#codesnippet(```typ
// Shows strict mails strong
#update-link-style(key: mailto-strict, value: strong)

// Replace mails with emoji
#update-link-style(key: mailto, value: it => [#emoji.mail])
```)
Styling rules consist of a key and a value. The key is a regex or a string to match an expression. You can find helpers for common link formats in @h2:api. The value is a function that takes and returns content, just like you would use a closure in a common show rule. \
Care that the order of the rules is of importance. This is the order in which the matchers are applied. Therefor in the above example, valid mail addresses would be styled bold. Other ```typ mailto:``` links would be shown as #emoji.mail. Inserting the same regex again will replace the rule. \
In order to effectively use the order of the rules, you can also insert before or after an element. Care that you need to match the key:
#codesnippet(```typ
// Shows strict mails strong
#update-link-style(key: l-url(base: "typst.org", value: strong)
#update-link-style(key: l-url(base: "typst.org/docs", before: l-url(base: "typst.org"), value: emph)
```)
Now the docs page will be emph, instead of strong.

You can also remove a rule:
#codesnippet(```typ
#remove-link-style(key: mailto-strict)
```)
Now for every mail, that was matched by `mailto-strict` before would now be matched my `mailto`.

#pagebreak(weak: true)
== API reference <h2:api>

#let show-module(name, scope: (:), outlined: true) = tidy-module(read(name), name: name, show-outline: outlined, include-examples-scope: false, extract-headings: 0, tidy: none)
#show-module("../bib.typ")
114 changes: 114 additions & 0 deletions packages/preview/kinase/0.1.0/lib.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/// Helper for matching Mails. This one matches every 'mailto:' link
#let l-mailto() = regex("mailto:.*")
/// Helper for matching Mails. This one is more strict and matches only, if a mail is an address that is structurally correct.
#let l-mailto-strict() = regex("^mailto:.*@.*\..*")

/// Helper to match phone numbers. Note that these are country dependent.
///
/// - region (string): ISO 3166-1 alpha-2 region string. Currently supported are US, DE, FR, GB and limited to non mobile.
#let l-phone(region: "US") = {
if region == "US" {
return regex(`^(?:\+?1)?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$`.text)
} else if region == "DE" {
return regex(`^(?:\+?49)?[-.\s]?\(?(?:0|\d{2})\)?[-.\s]?\d{1,5}[-.\s]?\d{1,5}$`.text)
} else if region == "GB" {
return regex(`^(?:\+?44)?[-.\s]?\(?(?:0|\d{2})\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,4}$`.text)
} else if region == "FR" {
return regex(`^(?:\+?33)?[-.\s]?\(?(?:0|\d{1,2})\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,4}$`.text)
}
panic("Code invalid or not supported")
//TODO add more regions
}

/// Helper to match urls. Matches any well formed url around the base url. E.g. if base is 'google.com', 'https://google.com/docs' and 'http://google.com:8080' are matched as well.
///
/// - base (string): Base url of a hostname. This does not check the url for legality. Though if it is, only legal urls are matched. By default this matches any url like link. Care that you have to escape any symbols with special meaning (e.g. 'typst.app' #sym.arrow `regex("typst\.app")`)
#let l-url(base: ".*?\..*?") = {
regex(`^(https?://)?(www\.)?`.text + base + `([/][-a-zA-Z0-9@:%._\+~#=]{1,256})?(:\d{1,5})?`.text)
}

/// Array of tuples, consisting of the matcher and corresponding styling function. Care that the order of insertion is the order in which the matchers are evaluated. In practice, this means you should place the more specific matches above more generic ones.
#let link-style = state("now", ())

/// Update the styling array. Entries are inserted. If before and after are none, entries are appended to the end. If a key already exist, the entry is replaced. The order is kept intact.
///
/// - key (regex, string): Matcher for the dest field of th e link function. If the key is a string, it is matched if it is contained. If it is a regex expression, it is matched if the expression produces at least one match.
/// - value (function): A function that takes content and returns content.
/// - before (regex, string): Insert before another key. Excludes after.
/// - after (regex, string): Insert after another key. Excludes before.
/// -> none
#let update-link-style(key: none, value: none, before: none, after: none) = {
if before != none and after != none {
panic("before and after exclude each other!")
}
link-style.update(arr => {
let i = arr.map(e => e.at(0)).position(it => it == key)
if i == none {
if before != none {
let i = arr.map(e => e.at(0)).position(it => it == before)
if i == none {
panic("before key does not exist")
}
arr.insert(i, (key, value))
} else if after != none {
let i = arr.map(e => e.at(0)).position(it => it == after)
if i == none {
panic("after key does not exist")
}
if arr.len() == i {
arr.push((key, value))
} else {
arr.insert(i + 1, (key, value))
}
} else {
arr.push((key, value))
}
} else {
let f = arr.remove(i)
arr.insert(i, (key, value))
}
arr
})
none
}

/// Removes an entry from the link-style array, if it exists.
///
/// - key (regex, string): Matcher for the dest field of th e link function. If the key is a string, it is matched if it is contained. If it is a regex expression, it is matched if the expression produces at least one match.
/// -> none
#let remove-update-style(key: none) = {
link-style.update(arr => {
let i = arr.map(e => e.at(0)).position(it => it == key)
if i != none {
arr.remove(i)
}
arr
})
}


/// Function for creating applying the link-style.
///
/// - body (content): The document body.
#let make-link(body) = {
show link: it => {
context {
let state = link-style.final()
if type(it.dest) == "string" {
for p in state {
let match = p.at(0)
let match-type = type(match)
if match-type == "string" and it.dest.contains(match) {
return p.at(1)(it.body)
} else if match-type == "regex" {
if it.dest.match(match) != none {
return p.at(1)(it.body)
}
}
}
}
it
}
}
body
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions packages/preview/kinase/0.1.0/resources/example.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#import "@preview/kinase:0.1.0": *

#show: make-link

#update-link-style(key: l-mailto(), value: it => strong(it), )
#update-link-style(key: l-url(base: "typst\.app"), value: it => emph(it))
#update-link-style(key: l-url(base: "google\.com"), before: l-url(base: "typst\.app"), value: it => highlight(it))
#update-link-style(key: l-url(base: "typst\.app/docs"), value: it => strong(it), before: l-url(base: "typst\.app"))

#link("mailto:john.smith@typst.org") \

#link("https://www.typst.app/docs")

#link("typst.app")

#link("+49 2422424422")
9 changes: 9 additions & 0 deletions packages/preview/kinase/0.1.0/typst.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "kinase"
version = "0.1.0"
entrypoint = "lib.typ"
authors = ["Lennart Schuster"]
license = "MIT"
description = "Easy styling for different link types like mails and urls."
exclude = ["docs", "resources"]
keywords = ["utility", "languages"]