diff --git a/Render.hs b/Render.hs
deleted file mode 100644
index d330b11..0000000
--- a/Render.hs
+++ /dev/null
@@ -1,203 +0,0 @@
--- \| Render.hs is a program to generate custom template:
--- - projects list from directory listing
--- - snippets from org mode file
---
--- nix develop --command ghcid ./Render.hs -T main
-{-# LANGUAGE BlockArguments #-}
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE ImportQualifiedPost #-}
-{-# LANGUAGE OverloadedRecordDot #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuasiQuotes #-}
-
-import Data.Aeson (FromJSON)
-import Data.ByteString qualified as BS
-import Data.ByteString.Char8 qualified as BS
-import Data.List (isSuffixOf, sortOn)
-import Data.String.QQ (s)
-import Data.Text qualified as Text
-import Data.Text.IO qualified as Text
-import Data.Tree
-import Data.Yaml hiding (Parser)
-import Lucid
-import Lucid.Base (makeAttribute, makeElement, makeElementNoEnd)
-import RIO
-import RIO.Text qualified
-import System.Directory (listDirectory)
-import System.FilePath
-import Text.Pandoc.Class (runIOorExplode)
-import Text.Pandoc.Definition
-import Text.Pandoc.Extensions
-import Text.Pandoc.Options (def, readerExtensions)
-import Text.Pandoc.Readers.Markdown (readMarkdown)
-import Text.Pandoc.Readers.Org (readOrg)
-import Text.Parsec qualified as Parsec
-import Text.Parsec.Text (Parser)
-
-header :: Text
-header =
- [s|
----
-title: Projects
-pandoc:
- rewriteClass:
- plist: grid md:grid-cols-3 gap-4 mb-5
- pcard: rounded border-2 border-blue-100 p-1
- ptitle: text-lg
- pdate: text-sm relative -top-3 -mb-3
- picon: relative -top-5 float right-0
----
-
-
-
-Here are some of the projects I have worked on, as an author or contributor.
-|]
-
-data Project = Project
- { fp :: FilePath
- , meta :: ProjectMeta
- , intro :: Text
- }
-
-data ProjectMeta = ProjectMeta
- { date :: Text
- , tags :: [Text]
- , title :: Text
- }
- deriving (Generic, FromJSON)
-
-parseProject :: FilePath -> IO Project
-parseProject fp = do
- putStrLn $ "[+] " <> fp
- ("---" : lines) <- BS.lines <$> BS.readFile fp
- let (yml, "---" : "" : intro : _) = break (== "---") lines
- pm <- decodeThrow (BS.unlines yml)
- pure $ Project fp pm (parseIntro $! decodeUtf8With lenientDecode intro)
-
-getIcon :: Project -> Maybe (Html ())
-getIcon p
- | "fractal" `elem` p.meta.tags = Just "🥦"
- | "design" `elem` p.meta.tags = Just "🎨"
- | "video" `elem` p.meta.tags = Just "🎥"
- | "library" `elem` p.meta.tags = Just "📖"
- | "music" `elem` p.meta.tags = Just "🎵"
- | "extension" `elem` p.meta.tags || "plugin" `elem` p.meta.tags = Just "âš™"
- | "cli" `elem` p.meta.tags = Just cliSvg
- | "web-service" `elem` p.meta.tags = Just srvSvg
- | "nix" `elem` p.meta.tags || "packaging" `elem` p.meta.tags = Just "📦"
- | "contributor" `elem` p.meta.tags = Just "🧑"
- | "game" `elem` p.meta.tags = Just "🎮"
- | "code" `elem` p.meta.tags || "keyboard" `elem` p.meta.tags = Just "⌨"
- | otherwise = Nothing
-
-viewBox_ = makeAttribute "viewBox"
-fill_ = makeAttribute "fill"
-d_ = makeAttribute "d"
-path_ = makeElement "path"
-
-srvSvg =
- with svg_ [xmlns_ "http://www.w3.org/2000/svg", viewBox_ "0 0 24 24", width_ "24", height_ "24"] do
- with path_ [fill_ "none", d_ "M0 0h24v24H0z"] mempty
- with path_ [d_ "M5 11h14V5H5v6zm16-7v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1zm-2 9H5v6h14v-6zM7 15h3v2H7v-2zm0-8h3v2H7V7z"] mempty
-
-cliSvg = with svg_ [xmlns_ "http://www.w3.org/2000/svg", viewBox_ "0 0 24 24", width_ "24", height_ "24"] do
- with path_ [fill_ "none", d_ "M0 0h24v24H0z"] mempty
- with path_ [d_ "M3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm9 12v2h6v-2h-6zm-3.586-3l-2.828 2.828L7 16.243 11.243 12 7 7.757 5.586 9.172 8.414 12z"] mempty
-
-renderProject :: Project -> Html ()
-renderProject p =
- with div_ [class_ "rounded border-2 border-blue-100 p-1"] do
- with div_ [class_ "text-lg"] do
- let t = Text.pack (takeBaseName $ fp p)
- with a_ [class_ "text-blue-600 mavenLinkBold hover:underline", href_ ("project/" <> t)] do
- toHtml (if (Text.length p.meta.title < Text.length t) then p.meta.title else t)
-
- case getIcon p of
- Just ico -> with span_ [class_ "float-right"] ico
- Nothing -> pure ()
-
- with span_ [class_ "text-sm relative -top-1"] (toHtml (p.meta.date))
- div_ (toHtml (intro p))
-
-renderProjects :: [Project] -> Html ()
-renderProjects xs = with div_ [class_ "grid md:grid-cols-3 gap-4 mb-5"] do
- traverse_ renderProject xs
-
-parseIntro :: Text -> Text
-parseIntro t = case Parsec.runParser introParser () "" t of
- Left e -> error (show t <> " -> " <> show e)
- Right xs -> (mconcat . takeWhile (/= ".") $ xs) <> "."
-
-introParser :: Parser [Text]
-introParser = Parsec.many1 (wordP <|> linkP <|> dotP)
- where
- dotP = "." <$ Parsec.char '.'
- wordP = Text.pack <$> Parsec.many1 (Parsec.satisfy (`notElem` ['.', '#', '[', ']']))
- linkP = do
- Parsec.optional (Parsec.char '#')
- Parsec.many1 (Parsec.char '[')
- l <- Text.pack <$> Parsec.many1 (Parsec.satisfy (`notElem` [']']))
- Parsec.many1 (Parsec.char ']')
- Parsec.optional $ do
- Parsec.char '('
- Parsec.many1 (Parsec.satisfy (`notElem` [')']))
- Parsec.char ')'
- Parsec.optional (Parsec.char '#')
- pure $ if Text.elem '|' l then Text.takeWhileEnd (/= '|') l else l
-
-formatIntro :: [Text] -> Text
-formatIntro = flip mappend "." . mconcat . takeWhile (/= ".")
-
-mainProjs :: IO ()
-mainProjs = do
- projFiles <- map (mappend "content/project/") <$> listDirectory "content/project"
- projs <- traverse parseProject projFiles
- renderToFile "content/templates/components/projects.tpl" (renderProjects (reverse $ sortOn (date . meta) projs))
-
--- (id, title)
-data DocHeading = DocHeading Text Text
-
-pandocTOCTree :: Pandoc -> Forest DocHeading
-pandocTOCTree (Pandoc _ blocks) = go [] 1 blocks
- where
- go acc _lvl [] = reverse acc
- go acc lvl (x : rest) = case x of
- Header hlvl (oid, _, _) [Str title]
- | hlvl == lvl ->
- -- TODO: support nested heading
- let oh = DocHeading oid title
- childs = []
- in go (Node oh childs : acc) lvl rest
- _ -> go acc lvl rest
-
-renderTOCTree :: Text -> Tree DocHeading -> Html ()
-renderTOCTree base (Node (DocHeading oid title) childs) = li_ do
- with a_ [href_ (mconcat [base, "#", oid])] do
- (toHtml title)
- unless (null childs) do
- ul_ do
- traverse_ (renderTOCTree base) childs
-
-doRead :: FilePath -> IO Pandoc
-doRead fp = do
- content <- Text.readFile fp
- runIOorExplode $
- if ".org" `isSuffixOf` fp
- then readOrg readerOpts content
- else readMarkdown readerOpts content
- where
- readerOpts = def{readerExtensions = extensionsFromList (exts)}
- exts = [Ext_auto_identifiers]
-
-renderTOCTemplate :: FilePath -> Pandoc -> IO ()
-renderTOCTemplate fp doc = do
- renderToFile fp do
- ul_ do
- traverse_ (renderTOCTree "snippets") (pandocTOCTree doc)
-
-mainSnippets :: IO ()
-mainSnippets = do
- renderTOCTemplate "content/templates/components/toc-snippets.tpl" =<< doRead "content/snippets.org"
-
-main :: IO ()
-main = mainProjs >> mainSnippets
diff --git a/Tutorials/Slug.md b/Tutorials/Slug.md
new file mode 100644
index 0000000..1696f72
--- /dev/null
+++ b/Tutorials/Slug.md
@@ -0,0 +1,24 @@
+---
+page:
+ headHtml: |
+
+---
+By default the filesystem path is used to determine the note URL. You can override this using the `slug` frontmatter metadata.
+
+## Overriding the URL
+
+For example,
+
+- Source: https://raw.githubusercontent.com/srid/srid/master/free/Actualism%20Method.md
+- Rendered: https://srid.ca/method
+
+Notice that in the source, we see:
+
+```yaml
+---
+slug: method
+---
+```
+
+This makes Emantoe use `/method` as the URL path for this note. Without this, by default, Emanote would use `/free/Actualism%20Method`.
+
diff --git a/ema-template.cabal b/ema-template.cabal
deleted file mode 100644
index dc20b7d..0000000
--- a/ema-template.cabal
+++ /dev/null
@@ -1,106 +0,0 @@
-cabal-version: 2.4
-name: ema-template
-version: 0.1.0.0
-license: AGPL-3.0-only
-copyright: 2022 Sridhar Ratnakumar
-maintainer: srid@srid.ca
-author: Sridhar Ratnakumar
-category: Web
-
--- A short (one-line) description of the package.
--- synopsis:
-
--- A longer description of the package.
--- description:
-
--- A URL where users can report bugs.
--- bug-reports:
-
-extra-source-files:
- LICENSE
- README.md
-
-data-dir: static
-data-files:
- *.css
- *.svg
-
-executable ema-template
- build-depends:
- , aeson
- , async
- , base >=4 && <5
- , blaze-html
- , blaze-markup
- , containers
- , data-default
- , directory
- , ema >=0.10
- , ema-extra >=0.10
- , ema-generics >=0.10
- , filepath
- , generic-optics
- , monad-logger
- , optics-core
- , optparse-applicative
- , relude >=1.0
- , text
- , time
- , unionmount >=0.2
- , unliftio
-
- mixins:
- base hiding (Prelude),
- relude (Relude as Prelude, Relude.Container.One),
- relude
-
- ghc-options:
- -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns
- -Wmissing-deriving-strategies -Wunused-foralls -Wunused-foralls
- -fprint-explicit-foralls -fprint-explicit-kinds -threaded
-
- default-extensions:
- BangPatterns
- ConstraintKinds
- DataKinds
- DeriveAnyClass
- DeriveDataTypeable
- DeriveFoldable
- DeriveFunctor
- DeriveGeneric
- DeriveLift
- DeriveTraversable
- DerivingStrategies
- DerivingVia
- EmptyCase
- EmptyDataDecls
- EmptyDataDeriving
- ExistentialQuantification
- ExplicitForAll
- FlexibleContexts
- FlexibleInstances
- GADTSyntax
- GeneralisedNewtypeDeriving
- ImportQualifiedPost
- KindSignatures
- LambdaCase
- MultiParamTypeClasses
- MultiWayIf
- NoStarIsType
- NumericUnderscores
- OverloadedStrings
- PolyKinds
- PostfixOperators
- RankNTypes
- ScopedTypeVariables
- StandaloneDeriving
- StandaloneKindSignatures
- TupleSections
- TypeApplications
- TypeFamilies
- TypeOperators
- ViewPatterns
-
- main-is: Main.hs
- hs-source-dirs: src
- default-language: Haskell2010
diff --git a/flake.lock b/flake.lock
index 6712526..0f63492 100644
--- a/flake.lock
+++ b/flake.lock
@@ -154,7 +154,7 @@
"commonmark-simple": "commonmark-simple",
"commonmark-wikilink": "commonmark-wikilink",
"ema": "ema",
- "emanote-template": "emanote-template_2",
+ "emanote-template": [],
"flake-parts": "flake-parts_2",
"flake-root": "flake-root_2",
"haskell-flake": "haskell-flake_2",
@@ -166,17 +166,16 @@
"unionmount": "unionmount_2"
},
"locked": {
- "lastModified": 1719828900,
- "narHash": "sha256-t4Bp56TAZwOwAS6ezev+wE3qtcpBCOkHVNnpbaG47JE=",
+ "lastModified": 1719887178,
+ "narHash": "sha256-GAxmOxH0NnzgIjtcY5OvLguXlQuh2Hs82pQ8WLBai04=",
"owner": "srid",
"repo": "emanote",
- "rev": "32666807bc2966c796eb95364716dfb08c50cefe",
+ "rev": "e20dbc918df86436ad1e97c79b74337b3625798f",
"type": "github"
},
"original": {
"owner": "srid",
"repo": "emanote",
- "rev": "32666807bc2966c796eb95364716dfb08c50cefe",
"type": "github"
}
},
@@ -196,22 +195,6 @@
"type": "github"
}
},
- "emanote-template_2": {
- "flake": false,
- "locked": {
- "lastModified": 1720320666,
- "narHash": "sha256-Q6jBdnWi/K6Zlv8igHy8DFi0gHE6/aNWABChvBzqVJk=",
- "owner": "srid",
- "repo": "emanote-template",
- "rev": "4441176de6094af603e75dfffb2ecc56cb2f33b9",
- "type": "github"
- },
- "original": {
- "owner": "srid",
- "repo": "emanote-template",
- "type": "github"
- }
- },
"emanote_2": {
"inputs": {
"commonmark-simple": "commonmark-simple_2",
@@ -454,26 +437,17 @@
"type": "github"
}
},
- "nixpkgs_3": {
- "locked": {
- "lastModified": 1672755833,
- "narHash": "sha256-AmPzlvY1Y5codnytZCDn2wlhVa8rDHNib5wBWtcD7c4=",
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "3665c429d349fbda46b0651e554cca8434452748",
- "type": "github"
- },
- "original": {
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "3665c429d349fbda46b0651e554cca8434452748",
- "type": "github"
- }
- },
"root": {
"inputs": {
"emanote": "emanote",
- "nixpkgs": "nixpkgs_3"
+ "flake-parts": [
+ "emanote",
+ "flake-parts"
+ ],
+ "nixpkgs": [
+ "emanote",
+ "nixpkgs"
+ ]
}
},
"systems": {
diff --git a/flake.nix b/flake.nix
index f1706a1..33ba1b9 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,68 +1,37 @@
{
- inputs = {
- emanote.url = "github:srid/emanote/32666807bc2966c796eb95364716dfb08c50cefe";
- nixpkgs.url = "github:NixOS/nixpkgs/3665c429d349fbda46b0651e554cca8434452748";
+ nixConfig = {
+ extra-substituters = "https://cache.garnix.io";
+ extra-trusted-public-keys = "cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g=";
};
- outputs = inputs: let
- emanote = inputs.emanote.packages.x86_64-linux.default;
- pkgs = import inputs.nixpkgs {system = "x86_64-linux";};
- ebml = pkgs.fetchFromGitHub {
- owner = "TristanCacqueray";
- repo = "haskell-ebml";
- rev = "aff25512b52e48e92d77cd59019a0291a8b43bf4";
- sha256 = "sha256-U2Mo83gr7dLm+rRKOLzS9LZUaZ90ECO6Zjbv6maflyc=";
- };
- ghc = pkgs.haskellPackages.ghcWithPackages (p: [
- p.markdown-unlit
- p.rio
- p.string-qq
- p.ki
- p.servant
- p.servant-websockets
- p.servant
- p.lucid
- p.servant-lucid
- p.websockets
- p.yaml
- p.pandoc
- p.pandoc-types
- (pkgs.haskellPackages.callCabal2nix "ebml" ebml {})
- ]);
- website = pkgs.stdenv.mkDerivation {
- name = "felipemarcelino.io-pages";
- buildInputs = [emanote];
- src = inputs.self;
- # https://github.com/jaspervdj/hakyll/issues/614
- # https://github.com/NixOS/nix/issues/318#issuecomment-52986702
- # https://github.com/MaxDaten/brutal-recipes/blob/source/default.nix#L24
- LOCALE_ARCHIVE =
- pkgs.lib.optionalString (pkgs.buildPlatform.libc == "glibc")
- "${pkgs.glibcLocales}/lib/locale/locale-archive";
- LANG = "en_US.UTF-8";
+ inputs = {
+ emanote.url = "github:srid/emanote";
+ emanote.inputs.emanote-template.follows = "";
+ nixpkgs.follows = "emanote/nixpkgs";
+ flake-parts.follows = "emanote/flake-parts";
+ };
- buildPhase = ''
- mkdir _out
- emanote -L content/ gen _out
- '';
- installPhase = ''
- mv _out $out
- '';
+ outputs = inputs@{ self, flake-parts, nixpkgs, ... }:
+ flake-parts.lib.mkFlake { inherit inputs; } {
+ systems = nixpkgs.lib.systems.flakeExposed;
+ imports = [ inputs.emanote.flakeModule ];
+ perSystem = { self', pkgs, system, ... }: {
+ emanote = {
+ # By default, the 'emanote' flake input is used.
+ # package = inputs.emanote.packages.${system}.default;
+ sites."default" = {
+ layers = [{ path = ./.; pathString = "."; }];
+ # port = 8080;
+ baseUrl = "/emanote-template/"; # Change to "/" (or remove it entirely) if using CNAME
+ # prettyUrls = true;
+ };
+ };
+ devShells.default = pkgs.mkShell {
+ buildInputs = [
+ pkgs.nixpkgs-fmt
+ ];
+ };
+ formatter = pkgs.nixpkgs-fmt;
+ };
};
- run = pkgs.writeScriptBin "run" ''
- ${emanote}/bin/emanote -L content/ run --host 0.0.0.0 --port 8080
- '';
- in {
- packages.x86_64-linux.default = website;
- apps."x86_64-linux".default = {
- type = "app";
- program = "${run}/bin/run";
- };
- devShells."x86_64-linux".default =
- pkgs.mkShell {buildInputs = [ghc pkgs.ghcid emanote];};
- devShells."x86_64-linux".gstreamer = pkgs.mkShell {
- buildInputs = [ghc pkgs.ghcid pkgs.gst_all_1.gstreamer];
- GST_PLUGIN_PATH = "${pkgs.gst_all_1.gst-plugins-base}/lib/gstreamer-1.0/:${pkgs.gst_all_1.gst-plugins-good}/lib/gstreamer-1.0/";
- };
- };
}
diff --git a/index.yaml b/index.yaml
index f48f69b..b3d3767 100644
--- a/index.yaml
+++ b/index.yaml
@@ -19,6 +19,7 @@ template:
theme: red
#iconUrl: static/favicon.jpeg
urlStrategy: pretty
+ editBaseUrl: https://github.com/srid/emanote-template/edit/master
pandoc:
rewriteClass:
prose: max-w-prose mx-auto
diff --git a/justfile b/justfile
deleted file mode 100644
index 4a39b3f..0000000
--- a/justfile
+++ /dev/null
@@ -1,19 +0,0 @@
-default:
- @just --list
-
-# Run hoogle
-docs:
- echo http://127.0.0.1:8888
- hoogle serve -p 8888 --local
-
-# Run cabal repl
-repl *ARGS:
- cabal repl {{ARGS}}
-
-# Autoformat the project tree
-fmt:
- treefmt
-
-# Run the dev server (ghcid + tailwind)
-run:
- ema-tailwind-run
diff --git a/src/Main.hs b/src/Main.hs
deleted file mode 100644
index 4c918a9..0000000
--- a/src/Main.hs
+++ /dev/null
@@ -1,158 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE UndecidableInstances #-}
-
-module Main where
-
-import Data.Default (def)
-import Data.Generics.Sum.Any (AsAny (_As))
-import Ema
-import Ema.CLI qualified
-import Ema.Route.Generic.TH
-import Ema.Route.Lib.Extra.StaticRoute qualified as SR
-import Optics.Core (Prism', (%))
-import Options.Applicative
-import Text.Blaze.Html.Renderer.Utf8 qualified as RU
-import Text.Blaze.Html5 ((!))
-import Text.Blaze.Html5 qualified as H
-import Text.Blaze.Html5.Attributes qualified as A
-
-data Model = Model
- { modelBaseUrl :: Text
- , modelStatic :: SR.Model
- }
- deriving stock (Eq, Show, Generic)
-
-data HtmlRoute
- = HtmlRoute_Index
- | HtmlRoute_About
- deriving stock (Show, Eq, Ord, Generic, Enum, Bounded)
-
-deriveGeneric ''HtmlRoute
-deriveIsRoute ''HtmlRoute [t|'[]|]
-
-type StaticRoute = SR.StaticRoute "static"
-
-data Route
- = Route_Html HtmlRoute
- | Route_Static StaticRoute
- deriving stock (Eq, Show, Ord, Generic)
-
-deriveGeneric ''Route
-deriveIsRoute
- ''Route
- [t|
- [ -- To render a `Route` we need `Model`
- WithModel Model
- , -- Override default sub-route encoding (to avoid the folder prefix in encoded URLs)
- WithSubRoutes [HtmlRoute, StaticRoute]
- ]
- |]
-
-instance EmaSite Route where
- type SiteArg Route = CliArgs
- siteInput cliAct args = do
- staticRouteDyn <- siteInput @StaticRoute cliAct ()
- pure $ Model (cliArgsBaseUrl args) <$> staticRouteDyn
- siteOutput rp m = \case
- Route_Html r ->
- pure $ Ema.AssetGenerated Ema.Html $ renderHtmlRoute rp m r
- Route_Static r ->
- siteOutput (rp % (_As @"Route_Static")) (modelStatic m) r
-
-renderHtmlRoute :: Prism' FilePath Route -> Model -> HtmlRoute -> LByteString
-renderHtmlRoute rp m r = do
- RU.renderHtml $ do
- H.docType
- H.html ! A.lang "en" $ do
- H.head $ do
- renderHead rp m r
- H.body ! A.class_ "bg-gray-50" $ do
- renderBody rp m r
-
-renderHead :: Prism' FilePath Route -> Model -> HtmlRoute -> H.Html
-renderHead rp model r = do
- H.meta ! A.charset "UTF-8"
- H.meta ! A.name "viewport" ! A.content "width=device-width, initial-scale=1"
- H.title $ H.toHtml $ routeTitle r <> " - Ema Template"
- H.base ! A.href (H.toValue $ modelBaseUrl model)
- H.link ! A.rel "stylesheet" ! A.href (staticRouteUrl rp model "tailwind.css")
-
-renderBody :: Prism' FilePath Route -> Model -> HtmlRoute -> H.Html
-renderBody rp model r = do
- H.div ! A.class_ "container mx-auto mt-8 p-4 max-w-prose border-2 bg-white rounded-lg shadow" $ do
- renderNavbar rp r
- H.h1 ! A.class_ "text-3xl font-bold" $ H.toHtml $ routeTitle r
- case r of
- HtmlRoute_Index -> do
- "You are on the index page. Want to see "
- routeLink rp HtmlRoute_About "About"
- "?"
- HtmlRoute_About -> do
- "You are on the about page."
- H.a ! A.href (staticRouteUrl rp model "logo.svg") ! A.target "_blank" $ do
- H.img ! A.src (staticRouteUrl rp model "logo.svg") ! A.class_ "py-4 w-32" ! A.alt "Ema Logo"
-
-renderNavbar :: Prism' FilePath Route -> HtmlRoute -> H.Html
-renderNavbar rp currentRoute =
- H.nav ! A.class_ "w-full text-xl font-bold flex space-x-4 mb-4" $ do
- forM_ (universe @HtmlRoute) $ \r ->
- let extraClass = if r == currentRoute then "bg-rose-400 text-white" else "text-gray-700"
- in H.a
- ! A.href (H.toValue $ routeUrl rp $ Route_Html r)
- ! A.class_ ("rounded p-2 " <> extraClass)
- $ H.toHtml
- $ routeTitle r
-
-routeTitle :: HtmlRoute -> Text
-routeTitle r = case r of
- HtmlRoute_Index -> "Home"
- HtmlRoute_About -> "About"
-
-routeLink :: Prism' FilePath Route -> HtmlRoute -> H.Html -> H.Html
-routeLink rp r =
- H.a
- ! A.href (H.toValue $ routeUrl rp $ Route_Html r)
- ! A.class_ "text-rose-400"
-
--- | Link to a file under ./static
-staticRouteUrl :: (IsString r) => Prism' FilePath Route -> Model -> FilePath -> r
-staticRouteUrl rp m =
- SR.staticRouteUrl (rp % (_As @"Route_Static")) (modelStatic m)
-
--- CLI argument handling
--- ---------------------
-
-data CliArgs = CliArgs
- { cliArgsBaseUrl :: Text
- , cliArgsEmaCli :: Ema.CLI.Cli
- }
- deriving stock (Eq, Show)
-
-parseCliArgs :: IO CliArgs
-parseCliArgs =
- execParser $ parserInfo cliParser
- where
- cliParser :: Parser CliArgs
- cliParser =
- CliArgs
- <$> option str (long "base-url" <> metavar "BASE_URL" <> help "Base URL to use in " <> value "/")
- <*> Ema.CLI.cliParser
- parserInfo :: Parser a -> ParserInfo a
- parserInfo p =
- info
- (versionOption <*> p <**> helper)
- ( fullDesc
- <> progDesc "ema-template: TODO"
- <> header "ema-template"
- )
- where
- versionOption = infoOption "0.1" (long "version" <> help "Show version")
-
--- Main entrypoint
--- ---------------
-
-main :: IO ()
-main = do
- cliArgs <- parseCliArgs
- let cfg = SiteConfig (cliArgsEmaCli cliArgs) def
- void $ Ema.runSiteWith @Route cfg cliArgs
diff --git a/static/logo.svg b/static/logo.svg
deleted file mode 100644
index fcfc3c7..0000000
--- a/static/logo.svg
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
diff --git a/static/tailwind.css b/static/tailwind.css
deleted file mode 100644
index 5782005..0000000
--- a/static/tailwind.css
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
-! tailwindcss v3.4.6 | MIT License | https://tailwindcss.com
-*/
-
-/*
-1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
-2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
-*/
-
-*,
-::before,
-::after {
- box-sizing: border-box;
- /* 1 */
- border-width: 0;
- /* 2 */
- border-style: solid;
- /* 2 */
- border-color: #e5e7eb;
- /* 2 */
-}
-
-::before,
-::after {
- --tw-content: '';
-}
-
-/*
-1. Use a consistent sensible line-height in all browsers.
-2. Prevent adjustments of font size after orientation changes in iOS.
-3. Use a more readable tab size.
-4. Use the user's configured `sans` font-family by default.
-5. Use the user's configured `sans` font-feature-settings by default.
-6. Use the user's configured `sans` font-variation-settings by default.
-7. Disable tap highlights on iOS
-*/
-
-html,
-:host {
- line-height: 1.5;
- /* 1 */
- -webkit-text-size-adjust: 100%;
- /* 2 */
- -moz-tab-size: 4;
- /* 3 */
- -o-tab-size: 4;
- tab-size: 4;
- /* 3 */
- font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- /* 4 */
- font-feature-settings: normal;
- /* 5 */
- font-variation-settings: normal;
- /* 6 */
- -webkit-tap-highlight-color: transparent;
- /* 7 */
-}
-
-/*
-1. Remove the margin in all browsers.
-2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
-*/
-
-body {
- margin: 0;
- /* 1 */
- line-height: inherit;
- /* 2 */
-}
-
-/*
-1. Add the correct height in Firefox.
-2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
-3. Ensure horizontal rules are visible by default.
-*/
-
-hr {
- height: 0;
- /* 1 */
- color: inherit;
- /* 2 */
- border-top-width: 1px;
- /* 3 */
-}
-
-/*
-Add the correct text decoration in Chrome, Edge, and Safari.
-*/
-
-abbr:where([title]) {
- -webkit-text-decoration: underline dotted;
- text-decoration: underline dotted;
-}
-
-/*
-Remove the default font size and weight for headings.
-*/
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- font-size: inherit;
- font-weight: inherit;
-}
-
-/*
-Reset links to optimize for opt-in styling instead of opt-out.
-*/
-
-a {
- color: inherit;
- text-decoration: inherit;
-}
-
-/*
-Add the correct font weight in Edge and Safari.
-*/
-
-b,
-strong {
- font-weight: bolder;
-}
-
-/*
-1. Use the user's configured `mono` font-family by default.
-2. Use the user's configured `mono` font-feature-settings by default.
-3. Use the user's configured `mono` font-variation-settings by default.
-4. Correct the odd `em` font sizing in all browsers.
-*/
-
-code,
-kbd,
-samp,
-pre {
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
- /* 1 */
- font-feature-settings: normal;
- /* 2 */
- font-variation-settings: normal;
- /* 3 */
- font-size: 1em;
- /* 4 */
-}
-
-/*
-Add the correct font size in all browsers.
-*/
-
-small {
- font-size: 80%;
-}
-
-/*
-Prevent `sub` and `sup` elements from affecting the line height in all browsers.
-*/
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-sup {
- top: -0.5em;
-}
-
-/*
-1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
-2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
-3. Remove gaps between table borders by default.
-*/
-
-table {
- text-indent: 0;
- /* 1 */
- border-color: inherit;
- /* 2 */
- border-collapse: collapse;
- /* 3 */
-}
-
-/*
-1. Change the font styles in all browsers.
-2. Remove the margin in Firefox and Safari.
-3. Remove default padding in all browsers.
-*/
-
-button,
-input,
-optgroup,
-select,
-textarea {
- font-family: inherit;
- /* 1 */
- font-feature-settings: inherit;
- /* 1 */
- font-variation-settings: inherit;
- /* 1 */
- font-size: 100%;
- /* 1 */
- font-weight: inherit;
- /* 1 */
- line-height: inherit;
- /* 1 */
- letter-spacing: inherit;
- /* 1 */
- color: inherit;
- /* 1 */
- margin: 0;
- /* 2 */
- padding: 0;
- /* 3 */
-}
-
-/*
-Remove the inheritance of text transform in Edge and Firefox.
-*/
-
-button,
-select {
- text-transform: none;
-}
-
-/*
-1. Correct the inability to style clickable types in iOS and Safari.
-2. Remove default button styles.
-*/
-
-button,
-input:where([type='button']),
-input:where([type='reset']),
-input:where([type='submit']) {
- -webkit-appearance: button;
- /* 1 */
- background-color: transparent;
- /* 2 */
- background-image: none;
- /* 2 */
-}
-
-/*
-Use the modern Firefox focus style for all focusable elements.
-*/
-
-:-moz-focusring {
- outline: auto;
-}
-
-/*
-Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
-*/
-
-:-moz-ui-invalid {
- box-shadow: none;
-}
-
-/*
-Add the correct vertical alignment in Chrome and Firefox.
-*/
-
-progress {
- vertical-align: baseline;
-}
-
-/*
-Correct the cursor style of increment and decrement buttons in Safari.
-*/
-
-::-webkit-inner-spin-button,
-::-webkit-outer-spin-button {
- height: auto;
-}
-
-/*
-1. Correct the odd appearance in Chrome and Safari.
-2. Correct the outline style in Safari.
-*/
-
-[type='search'] {
- -webkit-appearance: textfield;
- /* 1 */
- outline-offset: -2px;
- /* 2 */
-}
-
-/*
-Remove the inner padding in Chrome and Safari on macOS.
-*/
-
-::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/*
-1. Correct the inability to style clickable types in iOS and Safari.
-2. Change font properties to `inherit` in Safari.
-*/
-
-::-webkit-file-upload-button {
- -webkit-appearance: button;
- /* 1 */
- font: inherit;
- /* 2 */
-}
-
-/*
-Add the correct display in Chrome and Safari.
-*/
-
-summary {
- display: list-item;
-}
-
-/*
-Removes the default spacing and border for appropriate elements.
-*/
-
-blockquote,
-dl,
-dd,
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-hr,
-figure,
-p,
-pre {
- margin: 0;
-}
-
-fieldset {
- margin: 0;
- padding: 0;
-}
-
-legend {
- padding: 0;
-}
-
-ol,
-ul,
-menu {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-/*
-Reset default styling for dialogs.
-*/
-
-dialog {
- padding: 0;
-}
-
-/*
-Prevent resizing textareas horizontally by default.
-*/
-
-textarea {
- resize: vertical;
-}
-
-/*
-1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
-2. Set the default placeholder color to the user's configured gray 400 color.
-*/
-
-input::-moz-placeholder, textarea::-moz-placeholder {
- opacity: 1;
- /* 1 */
- color: #9ca3af;
- /* 2 */
-}
-
-input::placeholder,
-textarea::placeholder {
- opacity: 1;
- /* 1 */
- color: #9ca3af;
- /* 2 */
-}
-
-/*
-Set the default cursor for buttons.
-*/
-
-button,
-[role="button"] {
- cursor: pointer;
-}
-
-/*
-Make sure disabled buttons don't get the pointer cursor.
-*/
-
-:disabled {
- cursor: default;
-}
-
-/*
-1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
-2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
- This can trigger a poorly considered lint error in some tools but is included by design.
-*/
-
-img,
-svg,
-video,
-canvas,
-audio,
-iframe,
-embed,
-object {
- display: block;
- /* 1 */
- vertical-align: middle;
- /* 2 */
-}
-
-/*
-Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
-*/
-
-img,
-video {
- max-width: 100%;
- height: auto;
-}
-
-/* Make elements with the HTML hidden attribute stay hidden by default */
-
-[hidden] {
- display: none;
-}
-
-[type='text'],input:where(:not([type])),[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- background-color: #fff;
- border-color: #6b7280;
- border-width: 1px;
- border-radius: 0px;
- padding-top: 0.5rem;
- padding-right: 0.75rem;
- padding-bottom: 0.5rem;
- padding-left: 0.75rem;
- font-size: 1rem;
- line-height: 1.5rem;
- --tw-shadow: 0 0 #0000;
-}
-
-[type='text']:focus, input:where(:not([type])):focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus {
- outline: 2px solid transparent;
- outline-offset: 2px;
- --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
- --tw-ring-offset-width: 0px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: #2563eb;
- --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
- border-color: #2563eb;
-}
-
-input::-moz-placeholder, textarea::-moz-placeholder {
- color: #6b7280;
- opacity: 1;
-}
-
-input::placeholder,textarea::placeholder {
- color: #6b7280;
- opacity: 1;
-}
-
-::-webkit-datetime-edit-fields-wrapper {
- padding: 0;
-}
-
-::-webkit-date-and-time-value {
- min-height: 1.5em;
- text-align: inherit;
-}
-
-::-webkit-datetime-edit {
- display: inline-flex;
-}
-
-::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field {
- padding-top: 0;
- padding-bottom: 0;
-}
-
-select {
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
- background-position: right 0.5rem center;
- background-repeat: no-repeat;
- background-size: 1.5em 1.5em;
- padding-right: 2.5rem;
- -webkit-print-color-adjust: exact;
- print-color-adjust: exact;
-}
-
-[multiple],[size]:where(select:not([size="1"])) {
- background-image: initial;
- background-position: initial;
- background-repeat: unset;
- background-size: initial;
- padding-right: 0.75rem;
- -webkit-print-color-adjust: unset;
- print-color-adjust: unset;
-}
-
-[type='checkbox'],[type='radio'] {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- padding: 0;
- -webkit-print-color-adjust: exact;
- print-color-adjust: exact;
- display: inline-block;
- vertical-align: middle;
- background-origin: border-box;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
- flex-shrink: 0;
- height: 1rem;
- width: 1rem;
- color: #2563eb;
- background-color: #fff;
- border-color: #6b7280;
- border-width: 1px;
- --tw-shadow: 0 0 #0000;
-}
-
-[type='checkbox'] {
- border-radius: 0px;
-}
-
-[type='radio'] {
- border-radius: 100%;
-}
-
-[type='checkbox']:focus,[type='radio']:focus {
- outline: 2px solid transparent;
- outline-offset: 2px;
- --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
- --tw-ring-offset-width: 2px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: #2563eb;
- --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
-}
-
-[type='checkbox']:checked,[type='radio']:checked {
- border-color: transparent;
- background-color: currentColor;
- background-size: 100% 100%;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-[type='checkbox']:checked {
- background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
-}
-
-@media (forced-colors: active) {
- [type='checkbox']:checked {
- -webkit-appearance: auto;
- -moz-appearance: auto;
- appearance: auto;
- }
-}
-
-[type='radio']:checked {
- background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
-}
-
-@media (forced-colors: active) {
- [type='radio']:checked {
- -webkit-appearance: auto;
- -moz-appearance: auto;
- appearance: auto;
- }
-}
-
-[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus {
- border-color: transparent;
- background-color: currentColor;
-}
-
-[type='checkbox']:indeterminate {
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");
- border-color: transparent;
- background-color: currentColor;
- background-size: 100% 100%;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-@media (forced-colors: active) {
- [type='checkbox']:indeterminate {
- -webkit-appearance: auto;
- -moz-appearance: auto;
- appearance: auto;
- }
-}
-
-[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus {
- border-color: transparent;
- background-color: currentColor;
-}
-
-[type='file'] {
- background: unset;
- border-color: inherit;
- border-width: 0;
- border-radius: 0;
- padding: 0;
- font-size: unset;
- line-height: inherit;
-}
-
-[type='file']:focus {
- outline: 1px solid ButtonText;
- outline: 1px auto -webkit-focus-ring-color;
-}
-
-*, ::before, ::after {
- --tw-border-spacing-x: 0;
- --tw-border-spacing-y: 0;
- --tw-translate-x: 0;
- --tw-translate-y: 0;
- --tw-rotate: 0;
- --tw-skew-x: 0;
- --tw-skew-y: 0;
- --tw-scale-x: 1;
- --tw-scale-y: 1;
- --tw-pan-x: ;
- --tw-pan-y: ;
- --tw-pinch-zoom: ;
- --tw-scroll-snap-strictness: proximity;
- --tw-gradient-from-position: ;
- --tw-gradient-via-position: ;
- --tw-gradient-to-position: ;
- --tw-ordinal: ;
- --tw-slashed-zero: ;
- --tw-numeric-figure: ;
- --tw-numeric-spacing: ;
- --tw-numeric-fraction: ;
- --tw-ring-inset: ;
- --tw-ring-offset-width: 0px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: rgb(59 130 246 / 0.5);
- --tw-ring-offset-shadow: 0 0 #0000;
- --tw-ring-shadow: 0 0 #0000;
- --tw-shadow: 0 0 #0000;
- --tw-shadow-colored: 0 0 #0000;
- --tw-blur: ;
- --tw-brightness: ;
- --tw-contrast: ;
- --tw-grayscale: ;
- --tw-hue-rotate: ;
- --tw-invert: ;
- --tw-saturate: ;
- --tw-sepia: ;
- --tw-drop-shadow: ;
- --tw-backdrop-blur: ;
- --tw-backdrop-brightness: ;
- --tw-backdrop-contrast: ;
- --tw-backdrop-grayscale: ;
- --tw-backdrop-hue-rotate: ;
- --tw-backdrop-invert: ;
- --tw-backdrop-opacity: ;
- --tw-backdrop-saturate: ;
- --tw-backdrop-sepia: ;
- --tw-contain-size: ;
- --tw-contain-layout: ;
- --tw-contain-paint: ;
- --tw-contain-style: ;
-}
-
-::backdrop {
- --tw-border-spacing-x: 0;
- --tw-border-spacing-y: 0;
- --tw-translate-x: 0;
- --tw-translate-y: 0;
- --tw-rotate: 0;
- --tw-skew-x: 0;
- --tw-skew-y: 0;
- --tw-scale-x: 1;
- --tw-scale-y: 1;
- --tw-pan-x: ;
- --tw-pan-y: ;
- --tw-pinch-zoom: ;
- --tw-scroll-snap-strictness: proximity;
- --tw-gradient-from-position: ;
- --tw-gradient-via-position: ;
- --tw-gradient-to-position: ;
- --tw-ordinal: ;
- --tw-slashed-zero: ;
- --tw-numeric-figure: ;
- --tw-numeric-spacing: ;
- --tw-numeric-fraction: ;
- --tw-ring-inset: ;
- --tw-ring-offset-width: 0px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: rgb(59 130 246 / 0.5);
- --tw-ring-offset-shadow: 0 0 #0000;
- --tw-ring-shadow: 0 0 #0000;
- --tw-shadow: 0 0 #0000;
- --tw-shadow-colored: 0 0 #0000;
- --tw-blur: ;
- --tw-brightness: ;
- --tw-contrast: ;
- --tw-grayscale: ;
- --tw-hue-rotate: ;
- --tw-invert: ;
- --tw-saturate: ;
- --tw-sepia: ;
- --tw-drop-shadow: ;
- --tw-backdrop-blur: ;
- --tw-backdrop-brightness: ;
- --tw-backdrop-contrast: ;
- --tw-backdrop-grayscale: ;
- --tw-backdrop-hue-rotate: ;
- --tw-backdrop-invert: ;
- --tw-backdrop-opacity: ;
- --tw-backdrop-saturate: ;
- --tw-backdrop-sepia: ;
- --tw-contain-size: ;
- --tw-contain-layout: ;
- --tw-contain-paint: ;
- --tw-contain-style: ;
-}
-
-.container {
- width: 100%;
-}
-
-@media (min-width: 640px) {
- .container {
- max-width: 640px;
- }
-}
-
-@media (min-width: 768px) {
- .container {
- max-width: 768px;
- }
-}
-
-@media (min-width: 1024px) {
- .container {
- max-width: 1024px;
- }
-}
-
-@media (min-width: 1280px) {
- .container {
- max-width: 1280px;
- }
-}
-
-@media (min-width: 1536px) {
- .container {
- max-width: 1536px;
- }
-}
-
-.static {
- position: static;
-}
-
-.mx-auto {
- margin-left: auto;
- margin-right: auto;
-}
-
-.mb-4 {
- margin-bottom: 1rem;
-}
-
-.mt-8 {
- margin-top: 2rem;
-}
-
-.flex {
- display: flex;
-}
-
-.w-32 {
- width: 8rem;
-}
-
-.w-full {
- width: 100%;
-}
-
-.max-w-prose {
- max-width: 65ch;
-}
-
-.space-x-4 > :not([hidden]) ~ :not([hidden]) {
- --tw-space-x-reverse: 0;
- margin-right: calc(1rem * var(--tw-space-x-reverse));
- margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
-}
-
-.rounded {
- border-radius: 0.25rem;
-}
-
-.rounded-lg {
- border-radius: 0.5rem;
-}
-
-.border-2 {
- border-width: 2px;
-}
-
-.bg-gray-50 {
- --tw-bg-opacity: 1;
- background-color: rgb(249 250 251 / var(--tw-bg-opacity));
-}
-
-.bg-rose-400 {
- --tw-bg-opacity: 1;
- background-color: rgb(251 113 133 / var(--tw-bg-opacity));
-}
-
-.bg-white {
- --tw-bg-opacity: 1;
- background-color: rgb(255 255 255 / var(--tw-bg-opacity));
-}
-
-.p-2 {
- padding: 0.5rem;
-}
-
-.p-4 {
- padding: 1rem;
-}
-
-.py-4 {
- padding-top: 1rem;
- padding-bottom: 1rem;
-}
-
-.text-3xl {
- font-size: 1.875rem;
- line-height: 2.25rem;
-}
-
-.text-xl {
- font-size: 1.25rem;
- line-height: 1.75rem;
-}
-
-.font-bold {
- font-weight: 700;
-}
-
-.text-gray-700 {
- --tw-text-opacity: 1;
- color: rgb(55 65 81 / var(--tw-text-opacity));
-}
-
-.text-rose-400 {
- --tw-text-opacity: 1;
- color: rgb(251 113 133 / var(--tw-text-opacity));
-}
-
-.text-white {
- --tw-text-opacity: 1;
- color: rgb(255 255 255 / var(--tw-text-opacity));
-}
-
-.shadow {
- --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
- --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
- box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
-}
\ No newline at end of file