generated from srid/ema-template
-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Start supporting Obsidian-style callouts (#466)
- Loading branch information
Showing
12 changed files
with
243 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<line x1="18" y1="6" x2="6" y2="18"></line> | ||
<line x1="6" y1="6" x2="18" y2="18"></line> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<circle cx="12" cy="12" r="10"></circle> | ||
<line x1="12" y1="16" x2="12" y2="12"></line> | ||
<line x1="12" y1="8" x2="12.01" y2="8"></line> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<line x1="18" y1="2" x2="22" y2="6"></line> | ||
<path d="M7.5 20.5 19 9l-4-4L3.5 16.5 2 22z"></path> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<path | ||
d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"> | ||
</path> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path> | ||
<line x1="12" y1="9" x2="12" y2="13"></line> | ||
<line x1="12" y1="17" x2="12.01" y2="17"></line> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<div data-callout-metadata="" data-callout-fold="" data-callout="${callout:type}" | ||
class="callout bg-opacity-10"> | ||
<path | ||
d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"> | ||
</path> | ||
<div class="callout-title"> | ||
<div class="callout-icon"> | ||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" | ||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-5 h-5"> | ||
<apply template="/templates/filters/callout-icon-${callout:type}" /> | ||
</svg> | ||
</div> | ||
<div class="callout-title-inner"> | ||
<callout:title /> | ||
</div> | ||
</div> | ||
<div class="callout-content"> | ||
<callout:body /> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
cabal-version: 2.4 | ||
name: emanote | ||
version: 1.2.0.0 | ||
version: 1.2.1.0 | ||
license: AGPL-3.0-only | ||
copyright: 2022 Sridhar Ratnakumar | ||
maintainer: [email protected] | ||
|
@@ -186,6 +186,7 @@ library | |
Emanote.Pandoc.Markdown.Syntax.HashTag | ||
Emanote.Pandoc.Markdown.Syntax.Highlight | ||
Emanote.Pandoc.Renderer | ||
Emanote.Pandoc.Renderer.Callout | ||
Emanote.Pandoc.Renderer.Embed | ||
Emanote.Pandoc.Renderer.Query | ||
Emanote.Pandoc.Renderer.Url | ||
|
@@ -244,3 +245,4 @@ test-suite test | |
Emanote.Model.Link.RelSpec | ||
Emanote.Model.QuerySpec | ||
Emanote.Pandoc.ExternalLinkSpec | ||
Emanote.Pandoc.Renderer.CalloutSpec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
{-# LANGUAGE RecordWildCards #-} | ||
|
||
module Emanote.Pandoc.Renderer.Callout ( | ||
calloutResolvingSplice, | ||
|
||
-- * For tests | ||
CalloutType (..), | ||
Callout (..), | ||
parseCalloutType, | ||
) where | ||
|
||
import Control.Monad (msum) | ||
import Data.Default (Default (def)) | ||
import Data.Map.Syntax ((##)) | ||
import Data.Text qualified as T | ||
import Emanote.Model (Model) | ||
import Emanote.Model.Title qualified as Tit | ||
import Emanote.Pandoc.Renderer (PandocBlockRenderer) | ||
import Emanote.Route (LMLRoute) | ||
import Heist.Extra qualified as HE | ||
import Heist.Extra.Splices.Pandoc qualified as HP | ||
import Heist.Interpreted qualified as HI | ||
import Relude | ||
import Text.Megaparsec qualified as M | ||
import Text.Megaparsec.Char qualified as M | ||
import Text.Pandoc.Definition qualified as B | ||
|
||
calloutResolvingSplice :: PandocBlockRenderer Model LMLRoute | ||
calloutResolvingSplice _model _nr ctx _noteRoute blk = do | ||
B.BlockQuote blks <- pure blk | ||
callout <- parseCallout blks | ||
pure $ do | ||
tpl <- HE.lookupHtmlTemplateMust "/templates/filters/callout" | ||
HE.runCustomTemplate tpl $ do | ||
"callout:type" ## HI.textSplice (T.toLower $ show $ type_ callout) | ||
"callout:title" ## Tit.titleSplice ctx id $ Tit.fromInlines (title callout) | ||
"callout:body" ## HP.pandocSplice ctx $ B.Pandoc mempty (body callout) | ||
"query" ## | ||
HI.textSplice (show blks) | ||
|
||
{- | Obsidian callout type | ||
TODO: Add the rest, from https://help.obsidian.md/Editing+and+formatting/Callouts#Supported%20types | ||
-} | ||
data CalloutType | ||
= Note | ||
| Info | ||
| Tip | ||
| Warning | ||
| Failure | ||
deriving stock (Eq, Ord, Show, Enum, Bounded) | ||
|
||
instance Default CalloutType where | ||
def = Note | ||
|
||
data Callout = Callout | ||
{ type_ :: CalloutType | ||
, title :: [B.Inline] | ||
, body :: [B.Block] | ||
} | ||
deriving stock (Eq, Ord, Show) | ||
|
||
-- | Parse `Callout` from blockquote blocks | ||
parseCallout :: [B.Block] -> Maybe Callout | ||
parseCallout = parseObsidianCallout | ||
|
||
-- | Parse according to https://help.obsidian.md/Editing+and+formatting/Callouts | ||
parseObsidianCallout :: [B.Block] -> Maybe Callout | ||
parseObsidianCallout blks = do | ||
B.Para (B.Str calloutType : inlines) : body' <- pure blks | ||
type_ <- parseCalloutType calloutType | ||
let (title', mFirstPara) = disrespectSoftbreak inlines | ||
title = if null title' then defaultTitle type_ else title' | ||
body = maybe body' (: body') mFirstPara | ||
pure $ Callout {..} | ||
|
||
{- | If there is a `B.SoftBreak`, treat it as paragraph break. | ||
We do this to support Obsidian callouts where the first paragraph can start | ||
immediately after the callout heading without a newline break in between. | ||
-} | ||
disrespectSoftbreak :: [B.Inline] -> ([B.Inline], Maybe B.Block) | ||
disrespectSoftbreak = \case | ||
[] -> ([], Nothing) | ||
(B.SoftBreak : rest) -> ([], Just (B.Para rest)) | ||
(x : xs) -> | ||
let (a, b) = disrespectSoftbreak xs | ||
in (x : a, b) | ||
|
||
defaultTitle :: CalloutType -> [B.Inline] | ||
defaultTitle t = | ||
[B.Str $ show t] | ||
|
||
-- | Parse, for example, "[!tip]" into 'Tip'. | ||
parseCalloutType :: Text -> Maybe CalloutType | ||
parseCalloutType = | ||
rightToMaybe . parse parser "<callout:type>" | ||
where | ||
parser :: M.Parsec Void Text CalloutType | ||
parser = do | ||
void $ M.string "[!" | ||
s <- T.toLower . toText <$> M.some M.letterChar | ||
void $ M.string "]" | ||
maybe (fail "Unknown") pure $ parseType s | ||
parseType :: Text -> Maybe CalloutType | ||
parseType s = | ||
msum $ flip fmap (universe @CalloutType) $ \t -> do | ||
guard $ s == T.toLower (show @Text t) | ||
Just t | ||
parse :: M.Parsec Void Text a -> String -> Text -> Either Text a | ||
parse p fn = | ||
first (toText . M.errorBundlePretty) | ||
. M.parse (p <* M.eof) fn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module Emanote.Pandoc.Renderer.CalloutSpec where | ||
|
||
import Emanote.Pandoc.Renderer.Callout | ||
import Hedgehog | ||
import Relude | ||
import Test.Hspec | ||
import Test.Hspec.Hedgehog | ||
|
||
spec :: Spec | ||
spec = do | ||
describe "callout" $ do | ||
it "type" . hedgehog $ do | ||
parseCalloutType "[!tip]" === Just Tip | ||
parseCalloutType "[!Note]" === Just Note | ||
parseCalloutType "[!INFO]" === Just Info |