mirror of
https://github.com/tommilligan/mdbook-admonish.git
synced 2025-12-28 07:54:39 -05:00
Compare commits
7 Commits
fix-161
...
prep-1.15.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
467f5f8f13 | ||
|
|
c4a05dae9d | ||
|
|
1bb14684c4 | ||
|
|
b3798b4d9f | ||
|
|
26c344a1e6 | ||
|
|
b1e6a5ee1e | ||
|
|
0d7b64d1b8 |
6
.github/workflows/check.yml
vendored
6
.github/workflows/check.yml
vendored
@@ -96,6 +96,12 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
steps:
|
||||
# This is required, otherwise we get files with CRLF on Windows
|
||||
# Which causes tests relying on data loaded from files to fail
|
||||
- name: Set git to use LF everywhere
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
- name: Cache build files
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Changed
|
||||
## 1.15.0
|
||||
|
||||
- `additional-css` _UNIX_ style path normalization ([#161](https://github.com/tommilligan/mdbook-admonish/issues/161))
|
||||
### Added
|
||||
|
||||
- Support [custom directives](https://tommilligan.github.io/mdbook-admonish/overview.html#custom-blocks) with the new `mdbook-admonish generate-custom` helper. See the [mdbook-admonish book](https://tommilligan.github.io/mdbook-admonish/overview.html#custom-blocks) for guidance. Thanks to [@Sky9x](https://github.com/Sky9x) for helping design this feature! ([#165](https://github.com/tommilligan/mdbook-admonish/pull/165))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Typo from _prereprocessor_ to _preprocessor_
|
||||
- `additional-css` unix style path normalization. Thanks to [@carlocorradini](https://github.com/carlocorradini) for reporting and fixing! ([#163](https://github.com/tommilligan/mdbook-admonish/pull/163))
|
||||
|
||||
## 1.14.0
|
||||
|
||||
|
||||
31
CONTRIBUTING.md
Normal file
31
CONTRIBUTING.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Contributing
|
||||
|
||||
## Workflow
|
||||
|
||||
Please submit a PR from a **new branch** in your fork.
|
||||
Please do not submit a PR from your fork's `main` branch, as it makes collaborating on/editing the branch a pain.
|
||||
|
||||
## Project design
|
||||
|
||||
- Compiled CSS styles are built and committed from SCSS sources. See the `compile_assets` folder for details.
|
||||
- `mdbook-admonish install` is responsible for delivering additional assets and configuration to a client book.
|
||||
- `mdbook-admonish` is responsible for preprocessing book data, adding HTML that references compiled classnames.
|
||||
|
||||
## Scripts to get started
|
||||
|
||||
- `./scripts/install` installs other toolchains required for development
|
||||
- `./scripts/check` runs a full CI check
|
||||
- `./scripts/rebuild-book` rebuilds the reference book under `./book`. This is useful for integration testing locally.
|
||||
|
||||
## Making breaking changes in CSS
|
||||
|
||||
To make a breaking change in CSS, you should:
|
||||
|
||||
- Update the assets version in `./src/bin/assets/VERSION`
|
||||
- Update the required assets version specifier in `./src/REQUIRED_ASSETS_VERSION`
|
||||
|
||||
You must make the next `mdbook-admonish` crate version at least a **minor** version bump.
|
||||
|
||||
## Releasing
|
||||
|
||||
Github workflows are setup such that pushing a `vX.Y.Z` tag will trigger a release to be cut.
|
||||
20
Cargo.lock
generated
20
Cargo.lock
generated
@@ -109,6 +109,12 @@ version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@@ -625,6 +631,17 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||
|
||||
[[package]]
|
||||
name = "hex_color"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d37f101bf4c633f7ca2e4b5e136050314503dd198e78e325ea602c327c484ef0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"rand",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.26.0"
|
||||
@@ -952,11 +969,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mdbook-admonish"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"hex_color",
|
||||
"log",
|
||||
"mdbook",
|
||||
"once_cell",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-admonish"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.66.0"
|
||||
|
||||
@@ -30,8 +30,8 @@ anyhow = "1.0.75"
|
||||
# Note: clap 4.4 increases MSRV to 1.70.0 (2023-06-01)
|
||||
# To use MSRV supported dependencies, install using the lockfile with
|
||||
# `cargo install mdbook-admonish --locked`
|
||||
clap = { version = "4.3", default_features = false, features = ["std", "derive"], optional = true }
|
||||
env_logger = { version = "0.10", default_features = false, optional = true }
|
||||
clap = { version = "4.3", default-features = false, features = ["std", "derive"], optional = true }
|
||||
env_logger = { version = "0.10", default-features = false, optional = true }
|
||||
log = "0.4.20"
|
||||
mdbook = "0.4.35"
|
||||
once_cell = "1.18.0"
|
||||
@@ -46,6 +46,7 @@ serde_json = "1.0.107"
|
||||
toml_mdbook = { package = "toml", version = "0.5.11" }
|
||||
toml = "0.8.1"
|
||||
toml_edit = { version = "0.20.1", optional = true }
|
||||
hex_color = { version = "3.0.0", features = ["serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
|
||||
25
README.md
25
README.md
@@ -161,30 +161,7 @@ Guarantees provided are as follows:
|
||||
|
||||
## Development
|
||||
|
||||
Project design
|
||||
|
||||
- Compiled CSS styles are built and committed from SCSS sources. See the `compile_assets` folder for details.
|
||||
- `mdbook-admonish install` is responsible for delivering additional assets and configuration to a client book.
|
||||
- `mdbook-admonish` is responsible for preprocessing book data, adding HTML that references compiled classnames.
|
||||
|
||||
### Scripts to get started
|
||||
|
||||
- `./scripts/install` installs other toolchains required for development
|
||||
- `./scripts/check` runs a full CI check
|
||||
- `./scripts/rebuild-book` rebuilds the reference book under `./book`. This is useful for integration testing locally.
|
||||
|
||||
### Making breaking changes in CSS
|
||||
|
||||
To make a breaking change in CSS, you should:
|
||||
|
||||
- Update the assets version in `./src/bin/assets/VERSION`
|
||||
- Update the required assets version specifier in `./src/REQUIRED_ASSETS_VERSION`
|
||||
|
||||
You must make the next `mdbook-admonish` crate version at least a **minor** version bump.
|
||||
|
||||
### Releasing
|
||||
|
||||
Github workflows are setup such that pushing a `vX.Y.Z` tag will trigger a release to be cut.
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on developing.
|
||||
|
||||
## Thanks
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@ title = "The mdbook-admonish book"
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "3.0.1" # do not edit: managed by `mdbook-admonish install`
|
||||
|
||||
[[preprocessor.admonish.custom]]
|
||||
directive = "expensive"
|
||||
icon = "./money-bag.svg"
|
||||
color = "#24ab38"
|
||||
|
||||
[preprocessor.toc]
|
||||
command = "mdbook-toc"
|
||||
renderer = ["html"]
|
||||
@@ -18,4 +23,4 @@ renderer = ["html"]
|
||||
[output]
|
||||
|
||||
[output.html]
|
||||
additional-css = ["./mdbook-admonish.css"]
|
||||
additional-css = ["./mdbook-admonish.css", "./mdbook-admonish-custom.css"]
|
||||
|
||||
20
book/mdbook-admonish-custom.css
Normal file
20
book/mdbook-admonish-custom.css
Normal file
@@ -0,0 +1,20 @@
|
||||
:root {
|
||||
--md-admonition-icon--admonish-expensive: url("data:image/svg+xml;charset=utf-8,<svg width='800px' height='800px' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --><!-- ref: https://www.svgrepo.com/svg/526038/money-bag --><!-- Used under CC Attribution License; Author: Solar Icons --><path fill-rule='evenodd' clip-rule='evenodd' d='M12.052 1.25H11.948C11.0495 1.24997 10.3003 1.24995 9.70552 1.32991C9.07773 1.41432 8.51093 1.59999 8.05546 2.05546C7.59999 2.51093 7.41432 3.07773 7.32991 3.70552C7.27259 4.13189 7.25637 5.15147 7.25179 6.02566C5.22954 6.09171 4.01536 6.32778 3.17157 7.17157C2 8.34315 2 10.2288 2 14C2 17.7712 2 19.6569 3.17157 20.8284C4.34314 22 6.22876 22 9.99998 22H14C17.7712 22 19.6569 22 20.8284 20.8284C22 19.6569 22 17.7712 22 14C22 10.2288 22 8.34315 20.8284 7.17157C19.9846 6.32778 18.7705 6.09171 16.7482 6.02566C16.7436 5.15147 16.7274 4.13189 16.6701 3.70552C16.5857 3.07773 16.4 2.51093 15.9445 2.05546C15.4891 1.59999 14.9223 1.41432 14.2945 1.32991C13.6997 1.24995 12.9505 1.24997 12.052 1.25ZM15.2479 6.00188C15.2434 5.15523 15.229 4.24407 15.1835 3.9054C15.1214 3.44393 15.0142 3.24644 14.8839 3.11612C14.7536 2.9858 14.5561 2.87858 14.0946 2.81654C13.6116 2.7516 12.964 2.75 12 2.75C11.036 2.75 10.3884 2.7516 9.90539 2.81654C9.44393 2.87858 9.24644 2.9858 9.11612 3.11612C8.9858 3.24644 8.87858 3.44393 8.81654 3.9054C8.771 4.24407 8.75661 5.15523 8.75208 6.00188C9.1435 6 9.55885 6 10 6H14C14.4412 6 14.8565 6 15.2479 6.00188ZM12 9.25C12.4142 9.25 12.75 9.58579 12.75 10V10.0102C13.8388 10.2845 14.75 11.143 14.75 12.3333C14.75 12.7475 14.4142 13.0833 14 13.0833C13.5858 13.0833 13.25 12.7475 13.25 12.3333C13.25 11.9493 12.8242 11.4167 12 11.4167C11.1758 11.4167 10.75 11.9493 10.75 12.3333C10.75 12.7174 11.1758 13.25 12 13.25C13.3849 13.25 14.75 14.2098 14.75 15.6667C14.75 16.857 13.8388 17.7155 12.75 17.9898V18C12.75 18.4142 12.4142 18.75 12 18.75C11.5858 18.75 11.25 18.4142 11.25 18V17.9898C10.1612 17.7155 9.25 16.857 9.25 15.6667C9.25 15.2525 9.58579 14.9167 10 14.9167C10.4142 14.9167 10.75 15.2525 10.75 15.6667C10.75 16.0507 11.1758 16.5833 12 16.5833C12.8242 16.5833 13.25 16.0507 13.25 15.6667C13.25 15.2826 12.8242 14.75 12 14.75C10.6151 14.75 9.25 13.7903 9.25 12.3333C9.25 11.143 10.1612 10.2845 11.25 10.0102V10C11.25 9.58579 11.5858 9.25 12 9.25Z' fill='%231C274C'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition):is(.admonish-expensive) {
|
||||
border-color: #24ab38;
|
||||
}
|
||||
|
||||
:is(.admonish-expensive) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(36, 171, 56, 0.1);
|
||||
}
|
||||
:is(.admonish-expensive) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #24ab38;
|
||||
mask-image: var(--md-admonition-icon--admonish-expensive);
|
||||
-webkit-mask-image: var(--md-admonition-icon--admonish-expensive);
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
}
|
||||
6
book/money-bag.svg
Normal file
6
book/money-bag.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<!-- ref: https://www.svgrepo.com/svg/526038/money-bag -->
|
||||
<!-- Used under CC Attribution License; Author: Solar Icons -->
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.052 1.25H11.948C11.0495 1.24997 10.3003 1.24995 9.70552 1.32991C9.07773 1.41432 8.51093 1.59999 8.05546 2.05546C7.59999 2.51093 7.41432 3.07773 7.32991 3.70552C7.27259 4.13189 7.25637 5.15147 7.25179 6.02566C5.22954 6.09171 4.01536 6.32778 3.17157 7.17157C2 8.34315 2 10.2288 2 14C2 17.7712 2 19.6569 3.17157 20.8284C4.34314 22 6.22876 22 9.99998 22H14C17.7712 22 19.6569 22 20.8284 20.8284C22 19.6569 22 17.7712 22 14C22 10.2288 22 8.34315 20.8284 7.17157C19.9846 6.32778 18.7705 6.09171 16.7482 6.02566C16.7436 5.15147 16.7274 4.13189 16.6701 3.70552C16.5857 3.07773 16.4 2.51093 15.9445 2.05546C15.4891 1.59999 14.9223 1.41432 14.2945 1.32991C13.6997 1.24995 12.9505 1.24997 12.052 1.25ZM15.2479 6.00188C15.2434 5.15523 15.229 4.24407 15.1835 3.9054C15.1214 3.44393 15.0142 3.24644 14.8839 3.11612C14.7536 2.9858 14.5561 2.87858 14.0946 2.81654C13.6116 2.7516 12.964 2.75 12 2.75C11.036 2.75 10.3884 2.7516 9.90539 2.81654C9.44393 2.87858 9.24644 2.9858 9.11612 3.11612C8.9858 3.24644 8.87858 3.44393 8.81654 3.9054C8.771 4.24407 8.75661 5.15523 8.75208 6.00188C9.1435 6 9.55885 6 10 6H14C14.4412 6 14.8565 6 15.2479 6.00188ZM12 9.25C12.4142 9.25 12.75 9.58579 12.75 10V10.0102C13.8388 10.2845 14.75 11.143 14.75 12.3333C14.75 12.7475 14.4142 13.0833 14 13.0833C13.5858 13.0833 13.25 12.7475 13.25 12.3333C13.25 11.9493 12.8242 11.4167 12 11.4167C11.1758 11.4167 10.75 11.9493 10.75 12.3333C10.75 12.7174 11.1758 13.25 12 13.25C13.3849 13.25 14.75 14.2098 14.75 15.6667C14.75 16.857 13.8388 17.7155 12.75 17.9898V18C12.75 18.4142 12.4142 18.75 12 18.75C11.5858 18.75 11.25 18.4142 11.25 18V17.9898C10.1612 17.7155 9.25 16.857 9.25 15.6667C9.25 15.2525 9.58579 14.9167 10 14.9167C10.4142 14.9167 10.75 15.2525 10.75 15.6667C10.75 16.0507 11.1758 16.5833 12 16.5833C12.8242 16.5833 13.25 16.0507 13.25 15.6667C13.25 15.2826 12.8242 14.75 12 14.75C10.6151 14.75 9.25 13.7903 9.25 12.3333C9.25 11.143 10.1612 10.2845 11.25 10.0102V10C11.25 9.58579 11.5858 9.25 12 9.25Z" fill="#1C274C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -170,7 +170,7 @@ The default id is a normalized version of the admonishment's title,
|
||||
prefixed with the `default.css_id_prefix`,
|
||||
with an appended number if multiple blocks would have the same id.
|
||||
|
||||
Setting the `id` field will *ignore* all other ids and the duplicate counter.
|
||||
Setting the `id` field will _ignore_ all other ids and the duplicate counter.
|
||||
|
||||
````
|
||||
```admonish info title="My Info" id="my-special-info"
|
||||
@@ -194,3 +194,46 @@ Will yield something like the following HTML, which you can then apply styles to
|
||||
Content will be hidden initially.
|
||||
```
|
||||
|
||||
### Custom blocks
|
||||
|
||||
You can add new block types via the `book.toml` config:
|
||||
|
||||
```toml
|
||||
# book.toml
|
||||
|
||||
[[preprocessor.admonish.custom]]
|
||||
directive = "expensive"
|
||||
icon = "./money-bag.svg"
|
||||
color = "#24ab38"
|
||||
aliases = ["money", "cash", "budget"]
|
||||
```
|
||||
|
||||
You must then generate the relevant CSS file, and reference it in the `output.html` section.
|
||||
`mdbook-admonish` has a helper to quickly do this for you:
|
||||
|
||||
```bash
|
||||
# Generates a file at ./mdbook-admonish-custom.css with your styles in
|
||||
$ mdbook-admonish generate-custom ./mdbook-admonish-custom.css
|
||||
```
|
||||
|
||||
```toml
|
||||
# book.toml
|
||||
|
||||
[output.html]
|
||||
# Reference the new file, so it's bundled in with book styles
|
||||
additional-css = ["./mdbook-admonish.css", "./mdbook-admonish-custom.css"]
|
||||
```
|
||||
|
||||
You can then reference the new directive (or alias) like usual in your blocks.
|
||||
|
||||
````
|
||||
```admonish expensive
|
||||
Remember, this operation costs money!
|
||||
```
|
||||
````
|
||||
|
||||
```admonish expensive
|
||||
Remember, this operation costs money!
|
||||
```
|
||||
|
||||
You can also set a default `title`. See the [Reference](./reference.md) page for more details.
|
||||
|
||||
@@ -75,6 +75,31 @@ Subfields:
|
||||
- For the `html` renderer, the default value is `html`.
|
||||
- For all other renderers, the default value is `preserve`.
|
||||
|
||||
### `custom`
|
||||
|
||||
Optional.
|
||||
|
||||
Additional type of block to support.
|
||||
You must run `mdbook-admonish generate-custom` after updating these values, to generate the correct styles.
|
||||
|
||||
Add blocks using TOML's [Array of Tables](https://toml.io/en/v1.0.0#array-of-tables) notation:
|
||||
|
||||
```toml
|
||||
[[preprocessor.admonish.custom]]
|
||||
directive = "expensive"
|
||||
icon = "./money-bag.svg"
|
||||
color = "#24ab38"
|
||||
aliases = ["money", "cash", "budget"]
|
||||
```
|
||||
|
||||
Subfields:
|
||||
|
||||
- `directive`: The keyword to use this type of block.
|
||||
- `icon`: A filepath relative to the book root to load an SVG icon from.
|
||||
- `color`: An RGB hex encoded color to use for the icon.
|
||||
- `aliases` (optional): One or more alternative directives to use this block.
|
||||
- `title` (optional): The default title for this type of block. If not specified, defaults to the directive in title case. To give each alias a custom title, add multiple custom blocks.
|
||||
|
||||
### `command`
|
||||
|
||||
Required.
|
||||
@@ -93,6 +118,8 @@ This is automatically updated by `mdbook-admonish install` and should not be edi
|
||||
|
||||
All supported directives are listed below.
|
||||
|
||||
Custom directives can be added via the `custom` config option above.
|
||||
|
||||
`note`
|
||||
|
||||
```admonish note
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "sass --no-source-map scss/mdbook-admonish.scss ../src/bin/assets/mdbook-admonish.css",
|
||||
"build": "yarn run build-prod && yarn run build-custom-expected",
|
||||
"build-prod": "sass --no-source-map scss/mdbook-admonish.scss ../src/bin/assets/mdbook-admonish.css",
|
||||
"build-custom-expected": "sass --no-source-map scss/mdbook-admonish-custom-expected.scss ../src/test_data/mdbook-admonish-custom-expected.css",
|
||||
"lint": "prettier --check .",
|
||||
"fix": "prettier --write ."
|
||||
},
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
@use "sass:color";
|
||||
@use "sass:list";
|
||||
@use "./lib";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Variables
|
||||
@@ -68,17 +69,9 @@ $admonitions: (
|
||||
) !default;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Rules: layout
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Admonition variables
|
||||
:root {
|
||||
@each $names, $props in $admonitions {
|
||||
--md-admonition-icon--#{nth($names, 1)}: url("data:image/svg+xml;charset=utf-8,#{nth($props, 2)}");
|
||||
}
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
// Static content - base for all admonitions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Admonition
|
||||
@@ -231,48 +224,20 @@ summary.admonition-title {
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Rules: flavours
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@each $names, $props in $admonitions {
|
||||
$name: list.nth($names, 1);
|
||||
$tint: list.nth($props, 1);
|
||||
|
||||
// Admonition flavour selectors
|
||||
$flavours: ();
|
||||
|
||||
@each $name in $names {
|
||||
$flavours: list.join($flavours, ".#{$name}", $separator: comma);
|
||||
}
|
||||
|
||||
// Admonition flavour
|
||||
:is(.admonition):is(#{$flavours}) {
|
||||
border-color: $tint;
|
||||
}
|
||||
|
||||
// Admonition flavour title
|
||||
:is(#{$flavours}) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: color.adjust($tint, $alpha: -0.9);
|
||||
|
||||
// Admonition icon
|
||||
&::before {
|
||||
background-color: $tint;
|
||||
mask-image: var(--md-admonition-icon--#{$name});
|
||||
-webkit-mask-image: var(--md-admonition-icon--#{$name});
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
:root {
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
// Generate rules for each specified admonition variant
|
||||
@include lib.from-admonitions($admonitions);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Rules: themes
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// One rule per builtin theme in mdbook, overriding the default fg/bg if matched
|
||||
//
|
||||
// This must be after the variant CSS, so it can override they styles set there
|
||||
|
||||
.navy {
|
||||
& :is(.admonition) {
|
||||
|
||||
52
compile_assets/scss/lib.scss
Normal file
52
compile_assets/scss/lib.scss
Normal file
@@ -0,0 +1,52 @@
|
||||
@use "sass:color";
|
||||
@use "sass:list";
|
||||
|
||||
@mixin from-admonitions($admonitions) {
|
||||
// ----------------------------------------------------------------------------
|
||||
// Rules: layout
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Admonition variables
|
||||
:root {
|
||||
@each $names, $props in $admonitions {
|
||||
--md-admonition-icon--#{nth($names, 1)}: url("data:image/svg+xml;charset=utf-8,#{nth($props, 2)}");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Rules: flavours
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@each $names, $props in $admonitions {
|
||||
$name: list.nth($names, 1);
|
||||
$tint: list.nth($props, 1);
|
||||
|
||||
// Admonition flavour selectors
|
||||
$flavours: ();
|
||||
|
||||
@each $name in $names {
|
||||
$flavours: list.join($flavours, ".#{$name}", $separator: comma);
|
||||
}
|
||||
|
||||
// Admonition flavour
|
||||
:is(.admonition):is(#{$flavours}) {
|
||||
border-color: $tint;
|
||||
}
|
||||
|
||||
// Admonition flavour title
|
||||
:is(#{$flavours}) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: color.adjust($tint, $alpha: -0.9);
|
||||
|
||||
// Admonition icon
|
||||
&::before {
|
||||
background-color: $tint;
|
||||
mask-image: var(--md-admonition-icon--#{$name});
|
||||
-webkit-mask-image: var(--md-admonition-icon--#{$name});
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
compile_assets/scss/mdbook-admonish-custom-expected.scss
Normal file
16
compile_assets/scss/mdbook-admonish-custom-expected.scss
Normal file
@@ -0,0 +1,16 @@
|
||||
// This file aims to generate the subset of CSS specific to a single admonition directive.
|
||||
//
|
||||
// This is used for unit test data in the rust css generation module.
|
||||
|
||||
@use "sass:color";
|
||||
@use "sass:list";
|
||||
@use "./lib";
|
||||
@import "./material-color";
|
||||
|
||||
$admonitions: (
|
||||
admonish-note: $clr-blue-a200
|
||||
"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>",
|
||||
) !default;
|
||||
|
||||
// Generate rules for each specified admonition variant
|
||||
@include lib.from-admonitions($admonitions);
|
||||
@@ -9,13 +9,18 @@ title = "mdbook-admonish-integration"
|
||||
|
||||
[preprocessor.admonish]
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "3.0.1" # do not edit: managed by `mdbook-admonish install`
|
||||
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
|
||||
after = ["links"]
|
||||
|
||||
[[preprocessor.admonish.custom]]
|
||||
directive = "frog"
|
||||
icon = "./frog.svg"
|
||||
color = "#9004CC"
|
||||
|
||||
[preprocessor.admonish.renderer.test]
|
||||
render_mode = "strip"
|
||||
|
||||
[output]
|
||||
|
||||
[output.html]
|
||||
additional-css = ["./mdbook-admonish.css"]
|
||||
additional-css = ["./mdbook-admonish.css", "./mdbook-admonish-custom.css"]
|
||||
|
||||
@@ -9,13 +9,18 @@ title = "mdbook-admonish-integration"
|
||||
|
||||
[preprocessor.admonish]
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "3.0.1" # do not edit: managed by `mdbook-admonish install`
|
||||
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
|
||||
after = ["links"]
|
||||
|
||||
[[preprocessor.admonish.custom]]
|
||||
directive = "frog"
|
||||
icon = "./frog.svg"
|
||||
color = "#9004CC"
|
||||
|
||||
[preprocessor.admonish.renderer.test]
|
||||
render_mode = "strip"
|
||||
|
||||
[output]
|
||||
|
||||
[output.html]
|
||||
additional-css = ["./mdbook-admonish.css"]
|
||||
additional-css = ["./mdbook-admonish.css", "./mdbook-admonish-custom.css"]
|
||||
|
||||
@@ -18,6 +18,15 @@
|
||||
<p>Simples</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="admonition-frog" class="admonition admonish-frog">
|
||||
<div class="admonition-title">
|
||||
<p>Frog</p>
|
||||
<p><a class="admonition-anchor-link" href="#admonition-frog"></a></p>
|
||||
</div>
|
||||
<div>
|
||||
<p>Custom frog directive</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="admonition-default" class="admonition admonish-warning">
|
||||
<div>
|
||||
<p>No title, only body</p>
|
||||
|
||||
20
integration/expected/mdbook-admonish-custom.css
Normal file
20
integration/expected/mdbook-admonish-custom.css
Normal file
@@ -0,0 +1,20 @@
|
||||
:root {
|
||||
--md-admonition-icon--admonish-frog: url("data:image/svg+xml;charset=utf-8,<svg height='800px' width='800px' version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 512 512' xml:space='preserve'><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --><!-- ref: https://www.svgrepo.com/svg/232692/frog --><!-- Used under CC0 Licence --><path d='M472,268.109H40c-4.418,0-8,3.582-8,8s3.582,8,8,8h432c4.418,0,8-3.582,8-8S476.418,268.109,472,268.109z'/><path d='M320,300.109H192c-4.418,0-8,3.582-8,8s3.582,8,8,8h128c4.418,0,8-3.582,8-8S324.418,300.109,320,300.109z'/><path d='M483.105,224.949c-9.717-8.094-13.741-11.93-11.921-21.398c5.588-10.328,8.816-22.464,8.816-35.441c0-21.712-9.036-41.065-23.058-53.523c-8.67-14.834-24.283-25.463-43.124-29.246c-20.05-4.027-40.644,0.458-55.09,11.994C321.682,126.917,290,140.109,256,140.109s-65.682-13.192-102.728-42.776c-14.446-11.535-35.04-16.02-55.09-11.994c-18.841,3.783-34.454,14.412-43.124,29.246C41.036,127.044,32,146.397,32,168.109c0,12.977,3.228,25.113,8.816,35.441c1.82,9.468-2.204,13.305-11.921,21.398C16.701,235.106,0,249.018,0,284.109c0,30.939,44.4,68.017,85.951,92.4c55.883,32.792,117.864,51.6,170.049,51.6s114.166-18.808,170.049-51.6C467.6,352.126,512,315.049,512,284.109C512,249.018,495.299,235.106,483.105,224.949z M464,168.109c0,10.585-2.696,20.437-7.312,28.661c-0.078,0.131-0.148,0.266-0.219,0.402c-7.916,13.829-21.31,22.937-36.47,22.937c-24.262,0-44-23.327-44-52s19.738-52,44-52c9.282,0,17.896,3.423,25.002,9.245c0.351,0.356,0.731,0.674,1.135,0.955C456.965,135.79,464,150.995,464,168.109z M65.857,126.314c0.407-0.282,0.791-0.603,1.144-0.962c7.105-5.82,15.718-9.242,24.999-9.242c24.262,0,44,23.327,44,52s-19.738,52-44,52c-15.159,0-28.552-9.107-36.468-22.935c-0.072-0.138-0.143-0.275-0.222-0.407C50.696,188.545,48,178.694,48,168.11C48,150.999,55.032,135.795,65.857,126.314z M417.951,362.709c-52.713,30.933-113.256,49.4-161.951,49.4s-109.238-18.467-161.951-49.4C48.095,335.744,16,303.422,16,284.109c0-27.596,11.761-37.393,23.135-46.867c5.547-4.621,11.494-9.583,15.006-16.426c10.334,9.552,23.514,15.293,37.858,15.293c33.084,0,60-30.505,60-68c0-33.803-21.879-61.914-50.429-67.125c15.396-3.025,30.975,0.273,41.717,8.852c40.075,32.002,74.837,46.273,112.712,46.273s72.637-14.271,112.712-46.273c10.743-8.579,26.321-11.878,41.717-8.852C381.879,106.195,360,134.307,360,168.109c0,37.495,26.916,68,60,68c14.344,0,27.524-5.741,37.858-15.293c3.512,6.842,9.459,11.805,15.006,16.426C484.239,246.717,496,256.513,496,284.109C496,303.422,463.905,335.744,417.951,362.709z'/><path d='M92,180.109c8.445,0,36-1.154,36-16s-27.555-16-36-16s-36,1.154-36,16S83.555,180.109,92,180.109z'/><path d='M384,164.109c0,14.846,27.555,16,36,16s36-1.154,36-16s-27.555-16-36-16S384,149.263,384,164.109z'/><path d='M232,228.109c4.418,0,8-3.582,8-8v-8c0-4.418-3.582-8-8-8s-8,3.582-8,8v8C224,224.528,227.582,228.109,232,228.109z'/><path d='M280,228.109c4.418,0,8-3.582,8-8v-8c0-4.418-3.582-8-8-8s-8,3.582-8,8v8C272,224.528,275.582,228.109,280,228.109z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition):is(.admonish-frog) {
|
||||
border-color: #9004cc;
|
||||
}
|
||||
|
||||
:is(.admonish-frog) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(144, 4, 204, 0.1);
|
||||
}
|
||||
:is(.admonish-frog) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #9004cc;
|
||||
mask-image: var(--md-admonition-icon--admonish-frog);
|
||||
-webkit-mask-image: var(--md-admonition-icon--admonish-frog);
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
}
|
||||
29
integration/frog.svg
Normal file
29
integration/frog.svg
Normal file
@@ -0,0 +1,29 @@
|
||||
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve">
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<!-- ref: https://www.svgrepo.com/svg/232692/frog -->
|
||||
<!-- Used under CC0 Licence -->
|
||||
<path d="M472,268.109H40c-4.418,0-8,3.582-8,8s3.582,8,8,8h432c4.418,0,8-3.582,8-8S476.418,268.109,472,268.109z"/>
|
||||
<path d="M320,300.109H192c-4.418,0-8,3.582-8,8s3.582,8,8,8h128c4.418,0,8-3.582,8-8S324.418,300.109,320,300.109z"/>
|
||||
<path d="M483.105,224.949c-9.717-8.094-13.741-11.93-11.921-21.398c5.588-10.328,8.816-22.464,8.816-35.441
|
||||
c0-21.712-9.036-41.065-23.058-53.523c-8.67-14.834-24.283-25.463-43.124-29.246c-20.05-4.027-40.644,0.458-55.09,11.994
|
||||
C321.682,126.917,290,140.109,256,140.109s-65.682-13.192-102.728-42.776c-14.446-11.535-35.04-16.02-55.09-11.994
|
||||
c-18.841,3.783-34.454,14.412-43.124,29.246C41.036,127.044,32,146.397,32,168.109c0,12.977,3.228,25.113,8.816,35.441
|
||||
c1.82,9.468-2.204,13.305-11.921,21.398C16.701,235.106,0,249.018,0,284.109c0,30.939,44.4,68.017,85.951,92.4
|
||||
c55.883,32.792,117.864,51.6,170.049,51.6s114.166-18.808,170.049-51.6C467.6,352.126,512,315.049,512,284.109
|
||||
C512,249.018,495.299,235.106,483.105,224.949z M464,168.109c0,10.585-2.696,20.437-7.312,28.661
|
||||
c-0.078,0.131-0.148,0.266-0.219,0.402c-7.916,13.829-21.31,22.937-36.47,22.937c-24.262,0-44-23.327-44-52s19.738-52,44-52
|
||||
c9.282,0,17.896,3.423,25.002,9.245c0.351,0.356,0.731,0.674,1.135,0.955C456.965,135.79,464,150.995,464,168.109z M65.857,126.314
|
||||
c0.407-0.282,0.791-0.603,1.144-0.962c7.105-5.82,15.718-9.242,24.999-9.242c24.262,0,44,23.327,44,52s-19.738,52-44,52
|
||||
c-15.159,0-28.552-9.107-36.468-22.935c-0.072-0.138-0.143-0.275-0.222-0.407C50.696,188.545,48,178.694,48,168.11
|
||||
C48,150.999,55.032,135.795,65.857,126.314z M417.951,362.709c-52.713,30.933-113.256,49.4-161.951,49.4
|
||||
s-109.238-18.467-161.951-49.4C48.095,335.744,16,303.422,16,284.109c0-27.596,11.761-37.393,23.135-46.867
|
||||
c5.547-4.621,11.494-9.583,15.006-16.426c10.334,9.552,23.514,15.293,37.858,15.293c33.084,0,60-30.505,60-68
|
||||
c0-33.803-21.879-61.914-50.429-67.125c15.396-3.025,30.975,0.273,41.717,8.852c40.075,32.002,74.837,46.273,112.712,46.273
|
||||
s72.637-14.271,112.712-46.273c10.743-8.579,26.321-11.878,41.717-8.852C381.879,106.195,360,134.307,360,168.109
|
||||
c0,37.495,26.916,68,60,68c14.344,0,27.524-5.741,37.858-15.293c3.512,6.842,9.459,11.805,15.006,16.426
|
||||
C484.239,246.717,496,256.513,496,284.109C496,303.422,463.905,335.744,417.951,362.709z"/>
|
||||
<path d="M92,180.109c8.445,0,36-1.154,36-16s-27.555-16-36-16s-36,1.154-36,16S83.555,180.109,92,180.109z"/>
|
||||
<path d="M384,164.109c0,14.846,27.555,16,36,16s36-1.154,36-16s-27.555-16-36-16S384,149.263,384,164.109z"/>
|
||||
<path d="M232,228.109c4.418,0,8-3.582,8-8v-8c0-4.418-3.582-8-8-8s-8,3.582-8,8v8C224,224.528,227.582,228.109,232,228.109z"/>
|
||||
<path d="M280,228.109c4.418,0,8-3.582,8-8v-8c0-4.418-3.582-8-8-8s-8,3.582-8,8v8C272,224.528,275.582,228.109,280,228.109z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
20
integration/mdbook-admonish-custom.css
Normal file
20
integration/mdbook-admonish-custom.css
Normal file
@@ -0,0 +1,20 @@
|
||||
:root {
|
||||
--md-admonition-icon--admonish-frog: url("data:image/svg+xml;charset=utf-8,<svg height='800px' width='800px' version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 512 512' xml:space='preserve'><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --><!-- ref: https://www.svgrepo.com/svg/232692/frog --><!-- Used under CC0 Licence --><path d='M472,268.109H40c-4.418,0-8,3.582-8,8s3.582,8,8,8h432c4.418,0,8-3.582,8-8S476.418,268.109,472,268.109z'/><path d='M320,300.109H192c-4.418,0-8,3.582-8,8s3.582,8,8,8h128c4.418,0,8-3.582,8-8S324.418,300.109,320,300.109z'/><path d='M483.105,224.949c-9.717-8.094-13.741-11.93-11.921-21.398c5.588-10.328,8.816-22.464,8.816-35.441c0-21.712-9.036-41.065-23.058-53.523c-8.67-14.834-24.283-25.463-43.124-29.246c-20.05-4.027-40.644,0.458-55.09,11.994C321.682,126.917,290,140.109,256,140.109s-65.682-13.192-102.728-42.776c-14.446-11.535-35.04-16.02-55.09-11.994c-18.841,3.783-34.454,14.412-43.124,29.246C41.036,127.044,32,146.397,32,168.109c0,12.977,3.228,25.113,8.816,35.441c1.82,9.468-2.204,13.305-11.921,21.398C16.701,235.106,0,249.018,0,284.109c0,30.939,44.4,68.017,85.951,92.4c55.883,32.792,117.864,51.6,170.049,51.6s114.166-18.808,170.049-51.6C467.6,352.126,512,315.049,512,284.109C512,249.018,495.299,235.106,483.105,224.949z M464,168.109c0,10.585-2.696,20.437-7.312,28.661c-0.078,0.131-0.148,0.266-0.219,0.402c-7.916,13.829-21.31,22.937-36.47,22.937c-24.262,0-44-23.327-44-52s19.738-52,44-52c9.282,0,17.896,3.423,25.002,9.245c0.351,0.356,0.731,0.674,1.135,0.955C456.965,135.79,464,150.995,464,168.109z M65.857,126.314c0.407-0.282,0.791-0.603,1.144-0.962c7.105-5.82,15.718-9.242,24.999-9.242c24.262,0,44,23.327,44,52s-19.738,52-44,52c-15.159,0-28.552-9.107-36.468-22.935c-0.072-0.138-0.143-0.275-0.222-0.407C50.696,188.545,48,178.694,48,168.11C48,150.999,55.032,135.795,65.857,126.314z M417.951,362.709c-52.713,30.933-113.256,49.4-161.951,49.4s-109.238-18.467-161.951-49.4C48.095,335.744,16,303.422,16,284.109c0-27.596,11.761-37.393,23.135-46.867c5.547-4.621,11.494-9.583,15.006-16.426c10.334,9.552,23.514,15.293,37.858,15.293c33.084,0,60-30.505,60-68c0-33.803-21.879-61.914-50.429-67.125c15.396-3.025,30.975,0.273,41.717,8.852c40.075,32.002,74.837,46.273,112.712,46.273s72.637-14.271,112.712-46.273c10.743-8.579,26.321-11.878,41.717-8.852C381.879,106.195,360,134.307,360,168.109c0,37.495,26.916,68,60,68c14.344,0,27.524-5.741,37.858-15.293c3.512,6.842,9.459,11.805,15.006,16.426C484.239,246.717,496,256.513,496,284.109C496,303.422,463.905,335.744,417.951,362.709z'/><path d='M92,180.109c8.445,0,36-1.154,36-16s-27.555-16-36-16s-36,1.154-36,16S83.555,180.109,92,180.109z'/><path d='M384,164.109c0,14.846,27.555,16,36,16s36-1.154,36-16s-27.555-16-36-16S384,149.263,384,164.109z'/><path d='M232,228.109c4.418,0,8-3.582,8-8v-8c0-4.418-3.582-8-8-8s-8,3.582-8,8v8C224,224.528,227.582,228.109,232,228.109z'/><path d='M280,228.109c4.418,0,8-3.582,8-8v-8c0-4.418-3.582-8-8-8s-8,3.582-8,8v8C272,224.528,275.582,228.109,280,228.109z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition):is(.admonish-frog) {
|
||||
border-color: #9004cc;
|
||||
}
|
||||
|
||||
:is(.admonish-frog) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(144, 4, 204, 0.1);
|
||||
}
|
||||
:is(.admonish-frog) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #9004cc;
|
||||
mask-image: var(--md-admonition-icon--admonish-frog);
|
||||
-webkit-mask-image: var(--md-admonition-icon--admonish-frog);
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
}
|
||||
@@ -34,6 +34,27 @@ if [ "$DIFF_RESULT" != 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eprintln "Generating custom CSS (book)"
|
||||
mdbook-admonish generate-custom mdbook-admonish-custom.css
|
||||
|
||||
eprintln "Verifying generated book custom css"
|
||||
set +e
|
||||
diff -u \
|
||||
"expected/mdbook-admonish-custom.css" \
|
||||
"./mdbook-admonish-custom.css"
|
||||
DIFF_RESULT=$?
|
||||
set -e
|
||||
|
||||
if [ "$DIFF_RESULT" != 0 ]; then
|
||||
eprintln ""
|
||||
eprintln "error: generated custom css was different than expected"
|
||||
eprintln ""
|
||||
eprintln "error: If you expected the output to change, run:"
|
||||
eprintln "cp ./integration/mdbook-admonish-custom.css ./integration/expected/mdbook-admonish-custom.css"
|
||||
eprintln "and commit the result"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eprintln "Building mdbook"
|
||||
mdbook build
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ It verifies that `mdbook` post-processes our generated HTML in the way we expect
|
||||
Simples
|
||||
```
|
||||
|
||||
```admonish frog
|
||||
Custom frog directive
|
||||
```
|
||||
|
||||
```admonish warning ""
|
||||
No title, only body
|
||||
```
|
||||
|
||||
@@ -18,7 +18,20 @@ eprintln "Checking compiled styles up to date"
|
||||
COMITTED_ASSETS="$(cat ../src/bin/assets/mdbook-admonish.css)"
|
||||
yarn run build
|
||||
RECOMPILED_ASSETS="$(cat ../src/bin/assets/mdbook-admonish.css)"
|
||||
set +e
|
||||
diff -u <(printf "%s" "$COMITTED_ASSETS") <(printf "%s" "$RECOMPILED_ASSETS")
|
||||
DIFF_RESULT=$?
|
||||
set -e
|
||||
|
||||
if [ "$DIFF_RESULT" != 0 ]; then
|
||||
eprintln ""
|
||||
eprintln "error: committed assets are not up to date"
|
||||
eprintln ""
|
||||
eprintln "error: To update committed assets, please run"
|
||||
eprintln "cd compile_assets && yarn run build"
|
||||
eprintln "and commit the result"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
popd > /dev/null
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.1
|
||||
3.0.2
|
||||
|
||||
@@ -1,20 +1,4 @@
|
||||
@charset "UTF-8";
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
|
||||
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
|
||||
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
|
||||
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
|
||||
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
|
||||
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
|
||||
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
|
||||
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
|
||||
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
|
||||
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition) {
|
||||
display: flow-root;
|
||||
margin: 1.5625em 0;
|
||||
@@ -123,6 +107,25 @@ details[open].admonition > summary.admonition-title::after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
|
||||
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
|
||||
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
|
||||
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
|
||||
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
|
||||
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
|
||||
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
|
||||
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
|
||||
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
|
||||
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition):is(.admonish-note) {
|
||||
border-color: #448aff;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context, Result};
|
||||
use clap::{Parser, Subcommand};
|
||||
use mdbook::{
|
||||
errors::Error,
|
||||
preprocess::{CmdPreprocessor, Preprocessor},
|
||||
};
|
||||
use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
|
||||
use mdbook_admonish::Admonish;
|
||||
#[cfg(feature = "cli-install")]
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::{io, process};
|
||||
use std::process;
|
||||
|
||||
/// mdbook preprocessor to add support for admonitions
|
||||
#[derive(Parser)]
|
||||
@@ -36,6 +35,18 @@ enum Commands {
|
||||
#[arg(long)]
|
||||
css_dir: Option<PathBuf>,
|
||||
},
|
||||
|
||||
/// Generate CSS file for custom directives.
|
||||
GenerateCustom {
|
||||
/// Root directory for the book, should contain the configuration file (`book.toml`)
|
||||
///
|
||||
/// If not set, defaults to the current directory.
|
||||
#[arg(long)]
|
||||
dir: Option<PathBuf>,
|
||||
|
||||
/// File to write generated css to.
|
||||
output: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -62,10 +73,13 @@ fn run(cli: Cli) -> Result<()> {
|
||||
dir.unwrap_or_else(|| PathBuf::from(".")),
|
||||
css_dir.unwrap_or_else(|| PathBuf::from(".")),
|
||||
),
|
||||
Some(Commands::GenerateCustom { dir, output }) => {
|
||||
handle_generate_custom(dir.unwrap_or_else(|| PathBuf::from(".")), output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_preprocessing() -> Result<(), Error> {
|
||||
fn handle_preprocessing() -> std::result::Result<(), mdbook::errors::Error> {
|
||||
let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?;
|
||||
|
||||
if ctx.mdbook_version != mdbook::MDBOOK_VERSION {
|
||||
@@ -94,6 +108,47 @@ fn handle_supports(renderer: String) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Config {
|
||||
#[serde(default)]
|
||||
preprocessor: Preprocessors,
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
struct Preprocessors {
|
||||
#[serde(default)]
|
||||
admonish: Option<toml::Table>,
|
||||
|
||||
#[serde(flatten)]
|
||||
_other: toml::Table,
|
||||
}
|
||||
|
||||
/// Load the plugin specific config as a toml string, for private deserialization.
|
||||
fn admonish_config_string(config: &Config) -> Result<String> {
|
||||
Ok(toml_mdbook::to_string(
|
||||
&config
|
||||
.preprocessor
|
||||
.admonish
|
||||
.as_ref()
|
||||
.context("No configuration for mdbook-admonish in book.toml")?,
|
||||
)?)
|
||||
}
|
||||
|
||||
fn handle_generate_custom(proj_dir: PathBuf, output: PathBuf) -> Result<()> {
|
||||
let config = proj_dir.join("book.toml");
|
||||
log::info!("Reading configuration file '{}'", config.display());
|
||||
let data = fs::read_to_string(&config)
|
||||
.with_context(|| format!("can't read configuration file '{}'", config.display()))?;
|
||||
let config: Config = toml::from_str(&data).context("Invalid configuration file")?;
|
||||
|
||||
let css =
|
||||
mdbook_admonish::custom::css_from_config(&proj_dir, &admonish_config_string(&config)?)?;
|
||||
|
||||
log::info!("Writing custom CSS file '{}'", output.display());
|
||||
fs::write(output, css)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "cli-install")]
|
||||
mod install {
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
@@ -2,6 +2,7 @@ use anyhow::{Context, Result};
|
||||
use mdbook::preprocess::PreprocessorContext;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::types::AdmonitionDefaults;
|
||||
|
||||
@@ -15,7 +16,11 @@ pub(crate) fn admonish_config_from_context(ctx: &PreprocessorContext) -> Result<
|
||||
.get_preprocessor("admonish")
|
||||
.context("No configuration for mdbook-admonish in book.toml")?,
|
||||
)?;
|
||||
toml::from_str(&table).context("Invalid mdbook-admonish configuration in book.toml")
|
||||
admonish_config_from_str(&table)
|
||||
}
|
||||
|
||||
pub(crate) fn admonish_config_from_str(data: &str) -> Result<Config> {
|
||||
toml::from_str(data).context("Invalid mdbook-admonish configuration in book.toml")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
@@ -31,6 +36,29 @@ pub(crate) struct Config {
|
||||
|
||||
#[serde(default)]
|
||||
pub assets_version: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub custom: Vec<CustomDirective>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub(crate) struct CustomDirective {
|
||||
/// The primary directive. Used for CSS classnames
|
||||
pub directive: String,
|
||||
|
||||
/// Path to an SVG file, relative to the book root.
|
||||
pub icon: PathBuf,
|
||||
|
||||
/// Primary color for this directive.
|
||||
pub color: hex_color::HexColor,
|
||||
|
||||
/// Alternative directives the user can specify
|
||||
#[serde(default)]
|
||||
pub aliases: Vec<String>,
|
||||
|
||||
/// Title to use, human readable.
|
||||
#[serde(default)]
|
||||
pub title: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
|
||||
111
src/custom.rs
Normal file
111
src/custom.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
//! This module is responsible for generating custom CSS for new admonition variants.
|
||||
//!
|
||||
//! It has unit tests to ensure the output matches that of the compile_assets CSS.
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use hex_color::{Case, HexColor};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
static RX_COLLAPSE_NEWLINES: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"[\r\n]+\s*").expect("invalid whitespace regex"));
|
||||
|
||||
/// Do some simple things to make the svg input probably a valid data url
|
||||
/// Based on this gist: https://gist.github.com/jennyknuth/222825e315d45a738ed9d6e04c7a88d0
|
||||
fn svg_to_data_url(svg: &str) -> String {
|
||||
const XMLNS: &str = r#"http://www.w3.org/2000/svg"#;
|
||||
//
|
||||
let mut svg = RX_COLLAPSE_NEWLINES.replace_all(svg, "").to_string();
|
||||
if !svg.contains(XMLNS) {
|
||||
log::warn!("Your SVG file does not contain '<svg xmlns=\"{XMLNS}\"', it will likely fail to render.");
|
||||
}
|
||||
|
||||
svg = svg
|
||||
.replace('"', "'")
|
||||
.replace('%', "%25")
|
||||
.replace('#', "%23")
|
||||
.replace('{', "%7B")
|
||||
.replace('}', "%7D");
|
||||
format!("url(\"data:image/svg+xml;charset=utf-8,{}\")", svg)
|
||||
}
|
||||
|
||||
/// Given a valid set of inputs, generate the relevant CSS.
|
||||
///
|
||||
/// It is up to the caller to validate inputs.
|
||||
fn directive_css(name: &str, svg_data: &str, tint: HexColor) -> String {
|
||||
let data_url = svg_to_data_url(svg_data);
|
||||
let tint_faint = format!("rgba({}, {}, {}, {})", tint.r, tint.g, tint.b, 0.1);
|
||||
let tint = tint.display_rgb().with_case(Case::Lower);
|
||||
format!(
|
||||
":root {{
|
||||
--md-admonition-icon--admonish-{name}: {data_url};
|
||||
}}
|
||||
|
||||
:is(.admonition):is(.admonish-{name}) {{
|
||||
border-color: {tint};
|
||||
}}
|
||||
|
||||
:is(.admonish-{name}) > :is(.admonition-title, summary.admonition-title) {{
|
||||
background-color: {tint_faint};
|
||||
}}
|
||||
:is(.admonish-{name}) > :is(.admonition-title, summary.admonition-title)::before {{
|
||||
background-color: {tint};
|
||||
mask-image: var(--md-admonition-icon--admonish-{name});
|
||||
-webkit-mask-image: var(--md-admonition-icon--admonish-{name});
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
}}
|
||||
",
|
||||
name = name,
|
||||
data_url = data_url,
|
||||
tint = tint,
|
||||
tint_faint = tint_faint
|
||||
)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn css_from_config(book_dir: &Path, config: &str) -> Result<String> {
|
||||
let config = crate::book_config::admonish_config_from_str(config)?;
|
||||
let custom_directives = config.custom;
|
||||
|
||||
if custom_directives.is_empty() {
|
||||
return Err(anyhow!("No custom directives provided"));
|
||||
}
|
||||
|
||||
log::info!("Loaded {} custom directives", custom_directives.len());
|
||||
let mut css = String::new();
|
||||
for directive in custom_directives.iter() {
|
||||
let svg = fs::read_to_string(book_dir.join(&directive.icon))
|
||||
.with_context(|| format!("can't read icon file '{}'", directive.icon.display()))?;
|
||||
css.push_str(&directive_css(&directive.directive, &svg, directive.color));
|
||||
}
|
||||
Ok(css)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
const GENERATED_CSS: &str = include_str!("./test_data/mdbook-admonish-custom-expected.css");
|
||||
const NOTE_SVG: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox='0 0 24 24'>
|
||||
<path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/>
|
||||
</svg>
|
||||
"#;
|
||||
|
||||
// Verify the generated CSS here against a sample from the compile_assets output.
|
||||
//
|
||||
// The ensures that any new custom CSS will be in line with official styles.
|
||||
#[test]
|
||||
fn verify_against_generated_css() {
|
||||
let actual = directive_css("note", NOTE_SVG, HexColor::parse("#448aff").unwrap());
|
||||
assert_eq!(
|
||||
GENERATED_CSS, actual,
|
||||
"Rust generated CSS is out of step with SCSS generated CSS"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
//! For usage and reference, see the [mdbook-admonish book](https://tommilligan.github.io/mdbook-admonish/)
|
||||
//!
|
||||
//! Documentation is hosted externally, as docs.rs does not currently support plugins.
|
||||
|
||||
mod book_config;
|
||||
mod config;
|
||||
#[doc(hidden)]
|
||||
pub mod custom;
|
||||
mod markdown;
|
||||
mod parse;
|
||||
mod preprocessor;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use mdbook::errors::Result as MdbookResult;
|
||||
use pulldown_cmark::{CodeBlockKind::*, Event, Options, Parser, Tag};
|
||||
|
||||
pub use crate::preprocessor::Admonish;
|
||||
use crate::{
|
||||
book_config::OnFailure,
|
||||
parse::parse_admonition,
|
||||
types::{AdmonitionDefaults, RenderTextMode},
|
||||
types::{AdmonitionDefaults, CustomDirectiveMap, RenderTextMode},
|
||||
};
|
||||
|
||||
pub(crate) fn preprocess(
|
||||
content: &str,
|
||||
on_failure: OnFailure,
|
||||
admonition_defaults: &AdmonitionDefaults,
|
||||
custom_directives: &CustomDirectiveMap,
|
||||
render_text_mode: RenderTextMode,
|
||||
) -> MdbookResult<String> {
|
||||
let mut id_counter = Default::default();
|
||||
@@ -34,6 +34,7 @@ pub(crate) fn preprocess(
|
||||
let admonition = match parse_admonition(
|
||||
info_string.as_ref(),
|
||||
admonition_defaults,
|
||||
custom_directives,
|
||||
span_content,
|
||||
on_failure,
|
||||
indent,
|
||||
@@ -137,6 +138,7 @@ mod test {
|
||||
content,
|
||||
OnFailure::Continue,
|
||||
&AdmonitionDefaults::default(),
|
||||
&CustomDirectiveMap::default(),
|
||||
RenderTextMode::Html,
|
||||
)
|
||||
.unwrap()
|
||||
@@ -630,6 +632,7 @@ Bonus content!
|
||||
content,
|
||||
OnFailure::Bail,
|
||||
&AdmonitionDefaults::default(),
|
||||
&CustomDirectiveMap::default(),
|
||||
RenderTextMode::Html
|
||||
)
|
||||
.unwrap_err()
|
||||
@@ -657,6 +660,7 @@ x = 20;
|
||||
content,
|
||||
OnFailure::Bail,
|
||||
&AdmonitionDefaults::default(),
|
||||
&CustomDirectiveMap::default(),
|
||||
RenderTextMode::Strip
|
||||
)
|
||||
.unwrap(),
|
||||
@@ -735,6 +739,7 @@ Text
|
||||
css_id_prefix: None,
|
||||
collapsible: false,
|
||||
},
|
||||
&CustomDirectiveMap::default(),
|
||||
RenderTextMode::Html,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -770,6 +775,7 @@ Text
|
||||
css_id_prefix: None,
|
||||
collapsible: false,
|
||||
},
|
||||
&CustomDirectiveMap::default(),
|
||||
RenderTextMode::Html,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -925,6 +931,7 @@ Text
|
||||
css_id_prefix: Some("".to_owned()),
|
||||
collapsible: false,
|
||||
},
|
||||
&CustomDirectiveMap::default(),
|
||||
RenderTextMode::Html,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -966,6 +973,7 @@ Text
|
||||
css_id_prefix: Some("prefix-".to_owned()),
|
||||
collapsible: false,
|
||||
},
|
||||
&CustomDirectiveMap::default(),
|
||||
RenderTextMode::Html,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1007,6 +1015,7 @@ Text
|
||||
css_id_prefix: Some("ignored-prefix-".to_owned()),
|
||||
collapsible: false,
|
||||
},
|
||||
&CustomDirectiveMap::default(),
|
||||
RenderTextMode::Html,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub use crate::preprocessor::Admonish;
|
||||
use crate::{
|
||||
book_config::OnFailure,
|
||||
render::Admonition,
|
||||
resolve::AdmonitionMeta,
|
||||
types::{AdmonitionDefaults, CssId, Directive},
|
||||
types::{AdmonitionDefaults, BuiltinDirective, CssId, CustomDirectiveMap},
|
||||
};
|
||||
|
||||
/// Given the content in the span of the code block, and the info string,
|
||||
@@ -21,6 +20,7 @@ use crate::{
|
||||
pub(crate) fn parse_admonition<'a>(
|
||||
info_string: &'a str,
|
||||
admonition_defaults: &'a AdmonitionDefaults,
|
||||
custom_directives: &'a CustomDirectiveMap,
|
||||
content: &'a str,
|
||||
on_failure: OnFailure,
|
||||
indent: usize,
|
||||
@@ -28,7 +28,8 @@ pub(crate) fn parse_admonition<'a>(
|
||||
// We need to know fence details anyway for error messages
|
||||
let extracted = extract_admonish_body(content);
|
||||
|
||||
let info = AdmonitionMeta::from_info_string(info_string, admonition_defaults)?;
|
||||
let info =
|
||||
AdmonitionMeta::from_info_string(info_string, admonition_defaults, custom_directives)?;
|
||||
let info = match info {
|
||||
Ok(info) => info,
|
||||
Err(message) => {
|
||||
@@ -44,7 +45,7 @@ pub(crate) fn parse_admonition<'a>(
|
||||
r#"Error processing admonition. To fail the build instead of continuing, set 'on_failure = "bail"'"#
|
||||
);
|
||||
Ok(Admonition {
|
||||
directive: Directive::Bug,
|
||||
directive: BuiltinDirective::Bug.to_string(),
|
||||
title: "Error rendering admonishment".to_owned(),
|
||||
css_id: CssId::Prefix("admonition-".to_owned()),
|
||||
additional_classnames: Vec::new(),
|
||||
|
||||
@@ -8,7 +8,7 @@ use mdbook::{
|
||||
use crate::{
|
||||
book_config::{admonish_config_from_context, Config, RenderMode},
|
||||
markdown::preprocess,
|
||||
types::RenderTextMode,
|
||||
types::{CustomDirectiveMap, RenderTextMode},
|
||||
};
|
||||
|
||||
pub struct Admonish;
|
||||
@@ -22,6 +22,8 @@ impl Preprocessor for Admonish {
|
||||
let config = admonish_config_from_context(ctx)?;
|
||||
ensure_compatible_assets_version(&config)?;
|
||||
|
||||
let custom_directives =
|
||||
CustomDirectiveMap::from_configs(config.custom.into_iter().map(Into::into));
|
||||
let on_failure = config.on_failure;
|
||||
let admonition_defaults = config.default;
|
||||
|
||||
@@ -57,6 +59,7 @@ impl Preprocessor for Admonish {
|
||||
&chapter.content,
|
||||
on_failure,
|
||||
&admonition_defaults,
|
||||
&custom_directives,
|
||||
render_text_mode,
|
||||
)
|
||||
.map(|md| {
|
||||
|
||||
@@ -2,34 +2,11 @@ use mdbook::utils::unique_id_from_content;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use crate::preprocessor::Admonish;
|
||||
use crate::{
|
||||
resolve::AdmonitionMeta,
|
||||
types::{CssId, Directive},
|
||||
};
|
||||
|
||||
impl Directive {
|
||||
fn classname(&self) -> &'static str {
|
||||
match self {
|
||||
Directive::Note => "admonish-note",
|
||||
Directive::Abstract => "admonish-abstract",
|
||||
Directive::Info => "admonish-info",
|
||||
Directive::Tip => "admonish-tip",
|
||||
Directive::Success => "admonish-success",
|
||||
Directive::Question => "admonish-question",
|
||||
Directive::Warning => "admonish-warning",
|
||||
Directive::Failure => "admonish-failure",
|
||||
Directive::Danger => "admonish-danger",
|
||||
Directive::Bug => "admonish-bug",
|
||||
Directive::Example => "admonish-example",
|
||||
Directive::Quote => "admonish-quote",
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::{resolve::AdmonitionMeta, types::CssId};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) struct Admonition<'a> {
|
||||
pub(crate) directive: Directive,
|
||||
pub(crate) directive: String,
|
||||
pub(crate) title: String,
|
||||
pub(crate) content: Cow<'a, str>,
|
||||
pub(crate) css_id: CssId,
|
||||
@@ -75,7 +52,6 @@ impl<'a> Admonition<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut additional_class = Cow::Borrowed(self.directive.classname());
|
||||
let title = &self.title;
|
||||
let content = &self.content;
|
||||
let indent = " ".repeat(self.indent);
|
||||
@@ -96,14 +72,12 @@ impl<'a> Admonition<'a> {
|
||||
Cow::Borrowed("")
|
||||
};
|
||||
|
||||
let mut additional_class = format!("admonish-{}", self.directive);
|
||||
if !self.additional_classnames.is_empty() {
|
||||
let mut buffer = additional_class.into_owned();
|
||||
for additional_classname in &self.additional_classnames {
|
||||
buffer.push(' ');
|
||||
buffer.push_str(additional_classname);
|
||||
additional_class.push(' ');
|
||||
additional_class.push_str(additional_classname);
|
||||
}
|
||||
|
||||
additional_class = Cow::Owned(buffer);
|
||||
}
|
||||
|
||||
let admonition_block = if self.collapsible { "details" } else { "div" };
|
||||
|
||||
180
src/resolve.rs
180
src/resolve.rs
@@ -1,5 +1,8 @@
|
||||
use crate::config::InstanceConfig;
|
||||
use crate::types::{AdmonitionDefaults, CssId, Directive};
|
||||
use crate::types::{
|
||||
AdmonitionDefaults, BuiltinDirective, CssId, CustomDirective, CustomDirectiveMap,
|
||||
};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// All information required to render an admonition.
|
||||
@@ -7,25 +10,69 @@ use std::str::FromStr;
|
||||
/// i.e. all configured options have been resolved at this point.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) struct AdmonitionMeta {
|
||||
pub directive: Directive,
|
||||
pub directive: String,
|
||||
pub title: String,
|
||||
pub css_id: CssId,
|
||||
pub additional_classnames: Vec<String>,
|
||||
pub collapsible: bool,
|
||||
}
|
||||
|
||||
/// Wrapper type to hold any value directive configuration.
|
||||
enum Directive {
|
||||
Builtin(BuiltinDirective),
|
||||
Custom(CustomDirective),
|
||||
}
|
||||
|
||||
impl fmt::Display for Directive {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Builtin(builtin) => builtin.fmt(f),
|
||||
Self::Custom(custom) => f.write_str(&custom.directive),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Directive {
|
||||
fn from_str(custom_directive_map: &CustomDirectiveMap, string: &str) -> Result<Self, ()> {
|
||||
if let Ok(builtin) = BuiltinDirective::from_str(string) {
|
||||
return Ok(Self::Builtin(builtin));
|
||||
}
|
||||
|
||||
if let Some(config) = custom_directive_map.get(string) {
|
||||
return Ok(Self::Custom(config.clone()));
|
||||
}
|
||||
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn title(self, raw_directive: &str) -> String {
|
||||
match self {
|
||||
Directive::Builtin(_) => format_builtin_directive_title(raw_directive),
|
||||
Directive::Custom(custom) => custom
|
||||
.title
|
||||
.clone()
|
||||
.unwrap_or_else(|| uppercase_first(raw_directive)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AdmonitionMeta {
|
||||
pub fn from_info_string(
|
||||
info_string: &str,
|
||||
defaults: &AdmonitionDefaults,
|
||||
custom_directives: &CustomDirectiveMap,
|
||||
) -> Option<Result<Self, String>> {
|
||||
InstanceConfig::from_info_string(info_string)
|
||||
.map(|raw| raw.map(|raw| Self::resolve(raw, defaults)))
|
||||
.map(|raw| raw.map(|raw| Self::resolve(raw, defaults, custom_directives)))
|
||||
}
|
||||
|
||||
/// Combine the per-admonition configuration with global defaults (and
|
||||
/// other logic) to resolve the values needed for rendering.
|
||||
fn resolve(raw: InstanceConfig, defaults: &AdmonitionDefaults) -> Self {
|
||||
fn resolve(
|
||||
raw: InstanceConfig,
|
||||
defaults: &AdmonitionDefaults,
|
||||
custom_directives: &CustomDirectiveMap,
|
||||
) -> Self {
|
||||
let InstanceConfig {
|
||||
directive: raw_directive,
|
||||
title,
|
||||
@@ -38,12 +85,14 @@ impl AdmonitionMeta {
|
||||
let title = title.or_else(|| defaults.title.clone());
|
||||
let collapsible = collapsible.unwrap_or(defaults.collapsible);
|
||||
|
||||
let directive = Directive::from_str(custom_directives, &raw_directive);
|
||||
|
||||
// Load the directive (and title, if one still not given)
|
||||
let (directive, title) = match (Directive::from_str(&raw_directive), title) {
|
||||
(Ok(directive), None) => (directive, format_directive_title(&raw_directive)),
|
||||
(Err(_), None) => (Directive::Note, "Note".to_owned()),
|
||||
(Ok(directive), Some(title)) => (directive, title),
|
||||
(Err(_), Some(title)) => (Directive::Note, title),
|
||||
let (directive, title) = match (directive, title) {
|
||||
(Ok(directive), None) => (directive.to_string(), directive.title(&raw_directive)),
|
||||
(Err(_), None) => (BuiltinDirective::Note.to_string(), "Note".to_owned()),
|
||||
(Ok(directive), Some(title)) => (directive.to_string(), title),
|
||||
(Err(_), Some(title)) => (BuiltinDirective::Note.to_string(), title),
|
||||
};
|
||||
|
||||
let css_id = if let Some(verbatim) = id {
|
||||
@@ -71,7 +120,7 @@ impl AdmonitionMeta {
|
||||
/// Format the title of an admonition directive
|
||||
///
|
||||
/// We special case a few words to make them look nicer (e.g. "tldr" -> "TL;DR" and "faq" -> "FAQ").
|
||||
fn format_directive_title(input: &str) -> String {
|
||||
fn format_builtin_directive_title(input: &str) -> String {
|
||||
match input {
|
||||
"tldr" => "TL;DR".to_owned(),
|
||||
"faq" => "FAQ".to_owned(),
|
||||
@@ -96,15 +145,15 @@ mod test {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_format_directive_title() {
|
||||
assert_eq!(format_directive_title(""), "");
|
||||
assert_eq!(format_directive_title("a"), "A");
|
||||
assert_eq!(format_directive_title("tldr"), "TL;DR");
|
||||
assert_eq!(format_directive_title("faq"), "FAQ");
|
||||
assert_eq!(format_directive_title("note"), "Note");
|
||||
assert_eq!(format_directive_title("abstract"), "Abstract");
|
||||
fn test_format_builtin_directive_title() {
|
||||
assert_eq!(format_builtin_directive_title(""), "");
|
||||
assert_eq!(format_builtin_directive_title("a"), "A");
|
||||
assert_eq!(format_builtin_directive_title("tldr"), "TL;DR");
|
||||
assert_eq!(format_builtin_directive_title("faq"), "FAQ");
|
||||
assert_eq!(format_builtin_directive_title("note"), "Note");
|
||||
assert_eq!(format_builtin_directive_title("abstract"), "Abstract");
|
||||
// Unicode
|
||||
assert_eq!(format_directive_title("🦀"), "🦀");
|
||||
assert_eq!(format_builtin_directive_title("🦀"), "🦀");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -118,10 +167,11 @@ mod test {
|
||||
additional_classnames: Vec::new(),
|
||||
collapsible: None,
|
||||
},
|
||||
&Default::default()
|
||||
&Default::default(),
|
||||
&CustomDirectiveMap::default(),
|
||||
),
|
||||
AdmonitionMeta {
|
||||
directive: Directive::Note,
|
||||
directive: "note".to_owned(),
|
||||
title: "Note".to_owned(),
|
||||
css_id: CssId::Prefix("admonition-".to_owned()),
|
||||
additional_classnames: Vec::new(),
|
||||
@@ -146,9 +196,10 @@ mod test {
|
||||
css_id_prefix: Some("custom-prefix-".to_owned()),
|
||||
collapsible: true,
|
||||
},
|
||||
&CustomDirectiveMap::default(),
|
||||
),
|
||||
AdmonitionMeta {
|
||||
directive: Directive::Note,
|
||||
directive: "note".to_owned(),
|
||||
title: "Important!!!".to_owned(),
|
||||
css_id: CssId::Prefix("custom-prefix-".to_owned()),
|
||||
additional_classnames: Vec::new(),
|
||||
@@ -173,9 +224,10 @@ mod test {
|
||||
css_id_prefix: Some("ignored-custom-prefix-".to_owned()),
|
||||
collapsible: true,
|
||||
},
|
||||
&CustomDirectiveMap::default(),
|
||||
),
|
||||
AdmonitionMeta {
|
||||
directive: Directive::Note,
|
||||
directive: "note".to_owned(),
|
||||
title: "Important!!!".to_owned(),
|
||||
css_id: CssId::Verbatim("my-custom-id".to_owned()),
|
||||
additional_classnames: Vec::new(),
|
||||
@@ -183,4 +235,88 @@ mod test {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_admonition_info_from_raw_with_custom_directive() {
|
||||
assert_eq!(
|
||||
AdmonitionMeta::resolve(
|
||||
InstanceConfig {
|
||||
directive: "frog".to_owned(),
|
||||
title: None,
|
||||
id: None,
|
||||
additional_classnames: Vec::new(),
|
||||
collapsible: None,
|
||||
},
|
||||
&AdmonitionDefaults::default(),
|
||||
&CustomDirectiveMap::from_configs(vec![CustomDirective {
|
||||
directive: "frog".to_owned(),
|
||||
aliases: Vec::new(),
|
||||
title: None,
|
||||
}]),
|
||||
),
|
||||
AdmonitionMeta {
|
||||
directive: "frog".to_owned(),
|
||||
title: "Frog".to_owned(),
|
||||
css_id: CssId::Prefix("admonition-".to_owned()),
|
||||
additional_classnames: Vec::new(),
|
||||
collapsible: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_admonition_info_from_raw_with_custom_directive_and_title() {
|
||||
assert_eq!(
|
||||
AdmonitionMeta::resolve(
|
||||
InstanceConfig {
|
||||
directive: "frog".to_owned(),
|
||||
title: None,
|
||||
id: None,
|
||||
additional_classnames: Vec::new(),
|
||||
collapsible: None,
|
||||
},
|
||||
&AdmonitionDefaults::default(),
|
||||
&CustomDirectiveMap::from_configs(vec![CustomDirective {
|
||||
directive: "frog".to_owned(),
|
||||
aliases: Vec::new(),
|
||||
title: Some("🏳️🌈".to_owned()),
|
||||
}]),
|
||||
),
|
||||
AdmonitionMeta {
|
||||
directive: "frog".to_owned(),
|
||||
title: "🏳️🌈".to_owned(),
|
||||
css_id: CssId::Prefix("admonition-".to_owned()),
|
||||
additional_classnames: Vec::new(),
|
||||
collapsible: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_admonition_info_from_raw_with_custom_directive_alias() {
|
||||
assert_eq!(
|
||||
AdmonitionMeta::resolve(
|
||||
InstanceConfig {
|
||||
directive: "toad".to_owned(),
|
||||
title: Some("Still a frog".to_owned()),
|
||||
id: None,
|
||||
additional_classnames: Vec::new(),
|
||||
collapsible: None,
|
||||
},
|
||||
&AdmonitionDefaults::default(),
|
||||
&CustomDirectiveMap::from_configs(vec![CustomDirective {
|
||||
directive: "frog".to_owned(),
|
||||
aliases: vec!["newt".to_owned(), "toad".to_owned()],
|
||||
title: Some("🏳️🌈".to_owned()),
|
||||
}]),
|
||||
),
|
||||
AdmonitionMeta {
|
||||
directive: "frog".to_owned(),
|
||||
title: "Still a frog".to_owned(),
|
||||
css_id: CssId::Prefix("admonition-".to_owned()),
|
||||
additional_classnames: Vec::new(),
|
||||
collapsible: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
20
src/test_data/mdbook-admonish-custom-expected.css
Normal file
20
src/test_data/mdbook-admonish-custom-expected.css
Normal file
@@ -0,0 +1,20 @@
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition):is(.admonish-note) {
|
||||
border-color: #448aff;
|
||||
}
|
||||
|
||||
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(68, 138, 255, 0.1);
|
||||
}
|
||||
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #448aff;
|
||||
mask-image: var(--md-admonition-icon--admonish-note);
|
||||
-webkit-mask-image: var(--md-admonition-icon--admonish-note);
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
}
|
||||
92
src/types.rs
92
src/types.rs
@@ -1,4 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Book wide defaults that may be provided by the user.
|
||||
@@ -15,8 +17,13 @@ pub(crate) struct AdmonitionDefaults {
|
||||
pub(crate) css_id_prefix: Option<String>,
|
||||
}
|
||||
|
||||
/// First class supported directives by the crate.
|
||||
///
|
||||
/// These are guaranteed to have valid CSS/icons available.
|
||||
///
|
||||
/// Custom directives can also be added via the book.toml config.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) enum Directive {
|
||||
pub(crate) enum BuiltinDirective {
|
||||
Note,
|
||||
Abstract,
|
||||
Info,
|
||||
@@ -31,7 +38,7 @@ pub(crate) enum Directive {
|
||||
Quote,
|
||||
}
|
||||
|
||||
impl FromStr for Directive {
|
||||
impl FromStr for BuiltinDirective {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(string: &str) -> Result<Self, ()> {
|
||||
@@ -53,6 +60,87 @@ impl FromStr for Directive {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BuiltinDirective {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let value = match self {
|
||||
Self::Note => "note",
|
||||
Self::Abstract => "abstract",
|
||||
Self::Info => "info",
|
||||
Self::Tip => "tip",
|
||||
Self::Success => "success",
|
||||
Self::Question => "question",
|
||||
Self::Warning => "warning",
|
||||
Self::Failure => "failure",
|
||||
Self::Danger => "danger",
|
||||
Self::Bug => "bug",
|
||||
Self::Example => "example",
|
||||
Self::Quote => "quote",
|
||||
};
|
||||
f.write_str(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// The subset of information we care about during plugin runtime for custom directives.
|
||||
///
|
||||
/// This drops information only needed during CSS generation.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct CustomDirective {
|
||||
pub directive: String,
|
||||
pub aliases: Vec<String>,
|
||||
pub title: Option<String>,
|
||||
}
|
||||
|
||||
impl From<crate::book_config::CustomDirective> for CustomDirective {
|
||||
fn from(other: crate::book_config::CustomDirective) -> Self {
|
||||
let crate::book_config::CustomDirective {
|
||||
directive,
|
||||
aliases,
|
||||
title,
|
||||
..
|
||||
} = other;
|
||||
Self {
|
||||
directive,
|
||||
aliases,
|
||||
title,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A map from the user given directive to underlying config.
|
||||
///
|
||||
/// The terminology is a bit mixed here - this map allows any input-directive,
|
||||
/// and returns the output-directive config.
|
||||
///
|
||||
/// i.e. this is the step alias mapping happens at
|
||||
#[derive(Default)]
|
||||
pub(crate) struct CustomDirectiveMap {
|
||||
inner: HashMap<String, CustomDirective>,
|
||||
}
|
||||
|
||||
impl CustomDirectiveMap {
|
||||
pub fn get(&self, key: &str) -> Option<&CustomDirective> {
|
||||
self.inner.get(key)
|
||||
}
|
||||
|
||||
pub fn from_configs<T>(configs: T) -> Self
|
||||
where
|
||||
T: IntoIterator<Item = CustomDirective>,
|
||||
{
|
||||
let mut inner = HashMap::default();
|
||||
for directive in configs.into_iter() {
|
||||
inner
|
||||
.entry(directive.directive.clone())
|
||||
.or_insert(directive.clone());
|
||||
|
||||
for alias in directive.aliases.iter() {
|
||||
inner.entry(alias.clone()).or_insert(directive.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum RenderTextMode {
|
||||
Strip,
|
||||
|
||||
Reference in New Issue
Block a user