web-view-colonnade (empty) → 0.1.0.0
raw patch · 6 files changed
+832/−0 lines, 6 filesdep +basedep +colonnadedep +containers
Dependencies added: base, colonnade, containers, text, vector, web-view, web-view-colonnade
Files
- LICENSE +20/−0
- README.md +142/−0
- src/WebView/Colonnade.hs +372/−0
- test/Main.hs +8/−0
- test/WebView/ColonnadeSpec.hs +174/−0
- web-view-colonnade.cabal +116/−0
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2025 José Lorenzo Rodríguez++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,142 @@+# Web View Colonnade++Build HTML tables using [colonnade](https://hackage.haskell.org/package/colonnade) and rendering with the [web-view](https://hackage.haskell.org/package/web-view) library in Haskell.++This library provides functionality similar to `lucid-colonnade` and `blaze-colonnade`, but for the web-view library. It lets you build complex HTML tables with minimal boilerplate.++## Installation++Add the following to your `package.yaml` or `.cabal` file:++```yaml+dependencies:+ - colonnade+ - web-view+ - web-view-colonnade+```++## Examples++### Basic Example++```haskell+{-# LANGUAGE OverloadedStrings #-}++import qualified Data.Text as T+import qualified Colonnade as C+import qualified Web.View.View as V+import qualified Web.View.Element as E+import Web.View (renderText)+import WebView.Colonnade++-- Define a data type to represent our data+data Person = Person+ { name :: T.Text+ , age :: Int+ }++-- Define some data+people :: [Person]+people =+ [ Person "Alice" 30+ , Person "Bob" 25+ , Person "Carol" 35+ ]++-- Define the table structure+personTable :: C.Colonnade C.Headed Person (V.View c ())+personTable = mconcat+ [ C.headed "Name" (E.text . name)+ , C.headed "Age" (E.text . T.pack . show . age)+ ]++main :: IO ()+main = do+ -- Render a table with custom attributes+ let html = encodeHtmlTable (V.extClass "person-table") personTable people+ putStrLn $ renderText html+```++This produces:++```html+<table class='person-table'>+ <thead>+ <tr>+ <th>Name</th>+ <th>Age</th>+ </tr>+ </thead>+ <tbody>+ <tr>+ <td>Alice</td>+ <td>30</td>+ </tr>+ <tr>+ <td>Bob</td>+ <td>25</td>+ </tr>+ <tr>+ <td>Carol</td>+ <td>35</td>+ </tr>+ </tbody>+</table>+```++### Cell Attributes++The `Cell` type allows you to add attributes to individual table cells:++```haskell+personCellTable :: C.Colonnade C.Headed Person (Cell c)+personCellTable = mconcat+ [ C.headed "Name" (\p -> Cell (V.extClass "name-cell") (E.text $ name p))+ , C.headed "Age" (\p -> Cell (V.extClass "age-cell") (E.text . T.pack . show $ age p))+ ]++main :: IO ()+main = do+ let html = encodeCellTable (V.extClass "person-table") personCellTable people+ putStrLn $ renderText html+```++This will render each cell with the appropriate class attributes.++## Contributing++We welcome contributions to web-view-colonnade! This project uses a nix-based devenv shell for development.++### Setting Up the Development Environment++1. Make sure you have [Nix](https://nixos.org/download.html) installed+2. Install [devenv](https://devenv.sh/getting-started/)+3. Clone this repository:+ ```+ git clone https://github.com/lorenzo/web-view-colonnade.git+ cd web-view-colonnade+ ```+4. Start the development shell:+ ```+ devenv shell+ ```+5. Build the project:+ ```+ cabal build+ ```+6. Run the tests:+ ```+ cabal test+ ```++### Pull Requests++1. Fork the repository+2. Create a new branch for your feature+3. Add tests for your new feature+4. Ensure all tests pass+5. Submit a pull request++## License++This project is licensed under the MIT license - see the LICENSE file for details.
+ src/WebView/Colonnade.hs view
@@ -0,0 +1,372 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeApplications #-}+++module WebView.Colonnade+ ( -- * What is this?+ -- $whatis+ -- * How to use this library+ -- $use++ -- * Encoding functions+ encodeHtmlTable+ , encodeCellTable+ , encodeTable+ -- * Cell+ , Cell(..)+ , charCell+ , stringCell+ , textCell+ , htmlCell+ , htmlFromCell+ ) where++import Colonnade (Colonnade)+import qualified Web.View.View as V+import qualified Web.View.Element as E+import qualified Colonnade.Encode as E+import qualified Data.Text as T+import Data.String (IsString(..))+import Data.Foldable (for_)+import Web.View.Types (Mod)++{- $whatis+ Build HTML tables using @web-view@ and @colonnade@. This module provides+ functionality similar to @lucid-colonnade@ and @blaze-colonnade@ but for the+ web-view library.+-}++{- $use++ = Usage++ We start with a few necessary imports and some example data types:++ >>> :set -XOverloadedStrings+ >>> import Data.Monoid (mconcat,(<>))+ >>> import Data.Char (toLower)+ >> import qualified Data.Text as T+ >>> import Data.Profunctor (Profunctor(lmap))+ >>> import Colonnade (Colonnade,Headed,Headless,headed)+ >>> import Web.View+ >>> import qualified Web.View.Style as V + >>> import qualified Web.View.Types as V+ >>> data Department = Management | Sales | Engineering deriving (Show,Eq)+ >>> data Employee = Employee { name :: T.Text, department :: Department, age :: Int }++ We define some employees that we will display in a table:++ >>> :{+ let employees =+ [ Employee "Thaddeus" Sales 34+ , Employee "Lucia" Engineering 33+ , Employee "Pranav" Management 57+ ]+ :}++ Let's build a table that displays the name and the age+ of an employee. Additionally, we will emphasize the names of+ engineers using a @\<strong\>@ tag.++ >>> :{+ let tableEmpA :: Colonnade Headed Employee (View c ())+ tableEmpA = mconcat+ [ headed "Name" $ \emp -> case department emp of+ Engineering -> el bold (text (name emp))+ _ -> text (name emp)+ , headed "Age" (text . T.pack . show . age)+ ]+ :}++ The type signature of @tableEmpA@ is inferrable but is written+ out for clarity in this example. Note that the first+ argument to 'headed' can be passed as a string literal due to the @OverloadedStrings@ extension.+ Let's continue:++ >>> let customAttrs = V.extClass "stylish-table" <> V.att "id" "main-table"+ >>> renderText (encodeHtmlTable customAttrs tableEmpA employees)+ <table class='stylish-table' id='main-table'>+ <thead>+ <tr>+ <th>Name</th>+ <th>Age</th>+ </tr>+ </thead>+ <tbody>+ <tr>+ <td>Thaddeus</td>+ <td>34</td>+ </tr>+ <tr>+ <td><div class="bold">Lucia</div></td>+ <td>33</td>+ </tr>+ <tr>+ <td>Pranav</td>+ <td>57</td>+ </tr>+ </tbody>+ </table>++ Excellent. As expected, Lucia's name is wrapped in a @\<strong\>@ tag+ since she is an engineer.++ One limitation of using @View@ as the content+ type of a 'Colonnade' is that we are unable to add attributes to+ the @\<td\>@ and @\<th\>@ elements. This library provides the 'Cell' type+ to work around this problem. A 'Cell' is just a @V.View@ content and a set+ of attributes to be applied to its parent @\<th\>@ or @\<td\>@. To illustrate+ its use, another employee table will be built. This table will+ contain a single column indicating the department of each employee. Each+ cell will be assigned a class name based on the department. Let's build a table + that encodes departments:++ >>> :{+ let tableDept :: Colonnade Headed Department (Cell c)+ tableDept = mconcat+ [ headed "Dept." $ \d -> Cell+ (V.extClass (V.ClassName $ T.pack (map Data.Char.toLower (show d))))+ (E.text (T.pack (show d)))+ ]+ :}++ Again, @OverloadedStrings@ plays a role, this time allowing the+ literal @"Dept."@ to be accepted as a value of type 'Cell'. To avoid+ this extension, 'stringCell' could be used to upcast the 'String'.+ To try out our 'Colonnade' on a list of departments, we need to use+ 'encodeCellTable' instead of 'encodeHtmlTable':++ >>> let twoDepts = [Sales,Management]+ >>> renderText (encodeCellTable customAttrs tableDept twoDepts)+ <table class='stylish-table' id='main-table'>+ <thead>+ <tr>+ <th>Dept.</th>+ </tr>+ </thead>+ <tbody>+ <tr>+ <td class='sales'>Sales</td>+ </tr>+ <tr>+ <td class='management'>Management</td>+ </tr>+ </tbody>+ </table>++ The attributes on the @\<td\>@ elements show up as they are expected to.+ Now, we take advantage of the @Profunctor@ instance of 'Colonnade' to allow+ this to work on @Employee@\'s instead:++ >>> :t lmap+ lmap :: Profunctor p => (a -> b) -> p b c -> p a c+ >>> let tableEmpB = lmap department tableDept+ >>> :t tableEmpB+ tableEmpB :: Colonnade Headed Employee (Cell c)+ >>> renderText (encodeCellTable customAttrs tableEmpB employees)+ <table class='stylish-table' id='main-table'>+ <thead>+ <tr>+ <th>Dept.</th>+ </tr>+ </thead>+ <tbody>+ <tr>+ <td class='sales'>Sales</td>+ </tr>+ <tr>+ <td class='engineering'>Engineering</td>+ </tr>+ <tr>+ <td class='management'>Management</td>+ </tr>+ </tbody>+ </table>++ This table shows the department of each of our three employees, additionally+ making a lowercased version of the department into a class name for the @\<td\>@.+ This table is nice for illustrative purposes, but it does not provide all the+ information that we have about the employees. If we combine it with the+ earlier table we wrote, we can present everything in the table. One small+ roadblock is that the types of @tableEmpA@ and @tableEmpB@ do not match, which+ prevents a straightforward monoidal append:++ >>> :t tableEmpA+ tableEmpA :: Colonnade Headed Employee (V.View c ())+ >>> :t tableEmpB+ tableEmpB :: Colonnade Headed Employee (Cell c)++ We can upcast the content type with 'fmap':++ >>> let tableEmpC = fmap htmlCell tableEmpA <> tableEmpB+ >>> :t tableEmpC+ tableEmpC :: Colonnade Headed Employee (Cell c)+ >>> renderText (encodeCellTable customAttrs tableEmpC employees)+ <table class='stylish-table' id='main-table'>+ <thead>+ <tr>+ <th>Name</th>+ <th>Age</th>+ <th>Dept.</th>+ </tr>+ </thead>+ <tbody>+ <tr>+ <td>Thaddeus</td>+ <td>34</td>+ <td class='sales'>Sales</td>+ </tr>+ <tr>+ <td><strong>Lucia</strong></td>+ <td>33</td>+ <td class='engineering'>Engineering</td>+ </tr>+ <tr>+ <td>Pranav</td>+ <td>57</td>+ <td class='management'>Management</td>+ </tr>+ </tbody>+ </table>+-}++-- | A table cell with attributes and content+data Cell c = Cell+ { cellAttributes :: Mod c -- ^ Attributes for the td/th element+ , cellHtml :: V.View c () -- ^ Content inside the cell+ }++instance IsString (Cell c) where+ fromString = stringCell++instance Semigroup (Cell c) where+ Cell attrs1 content1 <> Cell attrs2 content2 = + Cell (attrs1 <> attrs2) (content1 >> content2)++instance Monoid (Cell c) where+ mempty = Cell mempty (pure ())+ mappend = (<>)++-- | Create a cell from HTML content+htmlCell :: V.View c () -> Cell c+htmlCell content = Cell mempty content++-- | Create a cell from a string+stringCell :: String -> Cell c+stringCell = htmlCell . E.text . T.pack++-- | Create a cell from a character+charCell :: Char -> Cell c+charCell = stringCell . pure++-- | Create a cell from text+textCell :: T.Text -> Cell c+textCell = htmlCell . E.text++-- | Convert a cell to an HTML element+htmlFromCell :: (Mod c -> V.View c () -> V.View c ()) -> (Cell c) -> V.View c ()+htmlFromCell f (Cell attrs content) = f attrs content++-- | Encode a table with HTML content+encodeHtmlTable ::+ forall h f x c.+ (E.Headedness h, Foldable f) =>+ -- | Attributes of @\<table\>@ element+ Mod c ->+ -- | How to encode data as columns+ Colonnade h x (V.View c ()) ->+ -- | Collection of data+ f x ->+ V.View c ()+encodeHtmlTable =+ encodeTable+ (E.headednessPure (mempty, mempty))+ mempty+ (const mempty)+ (\tagFn content -> tagFn mempty content)++-- | Encode a table with cells that may have attributes+encodeCellTable ::+ forall h f x c.+ (E.Headedness h, Foldable f) =>+ -- | Attributes of @\<table\>@ element+ Mod c ->+ -- | How to encode data as columns+ Colonnade h x (Cell c) ->+ -- | Collection of data+ f x ->+ V.View c ()+encodeCellTable =+ encodeTable+ (E.headednessPure (mempty, mempty))+ mempty+ (const mempty)+ htmlFromCell++{- | Encode a table. This handles a very general case and+ is seldom needed by users. One of the arguments provided is+ used to add attributes to the generated @\<tr\>@ elements.+-}+encodeTable ::+ forall h f x v c.+ (E.Headedness h, Foldable f) =>+ -- | Attributes and structure for header section+ h (Mod c, Mod c) ->+ -- | Attributes for tbody element+ Mod c ->+ -- | Attributes for each tr element+ (x -> Mod c) ->+ -- | Cell wrapper function+ ((Mod c -> V.View c () -> V.View c ()) -> v -> V.View c ()) ->+ -- | Table attributes+ Mod c ->+ -- | How to encode data as columns+ Colonnade h x v ->+ -- | Collection of data+ f x ->+ V.View c ()+encodeTable mtheadAttrs tbodyAttrs trAttrs wrapContent tableAttrs colonnade xs =+ V.tag "table" tableAttrs $ do+ d1 <- case E.headednessExtractForall of+ Nothing -> pure mempty+ Just extractForall -> do+ let (theadAttrs, theadTrAttrs) = extract mtheadAttrs+ V.tag "thead" theadAttrs $+ V.tag "tr" theadTrAttrs $ do+ foldlMapM' (wrapContent (V.tag "th") . extract . E.oneColonnadeHead) (E.getColonnade colonnade)+ where+ extract :: forall y. h y -> y+ extract = E.runExtractForall extractForall+ d2 <- encodeBody trAttrs wrapContent tbodyAttrs colonnade xs+ pure (d1 <> d2)++foldlMapM' :: forall g b a m. (Foldable g, Monoid b, Monad m) => (a -> m b) -> g a -> m b+foldlMapM' f xs = foldr f' pure xs mempty+ where+ f' :: a -> (b -> m b) -> b -> m b+ f' x k bl = do+ br <- f x+ let !b = mappend bl br+ k b++encodeBody ::+ (Foldable f) =>+ -- | Attributes of each @\<tr\>@ element+ (a -> Mod c) ->+ -- | Wrap content and convert to 'Html'+ ((Mod c -> V.View c () -> V.View c ()) -> v -> V.View c ()) ->+ -- | Attributes of @\<tbody\>@ element+ Mod c ->+ -- | How to encode data as a row+ Colonnade h a v ->+ -- | Collection of data+ f a ->+ V.View c ()+encodeBody trAttrs wrapContent tbodyAttrs colonnade xs = do+ V.tag "tbody" tbodyAttrs $ do+ for_ xs $ \x -> do+ V.tag "tr" (trAttrs x) $ do+ E.rowMonadic colonnade (wrapContent (V.tag "td")) x
+ test/Main.hs view
@@ -0,0 +1,8 @@+module Main (main) where++import Test.Hspec+import qualified WebView.ColonnadeSpec++main :: IO ()+main = hspec $ do+ describe "WebView.Colonnade" WebView.ColonnadeSpec.spec
+ test/WebView/ColonnadeSpec.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+module WebView.ColonnadeSpec (spec) where++import Test.Hspec+import WebView.Colonnade+import qualified Web.View.View as V+import qualified Web.View.Style as V+import qualified Web.View.Element as E+import Web.View (renderText)+import qualified Colonnade as C+import qualified Colonnade.Encode as E+import qualified Data.Text as T+import Data.String (IsString(fromString))+import Data.String.Interpolate (i)++data Person = Person+ { name :: T.Text+ , age :: Int+ } deriving (Show, Eq)++spec :: Spec+spec = do+ describe "Cell" $ do+ it "implements IsString" $ do+ let s = "test"+ cell = fromString s :: Cell c+ let result = renderText (htmlFromCell (\_ -> V.tag "td" mempty) cell)+ result `shouldBe` [i|<td>#{s}</td>|]++ it "implements Semigroup" $ do+ let s1 = "test1"+ s2 = "test2"+ cell1 = fromString s1 :: Cell c+ cell2 = fromString s2 :: Cell c+ combined = cell1 <> cell2+ let result = renderText (htmlFromCell (\_ -> V.tag "td" mempty) combined)+ result `shouldBe` [i|<td>+ #{s1}#{s2}</td>|]++ it "implements Monoid" $ do+ let s = "test"+ cell = fromString s :: Cell c+ let result1 = renderText (htmlFromCell (\_ -> V.tag "td" mempty) (cell <> mempty))+ result2 = renderText (htmlFromCell (\_ -> V.tag "td" mempty) cell)+ result1 `shouldBe` result2++ describe "encodeHtmlTable" $ do+ let personColonnade = mconcat+ [ C.headed "Name" (E.text . name)+ , C.headed "Age" (E.text . T.pack . show . age)+ ]+ people = [Person "Alice" 30, Person "Bob" 25]++ it "generates correct HTML structure" $ do+ let html = encodeHtmlTable (V.extClass "table") personColonnade people+ let result = renderText html+ result `shouldBe` [i|<table class='table'>+ <thead>+ <tr>+ <th>Name</th>+ <th>Age</th>+ </tr>+ </thead>+ <tbody>+ <tr>+ <td>Alice</td>+ <td>30</td>+ </tr>+ <tr>+ <td>Bob</td>+ <td>25</td>+ </tr>+ </tbody>+</table>|]++ it "preserves table attributes" $ do+ let attr = "class"+ val = "test-table"+ html = encodeHtmlTable (V.att attr val) personColonnade []+ rendered = renderText html+ rendered `shouldBe` [i|<table class='#{val}'>+ <thead>+ <tr>+ <th>Name</th>+ <th>Age</th>+ </tr>+ </thead>+ <tbody></tbody>+</table>|]++ describe "encodeCellTable" $ do+ let personColonnade = mconcat+ [ C.headed "Name" (\p -> Cell (V.extClass "name") (E.text $ name p))+ , C.headed "Age" (\p -> Cell (V.extClass "age") (E.text . T.pack . show $ age p))+ ]+ people = [Person "Alice" 30, Person "Bob" 25]++ it "preserves cell attributes" $ do+ let html = encodeCellTable mempty personColonnade people+ rendered = renderText html+ rendered `shouldBe` [i|<table>+ <thead>+ <tr>+ <th>Name</th>+ <th>Age</th>+ </tr>+ </thead>+ <tbody>+ <tr>+ <td class='name'>Alice</td>+ <td class='age'>30</td>+ </tr>+ <tr>+ <td class='name'>Bob</td>+ <td class='age'>25</td>+ </tr>+ </tbody>+</table>|]++ describe "Cell constructors" $ do+ it "charCell creates valid HTML" $ do+ let c = 'a'+ cell = charCell c+ let result = renderText (htmlFromCell (\_ -> V.tag "td" mempty) cell)+ result `shouldBe` [i|<td>#{c}</td>|]++ it "stringCell creates valid HTML" $ do+ let s = "test"+ cell = stringCell s+ let result = renderText (htmlFromCell (\_ -> V.tag "td" mempty) cell)+ result `shouldBe` [i|<td>#{s}</td>|]++ it "textCell creates valid HTML" $ do+ let t = "test" :: T.Text+ cell = textCell t+ let result = renderText (htmlFromCell (\_ -> V.tag "td" mempty) cell)+ result `shouldBe` [i|<td>#{t}</td>|]++ describe "encodeTable" $ do+ let personColonnade = mconcat+ [ C.headed "Name" (E.text . name)+ , C.headed "Age" (E.text . T.pack . show . age)+ ]+ people = [Person "Alice" 30, Person "Bob" 25]++ it "applies all attribute functions" $ do+ let html = encodeTable+ (E.headednessPure (V.extClass "head", V.extClass "head-row"))+ (V.extClass "body")+ (\_ -> V.extClass "row")+ (\tagFn content -> tagFn (V.extClass "i") content)+ (V.extClass "table")+ personColonnade+ people+ rendered = renderText html+ rendered `shouldBe` [i|<table class='table'>+ <thead class='head'>+ <tr class='head-row'>+ <th class='i'>Name</th>+ <th class='i'>Age</th>+ </tr>+ </thead>+ <tbody class='body'>+ <tr class='row'>+ <td class='i'>Alice</td>+ <td class='i'>30</td>+ </tr>+ <tr class='row'>+ <td class='i'>Bob</td>+ <td class='i'>25</td>+ </tr>+ </tbody>+</table>|]
+ web-view-colonnade.cabal view
@@ -0,0 +1,116 @@+cabal-version: 3.4++-- The cabal-version field refers to the version of the .cabal specification,+-- and can be different from the cabal-install (the tool) version and the+-- Cabal (the library) version you are using. As such, the Cabal (the library)+-- version used must be equal or greater than the version stated in this field.+-- Starting from the specification version 2.2, the cabal-version field must be+-- the first thing in the cabal file.++-- Initial package description 'web-view-colonnade' generated by+-- 'cabal init'. For further documentation, see:+-- http://haskell.org/cabal/users-guide/+--+-- The name of the package.+name: web-view-colonnade++-- The package version.+-- See the Haskell package versioning policy (PVP) for standards+-- guiding when and how versions should be incremented.+-- https://pvp.haskell.org+-- PVP summary: +-+------- breaking API changes+-- | | +----- non-breaking API additions+-- | | | +--- code changes with no API change+version: 0.1.0.0++-- A short (one-line) description of the package.+synopsis: Build HTML tables using web-view and colonnade.+homepage: https://github.com/lorenzo/web-view-colonnade++-- A longer description of the package.+description:+ Build HTML tables using web-view and colonnade. This module provides+ functionality similar to @lucid-colonnade@ and @blaze-colonnade@ but for the+ web-view library.++-- The license under which the package is released.+license: MIT++-- The file containing the license text.+license-file: LICENSE++-- The package author(s).+author: José Lorenzo Rodríguez++-- An email address to which users can send suggestions, bug reports, and patches.+maintainer: lorenzo@users.noreply.github.com++-- A copyright notice.+category: Web+build-type: Simple++-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.+extra-doc-files: README.md++-- Extra source files to be distributed with the package, such as examples, or a tutorial module.+-- extra-source-files:++common warnings+ ghc-options: -Wall++common deps+ build-depends:+ , base >=4.18.2.1 && <5+ , colonnade >=1.2.0 && <1.3+ , containers >=0.6.7 && <0.9+ , text >=2.0.2 && <2.2+ , vector >=0.13.2 && <0.14+ , web-view >=0.6.0 && <0.8++library+ -- Import common warning flags.+ import: warnings, deps++ -- Modules exported by the library.+ exposed-modules: WebView.Colonnade++ -- Modules included in this library but not exported.+ -- other-modules:++ -- LANGUAGE extensions used by modules in this package.+ -- other-extensions: ++ -- Directories containing source files.+ hs-source-dirs: src++ -- Base language which the package is written in.+ default-language: GHC2021++test-suite web-view-colonnade-test+ -- Import common warning flags.+ import: warnings, deps++ -- Base language which the package is written in.+ default-language: GHC2021++ -- Modules included in this executable, other than Main.+ other-modules: WebView.ColonnadeSpec++ -- LANGUAGE extensions used by modules in this package.+ other-extensions: OverloadedStrings++ -- The interface type and version of the test suite.+ type: exitcode-stdio-1.0++ -- Directories containing source files.+ hs-source-dirs: test++ -- The entrypoint to the test suite.+ main-is: Main.hs++ -- Test dependencies.+ build-depends: web-view-colonnade++source-repository head+ type: git+ location: https://github.com/lorenzo/web-view-colonnade