From 6a8b29d9519248ae98232c47e3a8cb1c73c08a07 Mon Sep 17 00:00:00 2001 From: Andrew Meier Date: Fri, 6 Feb 2026 07:26:42 -0500 Subject: [PATCH 1/5] Restructure repo, add Datastar docs, update configs Split fsharp-view-engine/ into lib/ (core library, tests, benchmarks, build) and docs/ (documentation Giraffe app, build). Add Datastar extension page to docs site with handler, route, and nav link. Add logo to README and docs site header. Fix inline code backtick styling. Update CI workflows, Pulumi docker context, and Dockerfile for new directory layout. --- .github/workflows/pull_request.yml | 6 +- .github/workflows/release.yml | 8 +- .gitignore | 2 + fsharp-view-engine/AGENTS.md => AGENTS.md | 0 CLAUDE.md | 70 +- README.md | 110 +- .../.config/dotnet-tools.json | 0 {fsharp-view-engine => docs}/.dockerignore | 0 docs/.gitignore | 5 + {fsharp-view-engine => docs}/Dockerfile | 6 +- {fsharp-view-engine => docs}/fake.cmd | 0 {fsharp-view-engine => docs}/fake.sh | 0 .../paket.dependencies | 3 +- {fsharp-view-engine => docs}/paket.lock | 13 +- .../src/Build/Build.fsproj | 0 docs/src/Build/Program.fs | 65 + .../src/Build/paket.references | 0 .../src/App => docs/src/Docs}/Config.fs | 2 +- .../App.fsproj => docs/src/Docs/Docs.fsproj | 11 +- docs/src/Docs/Handlers.fs | 66 + .../src/App => docs/src/Docs}/Program.fs | 9 +- docs/src/Docs/Views.fs | 291 +++ docs/src/Docs/docs/alpine.md | 185 ++ docs/src/Docs/docs/datastar.md | 313 +++ docs/src/Docs/docs/home.md | 56 + docs/src/Docs/docs/htmx.md | 206 ++ .../src/Docs}/docs/installation.md | 0 docs/src/Docs/docs/quickstart.md | 88 + docs/src/Docs/docs/svg.md | 155 ++ docs/src/Docs/docs/tailwind.md | 201 ++ .../src/App => docs/src/Docs}/input.css | 5 + .../App => docs/src/Docs}/paket.references | 0 .../Docs/wwwroot/android-chrome-192x192.png | Bin 0 -> 16687 bytes .../Docs/wwwroot/android-chrome-512x512.png | Bin 0 -> 44925 bytes docs/src/Docs/wwwroot/apple-touch-icon.png | Bin 0 -> 15097 bytes docs/src/Docs/wwwroot/css/output.css | 1760 +++++++++++++++++ docs/src/Docs/wwwroot/favicon-16x16.png | Bin 0 -> 765 bytes docs/src/Docs/wwwroot/favicon-32x32.png | Bin 0 -> 1798 bytes docs/src/Docs/wwwroot/favicon.ico | Bin 0 -> 15406 bytes docs/src/Docs/wwwroot/logo.png | Bin 0 -> 73569 bytes .../wwwroot/scripts/alpinejs.3.15.0.min.js | 0 docs/src/Docs/wwwroot/site.webmanifest | 1 + etc/logo.png | Bin 0 -> 73569 bytes etc/logo.svg | 73 + fsharp-view-engine/FSharp.ViewEngine.sln | 48 - fsharp-view-engine/src/App/Handlers.fs | 39 - fsharp-view-engine/src/App/Views.fs | 324 --- fsharp-view-engine/src/App/docs/home.md | 62 - fsharp-view-engine/src/App/docs/quickstart.md | 98 - .../src/FSharp.ViewEngine/Alpine.fs | 38 - .../src/FSharp.ViewEngine/Core.fs | 62 - .../src/FSharp.ViewEngine/Html.fs | 122 -- .../src/FSharp.ViewEngine/Htmx.fs | 17 - .../src/FSharp.ViewEngine/Svg.fs | 22 - .../src/FSharp.ViewEngine/Tailwind.fs | 24 - fsharp-view-engine/src/Tests/Tests.fs | 165 -- lib/.config/dotnet-tools.json | 13 + {fsharp-view-engine => lib}/.gitignore | 0 {fsharp-view-engine => lib}/LICENSE | 0 lib/fake.cmd | 1 + lib/fake.sh | 1 + {fsharp-view-engine => lib}/global.json | 0 lib/paket.dependencies | 13 + lib/paket.lock | 209 ++ lib/src/Benchmarks/Benchmarks.fs | 472 +++++ lib/src/Benchmarks/Benchmarks.fsproj | 18 + lib/src/Benchmarks/Profile.fs | 110 ++ lib/src/Benchmarks/paket.references | 5 + lib/src/Build/Build.fsproj | 13 + .../src/Build/Program.fs | 29 +- lib/src/Build/paket.references | 1 + lib/src/FSharp.ViewEngine/Alpine.fs | 41 + lib/src/FSharp.ViewEngine/Core.fs | 322 +++ lib/src/FSharp.ViewEngine/Datastar.fs | 45 + .../FSharp.ViewEngine.fsproj | 5 +- lib/src/FSharp.ViewEngine/Html.fs | 226 +++ lib/src/FSharp.ViewEngine/Htmx.fs | 17 + lib/src/FSharp.ViewEngine/README.md | 77 + lib/src/FSharp.ViewEngine/Svg.fs | 21 + lib/src/FSharp.ViewEngine/Tailwind.fs | 25 + .../src/FSharp.ViewEngine/paket.references | 0 .../src/Tests/Program.fs | 0 lib/src/Tests/Tests.fs | 173 ++ .../src/Tests/Tests.fsproj | 2 +- .../src/Tests/paket.references | 0 pulumi/src/docker/image.ts | 2 +- 86 files changed, 5425 insertions(+), 1147 deletions(-) rename fsharp-view-engine/AGENTS.md => AGENTS.md (100%) rename {fsharp-view-engine => docs}/.config/dotnet-tools.json (100%) rename {fsharp-view-engine => docs}/.dockerignore (100%) create mode 100644 docs/.gitignore rename {fsharp-view-engine => docs}/Dockerfile (87%) rename {fsharp-view-engine => docs}/fake.cmd (100%) rename {fsharp-view-engine => docs}/fake.sh (100%) mode change 100755 => 100644 rename {fsharp-view-engine => docs}/paket.dependencies (72%) rename {fsharp-view-engine => docs}/paket.lock (76%) rename {fsharp-view-engine => docs}/src/Build/Build.fsproj (100%) create mode 100644 docs/src/Build/Program.fs rename {fsharp-view-engine => docs}/src/Build/paket.references (100%) rename {fsharp-view-engine/src/App => docs/src/Docs}/Config.fs (94%) rename fsharp-view-engine/src/App/App.fsproj => docs/src/Docs/Docs.fsproj (75%) create mode 100644 docs/src/Docs/Handlers.fs rename {fsharp-view-engine/src/App => docs/src/Docs}/Program.fs (72%) create mode 100644 docs/src/Docs/Views.fs create mode 100644 docs/src/Docs/docs/alpine.md create mode 100644 docs/src/Docs/docs/datastar.md create mode 100644 docs/src/Docs/docs/home.md create mode 100644 docs/src/Docs/docs/htmx.md rename {fsharp-view-engine/src/App => docs/src/Docs}/docs/installation.md (100%) create mode 100644 docs/src/Docs/docs/quickstart.md create mode 100644 docs/src/Docs/docs/svg.md create mode 100644 docs/src/Docs/docs/tailwind.md rename {fsharp-view-engine/src/App => docs/src/Docs}/input.css (95%) rename {fsharp-view-engine/src/App => docs/src/Docs}/paket.references (100%) create mode 100644 docs/src/Docs/wwwroot/android-chrome-192x192.png create mode 100644 docs/src/Docs/wwwroot/android-chrome-512x512.png create mode 100644 docs/src/Docs/wwwroot/apple-touch-icon.png create mode 100644 docs/src/Docs/wwwroot/css/output.css create mode 100644 docs/src/Docs/wwwroot/favicon-16x16.png create mode 100644 docs/src/Docs/wwwroot/favicon-32x32.png create mode 100644 docs/src/Docs/wwwroot/favicon.ico create mode 100644 docs/src/Docs/wwwroot/logo.png rename {fsharp-view-engine/src/App => docs/src/Docs}/wwwroot/scripts/alpinejs.3.15.0.min.js (100%) create mode 100644 docs/src/Docs/wwwroot/site.webmanifest create mode 100644 etc/logo.png create mode 100644 etc/logo.svg delete mode 100644 fsharp-view-engine/FSharp.ViewEngine.sln delete mode 100644 fsharp-view-engine/src/App/Handlers.fs delete mode 100644 fsharp-view-engine/src/App/Views.fs delete mode 100644 fsharp-view-engine/src/App/docs/home.md delete mode 100644 fsharp-view-engine/src/App/docs/quickstart.md delete mode 100644 fsharp-view-engine/src/FSharp.ViewEngine/Alpine.fs delete mode 100644 fsharp-view-engine/src/FSharp.ViewEngine/Core.fs delete mode 100644 fsharp-view-engine/src/FSharp.ViewEngine/Html.fs delete mode 100644 fsharp-view-engine/src/FSharp.ViewEngine/Htmx.fs delete mode 100644 fsharp-view-engine/src/FSharp.ViewEngine/Svg.fs delete mode 100644 fsharp-view-engine/src/FSharp.ViewEngine/Tailwind.fs delete mode 100644 fsharp-view-engine/src/Tests/Tests.fs create mode 100644 lib/.config/dotnet-tools.json rename {fsharp-view-engine => lib}/.gitignore (100%) rename {fsharp-view-engine => lib}/LICENSE (100%) create mode 100644 lib/fake.cmd create mode 100644 lib/fake.sh rename {fsharp-view-engine => lib}/global.json (100%) create mode 100644 lib/paket.dependencies create mode 100644 lib/paket.lock create mode 100644 lib/src/Benchmarks/Benchmarks.fs create mode 100644 lib/src/Benchmarks/Benchmarks.fsproj create mode 100644 lib/src/Benchmarks/Profile.fs create mode 100644 lib/src/Benchmarks/paket.references create mode 100644 lib/src/Build/Build.fsproj rename {fsharp-view-engine => lib}/src/Build/Program.fs (69%) create mode 100644 lib/src/Build/paket.references create mode 100644 lib/src/FSharp.ViewEngine/Alpine.fs create mode 100644 lib/src/FSharp.ViewEngine/Core.fs create mode 100644 lib/src/FSharp.ViewEngine/Datastar.fs rename {fsharp-view-engine => lib}/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj (91%) create mode 100644 lib/src/FSharp.ViewEngine/Html.fs create mode 100644 lib/src/FSharp.ViewEngine/Htmx.fs create mode 100644 lib/src/FSharp.ViewEngine/README.md create mode 100644 lib/src/FSharp.ViewEngine/Svg.fs create mode 100644 lib/src/FSharp.ViewEngine/Tailwind.fs rename {fsharp-view-engine => lib}/src/FSharp.ViewEngine/paket.references (100%) rename {fsharp-view-engine => lib}/src/Tests/Program.fs (100%) create mode 100644 lib/src/Tests/Tests.fs rename {fsharp-view-engine => lib}/src/Tests/Tests.fsproj (98%) rename {fsharp-view-engine => lib}/src/Tests/paket.references (100%) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index fe4dd39..fc650f9 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -15,13 +15,13 @@ jobs: dotnet-version: 10.0.x - name: Install Tools run: dotnet tool restore - working-directory: ./fsharp-view-engine + working-directory: ./lib - name: Install Packages run: dotnet paket install - working-directory: ./fsharp-view-engine + working-directory: ./lib - name: Test run: ./fake.sh Test - working-directory: ./fsharp-view-engine + working-directory: ./lib preview: name: Preview runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8a5a16e..094652d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,13 +17,13 @@ jobs: dotnet-version: 10.0.x - name: Restore Tools run: dotnet tool restore - working-directory: ./fsharp-view-engine + working-directory: ./lib - name: Install Packages run: dotnet paket install - working-directory: ./fsharp-view-engine + working-directory: ./lib - name: Publish - run: ./fake.sh Publish - working-directory: ./fsharp-view-engine + run: ./fake.sh PushNugets + working-directory: ./lib env: NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} deploy: diff --git a/.gitignore b/.gitignore index 5eec986..4e52848 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +.idea +.vscode .claude diff --git a/fsharp-view-engine/AGENTS.md b/AGENTS.md similarity index 100% rename from fsharp-view-engine/AGENTS.md rename to AGENTS.md diff --git a/CLAUDE.md b/CLAUDE.md index 3dd6247..c89bd6c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,21 +3,24 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview -FSharp.ViewEngine is a view engine for F# web applications. It provides a functional approach to generating HTML with type-safe F# code, including integrated support for HTMX, Alpine.js, Tailwind CSS, and SVG elements. +FSharp.ViewEngine is a view engine for F# web applications. It provides a functional approach to generating HTML with type-safe F# code, including integrated support for HTMX, Alpine.js, Datastar, Tailwind CSS, and SVG elements. ## Repository Structure -- `fsharp-view-engine/` — F# library, app, tests, and build system -- `pulumi/` — Pulumi infrastructure (TypeScript) for deploying the demo app -- `.github/` — CI workflows (at repo root, with `working-directory: fsharp-view-engine`) +- `lib/` — Core F# library, tests, benchmarks, and build system +- `docs/` — Documentation Giraffe web app with Markdown pages and build system +- `etc/` — Assets (logos) +- `pulumi/` — Pulumi infrastructure (TypeScript) for deploying the docs app +- `.github/` — CI workflows - `.claude/` — Claude Code settings ## Common Development Commands **Important:** When running in a bash shell (including Claude Code), always use `./fake.sh` instead of `fake.cmd`. +### Library (`lib/`) + ```bash -# All dotnet/fake commands run from fsharp-view-engine/ -cd fsharp-view-engine +cd lib # Restore tools and packages dotnet tool restore @@ -30,13 +33,28 @@ dotnet run --project src/Tests/Tests.fsproj # Direct # Run a single test by name dotnet run --project src/Tests/Tests.fsproj -- --filter "Should render html document" -# Run demo app with Tailwind watch -./fake.sh Watch - # Create NuGet package (needs GITHUB_REF_NAME env var) ./fake.sh Pack +``` + +### Docs app (`docs/`) + +```bash +cd docs -# Pulumi deployment +# Run docs app with Tailwind watch (hot reload) +./fake.sh Watch + +# Build CSS for production +./fake.sh BuildCss + +# Publish docs app +./fake.sh Publish +``` + +### Pulumi deployment + +```bash cd pulumi npm install pulumi up -s prod @@ -44,17 +62,18 @@ pulumi up -s prod ## Architecture -### Core Type System (`fsharp-view-engine/src/FSharp.ViewEngine/Core.fs`) +### Core Type System (`lib/src/FSharp.ViewEngine/Core.fs`) Two discriminated unions form the foundation: - **Element**: `Text | Tag | Void | Fragment | Raw | Noop` — represents DOM nodes - **Attribute**: `KeyValue | Boolean | Children | Noop` — represents HTML attributes Rendering uses `StringBuilder` with recursive pattern matching. `Text` is HTML-encoded; `Raw` is not. `Void` elements (e.g., `br`, `img`) are self-closing and reject children. -### Module Organization +### Module Organization (`lib/src/FSharp.ViewEngine/`) - `Html.fs` — Standard HTML elements and attributes as static members on `Html` type - `Htmx.fs` — HTMX attributes (`_hxGet`, `_hxPost`, etc.) on `Htmx` type - `Alpine.fs` — Alpine.js directives (`_xData`, `_xShow`, etc.) on `Alpine` type +- `Datastar.fs` — Datastar attributes (`_dsSignals`, `_dsOn`, etc.) on `Datastar` type - `Tailwind.fs` — Tailwind UI custom elements on `Tailwind` type - `Svg.fs` — SVG elements and attributes on `Svg` type @@ -64,31 +83,38 @@ open FSharp.ViewEngine open type Html open type Htmx -div [ _class "container"; _hxGet "/api"; _children [ h1 "Hello" ] ] -|> Element.render +div { + _class "container" + _hxGet "/api" + h1 { "Hello" } +} +|> Render.toHtmlDocString ``` ### Project Structure -- `fsharp-view-engine/src/FSharp.ViewEngine/` — Core library (NuGet package) -- `fsharp-view-engine/src/Tests/` — xUnit tests -- `fsharp-view-engine/src/Build/` — FAKE build system (`Program.fs` defines targets) -- `fsharp-view-engine/src/App/` — Demo Giraffe web app with Markdown docs +- `lib/src/FSharp.ViewEngine/` — Core library (NuGet package) +- `lib/src/Tests/` — Expecto tests +- `lib/src/Benchmarks/` — BenchmarkDotNet benchmarks +- `lib/src/Build/` — FAKE build system (Test, Pack, PushNugets targets) +- `docs/src/Docs/` — Documentation Giraffe web app with Markdown pages +- `docs/src/Build/` — FAKE build system (Watch, BuildCss, Publish targets) - `pulumi/` — Infrastructure as code (Pulumi + TypeScript) ## Development Patterns - **New HTML elements** in `Html.fs`: use `Tag` for normal elements, `Void` for self-closing. Add convenience overloads (e.g., `p (text:string)`). -- **Framework attributes**: HTMX → `Htmx.fs` with `_hx` prefix; Alpine → `Alpine.fs` with `_x` prefix. +- **Framework attributes**: HTMX → `Htmx.fs` with `_hx` prefix; Alpine → `Alpine.fs` with `_x` prefix; Datastar → `Datastar.fs` with `_ds` prefix. +- **New doc pages**: Add markdown in `docs/src/Docs/docs/`, handler in `Handlers.fs`, route in `Program.fs`, nav link in `Views.fs`. - **Tests** compare rendered HTML strings using `String.clean` for whitespace normalization. Use `// language=HTML` comment for IDE syntax highlighting in expected strings. ## Build System -- FAKE build scripts invoked via `fake.cmd`/`fake.sh` -- Paket for package management (`paket.dependencies` at root of `fsharp-view-engine/`) +- FAKE build scripts invoked via `fake.cmd`/`fake.sh` (separate in `lib/` and `docs/`) +- Paket for package management (`paket.dependencies` in `lib/` and `docs/`) - .NET 10.0 SDK (`global.json`) - CI: GitHub Actions — tests on PRs, NuGet publish on release tags (`v*.*.*`) ## Infrastructure (Pulumi) - TypeScript Pulumi project in `pulumi/` -- Deploys demo app to Kubernetes via AWS ECR + Cloudflare Tunnel +- Deploys docs app to Kubernetes via AWS ECR - Domain: `fsharpviewengine.meiermade.com` - Stack references: `identity`, `infrastructure`, `fsharp-view-engine-identity` diff --git a/README.md b/README.md index 2214ce8..b200af7 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ [![Release](https://github.com/meiermade/FSharp.ViewEngine/actions/workflows/release.yml/badge.svg)](https://github.com/meiermade/FSharp.ViewEngine/actions/workflows/release.yml) +

+ FSharp.ViewEngine +

+ # FSharp.ViewEngine View engine for F#. Inspired by [Giraffe.ViewEngine](https://github.com/giraffe-fsharp/Giraffe.ViewEngine) and [Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine). Documentation site built using FSharp.ViewEngine available at [https://fsharpviewengine.meiermade.com](https://fsharpviewengine.meiermade.com). -> See [App](./src/App) for the source code. +> See [docs/src/Docs](./docs/src/Docs) for the source code. ## Installation Add the core view engine package. @@ -18,47 +22,38 @@ open FSharp.ViewEngine open type Html open type Htmx open type Alpine +open type Datastar open type Tailwind -html [ +html { _lang "en" - _children [ - head [ - title "Test" - meta [ _charset "utf-8" ] - link [ _href "/css/compiled.css"; _rel "stylesheet" ] - ] - body [ - _xData "{showContent: false}" - _class "bg-gray-50" - _children [ - div [ - _id "page" - _class [ "flex"; "flex-col" ] - _children [ - h1 [ _hxGet "/hello"; _hxTarget "#page"; _children "Hello" ] - h1 [ _hxGet "/world"; _hxTarget "#page"; _children "World" ] - ] - ] - br - div [ - _xShow "showContent" - _children [ - h2 [ _children "Content" ] - p [ _children "Some content" ] - ul [ - _children [ - li [ _children "One" ] - li [ _children "Two" ] - ] - ] - ] - ] - ] - ] - ] -] -|> Element.render + head { + title "Test" + meta { _charset "utf-8" } + link { _href "/css/compiled.css"; _rel "stylesheet" } + } + body { + _xData "{showContent: false}" + _class "bg-gray-50" + div { + _id "page" + _class [ "flex"; "flex-col" ] + h1 { _hxGet "/hello"; _hxTarget "#page"; "Hello" } + h1 { _hxGet "/world"; _hxTarget "#page"; "World" } + } + br + div { + _xShow "showContent" + h2 { "Content" } + p { "Some content" } + ul { + li { "One" } + li { "Two" } + } + } + } +} +|> Render.toHtmlDocString ``` ```html @@ -85,3 +80,40 @@ html [ ``` + +## Benchmarks +Ran on February 6, 2026 with BenchmarkDotNet MediumRun only. + +Environment: +- Windows 11 (10.0.26200.7623) +- 12th Gen Intel Core i9-12900HK +- .NET SDK 10.0.102, .NET Runtime 10.0.2 (X64 RyuJIT AVX2) + +Command: +``` +cd lib && dotnet run -c Release --project src/Benchmarks/Benchmarks.fsproj +``` + +BuildAndRender (mean, lower is better): +| Method | Mean | Allocated | +|-------------- |----------:|----------:| +| ViewEngineApi | 5.763 μs | 11.4 KB | +| OxpeckerApi | 7.562 μs | 12.88 KB | +| GiraffeApi | 7.925 μs | 23.95 KB | +| FelizApi | 11.053 μs | 25.87 KB | + +RenderOnly: +| Method | Mean | Allocated | +|-------------- |---------:|----------:| +| ViewEngineApi | 2.464 μs | 2.94 KB | +| OxpeckerApi | 2.796 μs | 2.94 KB | +| GiraffeApi | 3.176 μs | 12.77 KB | +| FelizApi | 6.151 μs | 14.2 KB | + +BuildOnly: +| Method | Mean | Allocated | +|-------------- |---------:|----------:| +| ViewEngineApi | 2.153 μs | 8.46 KB | +| OxpeckerApi | 5.275 μs | 9.95 KB | +| GiraffeApi | 7.323 μs | 11.17 KB | +| FelizApi | 7.707 μs | 11.66 KB | diff --git a/fsharp-view-engine/.config/dotnet-tools.json b/docs/.config/dotnet-tools.json similarity index 100% rename from fsharp-view-engine/.config/dotnet-tools.json rename to docs/.config/dotnet-tools.json diff --git a/fsharp-view-engine/.dockerignore b/docs/.dockerignore similarity index 100% rename from fsharp-view-engine/.dockerignore rename to docs/.dockerignore diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..7e44b7a --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,5 @@ +.paket +obj +bin +paket-files +*DotSettings.user diff --git a/fsharp-view-engine/Dockerfile b/docs/Dockerfile similarity index 87% rename from fsharp-view-engine/Dockerfile rename to docs/Dockerfile index 1f72440..744574c 100644 --- a/fsharp-view-engine/Dockerfile +++ b/docs/Dockerfile @@ -20,12 +20,12 @@ RUN dotnet paket install && dotnet paket restore COPY src src COPY fake.sh ./ RUN chmod +x fake.sh -RUN ./fake.sh PublishApp +RUN ./fake.sh Publish FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled WORKDIR /app -COPY --from=build /app/src/App/out . +COPY --from=build /app/src/Docs/out . -ENTRYPOINT ["dotnet", "App.dll"] +ENTRYPOINT ["dotnet", "Docs.dll"] diff --git a/fsharp-view-engine/fake.cmd b/docs/fake.cmd similarity index 100% rename from fsharp-view-engine/fake.cmd rename to docs/fake.cmd diff --git a/fsharp-view-engine/fake.sh b/docs/fake.sh old mode 100755 new mode 100644 similarity index 100% rename from fsharp-view-engine/fake.sh rename to docs/fake.sh diff --git a/fsharp-view-engine/paket.dependencies b/docs/paket.dependencies similarity index 72% rename from fsharp-view-engine/paket.dependencies rename to docs/paket.dependencies index 17c8c0d..4c28c1e 100644 --- a/fsharp-view-engine/paket.dependencies +++ b/docs/paket.dependencies @@ -2,7 +2,6 @@ source https://api.nuget.org/v3/index.json storage: none nuget Fake.Core.Target +nuget FSharp.Core nuget Giraffe -nuget JetBrains.Annotations nuget Markdig -nuget Expecto diff --git a/fsharp-view-engine/paket.lock b/docs/paket.lock similarity index 76% rename from fsharp-view-engine/paket.lock rename to docs/paket.lock index 6047145..f1dffa1 100644 --- a/fsharp-view-engine/paket.lock +++ b/docs/paket.lock @@ -1,9 +1,6 @@ STORAGE: NONE NUGET remote: https://api.nuget.org/v3/index.json - Expecto (10.2.3) - FSharp.Core (>= 7.0.200) - restriction: >= net6.0 - Mono.Cecil (>= 0.11.4 < 1.0) - restriction: >= net6.0 Fake.Core.CommandLineParsing (6.1.4) - restriction: >= netstandard2.0 FParsec (>= 1.1.1) - restriction: >= netstandard2.0 FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 @@ -48,7 +45,7 @@ NUGET FSharp.Control.Reactive (6.1.2) - restriction: >= netstandard2.0 FSharp.Core (>= 6.0.7) - restriction: >= netstandard2.0 System.Reactive (>= 6.0.1) - restriction: >= netstandard2.0 - FSharp.Core (10.0.102) - restriction: >= netstandard2.0 + FSharp.Core (10.0.102) FSharp.SystemTextJson (1.4.36) - restriction: >= net6.0 FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 System.Text.Json (>= 6.0.10) - restriction: >= netstandard2.0 @@ -60,15 +57,10 @@ NUGET System.Text.Json (>= 8.0.6) - restriction: >= net6.0 Giraffe.ViewEngine (1.4) - restriction: >= net6.0 FSharp.Core (>= 5.0) - restriction: >= netstandard2.0 - JetBrains.Annotations (2025.2.4) - System.Runtime (>= 4.1) - restriction: && (< net20) (>= netstandard1.0) (< netstandard2.0) Markdig (0.44) System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) Microsoft.Bcl.AsyncInterfaces (10.0.2) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net6.0) (< net8.0)) Microsoft.IO.RecyclableMemoryStream (3.0.1) - restriction: >= net6.0 - Microsoft.NETCore.Platforms (7.0.4) - restriction: || (&& (< monoandroid) (< net20) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net20) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net20) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net20) (>= netstandard1.5) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) - Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (< net20) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net20) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net20) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net20) (>= netstandard1.5) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) - Mono.Cecil (0.11.6) - restriction: >= net6.0 System.Buffers (4.6.1) - restriction: || (>= net462) (&& (>= net6.0) (< net8.0)) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) System.Collections.Immutable (10.0.2) - restriction: >= netstandard2.0 System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) @@ -84,9 +76,6 @@ NUGET System.Numerics.Vectors (4.6.1) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) System.Reactive (6.1) - restriction: >= netstandard2.0 System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net472) (&& (< net6.0) (>= netstandard2.0)) (>= uap10.1) - System.Runtime (4.3.1) - restriction: && (< net20) (>= netstandard1.0) (< netstandard2.0) - Microsoft.NETCore.Platforms (>= 1.1.1) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) - Microsoft.NETCore.Targets (>= 1.1.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) System.Runtime.CompilerServices.Unsafe (6.1.2) - restriction: || (>= net462) (&& (>= net6.0) (< net8.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) System.Text.Encodings.Web (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net462) (>= net6.0)) (&& (>= net6.0) (< net8.0)) (&& (>= net8.0) (< net9.0)) System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) diff --git a/fsharp-view-engine/src/Build/Build.fsproj b/docs/src/Build/Build.fsproj similarity index 100% rename from fsharp-view-engine/src/Build/Build.fsproj rename to docs/src/Build/Build.fsproj diff --git a/docs/src/Build/Program.fs b/docs/src/Build/Program.fs new file mode 100644 index 0000000..a748dc4 --- /dev/null +++ b/docs/src/Build/Program.fs @@ -0,0 +1,65 @@ +open Fake.Core +open Fake.Core.TargetOperators +open Fake.IO +open Fake.IO.FileSystemOperators +open Fake.IO.Globbing.Operators +open System.Text.RegularExpressions + +System.Environment.GetCommandLineArgs() +|> Array.tail +|> Array.toList +|> Context.FakeExecutionContext.Create false "build.fsx" +|> Context.RuntimeContext.Fake +|> Context.setExecutionContext + +let inline (==>!) x y = x ==> y |> ignore + +let srcDir = Path.getDirectory __SOURCE_DIRECTORY__ +let rootDir = Path.getDirectory srcDir +let docsDir = srcDir "Docs" + +let exec workDir cmd args = + CreateProcess.fromRawCommand cmd args + |> CreateProcess.withWorkingDirectory workDir + |> CreateProcess.ensureExitCode + |> Proc.start + |> Async.AwaitTask + |> Async.Ignore + +let execEnv env workDir cmd args = + CreateProcess.fromRawCommand cmd args + |> CreateProcess.withEnvironmentMap env + |> CreateProcess.withWorkingDirectory workDir + |> CreateProcess.ensureExitCode + |> Proc.start + |> Async.AwaitTask + |> Async.Ignore + +let dotnet workdir args = exec workdir "dotnet" args +let tailwindcss args = exec docsDir "tailwindcss" args + +Target.create "Watch" (fun _ -> + let watchApp = dotnet docsDir ["watch"; "run"; "--no-restore"] + let watchCss = tailwindcss ["--input"; "input.css"; "--output"; "wwwroot/css/output.css"; "--watch"] + Async.Parallel [| watchApp; watchCss |] + |> Async.RunSynchronously + |> ignore +) + +Target.create "BuildCss" <| fun _ -> + tailwindcss [ "--input"; "input.css"; "--output"; "wwwroot/css/output.css"; "--minify" ] + |> Async.RunSynchronously + +Target.create "Publish" <| fun _ -> + dotnet docsDir [ + "publish" + "--output"; "./out" + "--self-contained"; "false" + ] + |> Async.RunSynchronously + +Target.create "Default" (fun _ -> Target.listAvailable()) + +"BuildCss" ==>! "Publish" + +Target.runOrDefaultWithArguments "Default" diff --git a/fsharp-view-engine/src/Build/paket.references b/docs/src/Build/paket.references similarity index 100% rename from fsharp-view-engine/src/Build/paket.references rename to docs/src/Build/paket.references diff --git a/fsharp-view-engine/src/App/Config.fs b/docs/src/Docs/Config.fs similarity index 94% rename from fsharp-view-engine/src/App/Config.fs rename to docs/src/Docs/Config.fs index eda2226..828c661 100644 --- a/fsharp-view-engine/src/App/Config.fs +++ b/docs/src/Docs/Config.fs @@ -1,4 +1,4 @@ -namespace App +namespace Docs open System diff --git a/fsharp-view-engine/src/App/App.fsproj b/docs/src/Docs/Docs.fsproj similarity index 75% rename from fsharp-view-engine/src/App/App.fsproj rename to docs/src/Docs/Docs.fsproj index 7548c50..b50cd20 100644 --- a/fsharp-view-engine/src/App/App.fsproj +++ b/docs/src/Docs/Docs.fsproj @@ -5,6 +5,7 @@ $(NoWarn);NU1510 + @@ -21,13 +22,7 @@ - <_ContentIncludedByDefault Remove="Properties\launchSettings.json" /> - - - - - - + - \ No newline at end of file + diff --git a/docs/src/Docs/Handlers.fs b/docs/src/Docs/Handlers.fs new file mode 100644 index 0000000..91032d7 --- /dev/null +++ b/docs/src/Docs/Handlers.fs @@ -0,0 +1,66 @@ +namespace Docs + +open System +open System.IO +open System.Text.RegularExpressions +open Giraffe +open Microsoft.AspNetCore.Http +open Markdig +open FSharp.ViewEngine + +module Handlers = + + let private markdownPipeline = + MarkdownPipelineBuilder() + .UseAdvancedExtensions() + .Build() + + let private readMarkdownFile (fileName: string) = + let filePath = Path.Combine(AppContext.BaseDirectory, "docs", fileName + ".md") + if File.Exists(filePath) then + let content = File.ReadAllText(filePath) + Markdown.ToHtml(content, markdownPipeline) + else + "

Page Not Found

The requested page could not be found.

" + + let private extractHeadings (html: string) = + let pattern = """]*>([^<]+)""" + Regex.Matches(html, pattern) + |> Seq.cast + |> Seq.map (fun m -> (m.Groups.[2].Value.Trim(), m.Groups.[1].Value)) + |> Seq.toList + + let private renderPage (title: string) (fileName: string) : HttpHandler = + fun next ctx -> task { + let currentPath = ctx.Request.Path.Value + let markdownContent = readMarkdownFile fileName + let headings = extractHeadings markdownContent + let content = Views.layout title currentPath headings markdownContent + let html = Render.toHtmlDocString content + return! htmlString html next ctx + } + + // Route handlers + let homeHandler : HttpHandler = + renderPage "FSharp.ViewEngine Documentation" "home" + + let installationHandler : HttpHandler = + renderPage "Installation - FSharp.ViewEngine" "installation" + + let quickstartHandler : HttpHandler = + renderPage "Quickstart - FSharp.ViewEngine" "quickstart" + + let alpineHandler : HttpHandler = + renderPage "Alpine.js - FSharp.ViewEngine" "alpine" + + let datastarHandler : HttpHandler = + renderPage "Datastar - FSharp.ViewEngine" "datastar" + + let htmxHandler : HttpHandler = + renderPage "HTMX - FSharp.ViewEngine" "htmx" + + let svgHandler : HttpHandler = + renderPage "SVG - FSharp.ViewEngine" "svg" + + let tailwindHandler : HttpHandler = + renderPage "Tailwind - FSharp.ViewEngine" "tailwind" diff --git a/fsharp-view-engine/src/App/Program.fs b/docs/src/Docs/Program.fs similarity index 72% rename from fsharp-view-engine/src/App/Program.fs rename to docs/src/Docs/Program.fs index 306730c..4ef07bc 100644 --- a/fsharp-view-engine/src/App/Program.fs +++ b/docs/src/Docs/Program.fs @@ -2,7 +2,7 @@ open Microsoft.AspNetCore.Builder open Microsoft.Extensions.Hosting open Microsoft.Extensions.DependencyInjection open Giraffe -open App.Handlers +open Docs.Handlers let webApp = choose [ @@ -10,6 +10,11 @@ let webApp = route "/" >=> homeHandler route "/installation" >=> installationHandler route "/quickstart" >=> quickstartHandler + route "/extensions/alpine" >=> alpineHandler + route "/extensions/datastar" >=> datastarHandler + route "/extensions/htmx" >=> htmxHandler + route "/extensions/svg" >=> svgHandler + route "/extensions/tailwind" >=> tailwindHandler ] ] @@ -32,7 +37,7 @@ let main args = configureApp app - let config = App.Config.load() + let config = Docs.Config.load() app.Run(config.serverUrl) 0 // Exit code diff --git a/docs/src/Docs/Views.fs b/docs/src/Docs/Views.fs new file mode 100644 index 0000000..76e3a26 --- /dev/null +++ b/docs/src/Docs/Views.fs @@ -0,0 +1,291 @@ +module Docs.Views + +open FSharp.ViewEngine +open type Html +open type Alpine +open type Tailwind + +type Page = + { title:string } + +let magnifyingGlassIcon = raw """ + + + + """ +let menuIcon = raw """ + + + + """ +let githubIcon = raw """""" +let sunIcon = raw """""" +let moonIcon = raw """""" +let sunIconSmall = raw """""" +let moonIconSmall = raw """""" +let monitorIcon = raw """""" + +let private pageHeader = + header { + _class [ + "sticky top-0 z-50 flex flex-none flex-wrap items-center justify-between" + "bg-white px-4 py-5 shadow-md shadow-slate-900/5 transition duration-500" + "sm:px-6 lg:px-8 dark:shadow-none dark:bg-slate-900/75 dark:backdrop-blur" + ] + // Left section: hamburger + logo + div { + _class "flex items-center gap-4" + // Mobile menu button (hidden on desktop) + div { + _class "flex lg:hidden" + button { + _type "button" + _class "relative text-slate-500 hover:text-slate-600 dark:text-slate-400 dark:hover:text-slate-300" + menuIcon + } + } + // Logo + a { + _href "/" + _class "flex items-center gap-2 text-sm font-semibold tracking-wider text-slate-700 dark:text-white" + img { _src "/logo.png"; _alt "FSharp.ViewEngine"; _class "h-6 w-6" } + "FSharp.ViewEngine" + } + } + // Right section with theme toggle and GitHub + div { + _class "relative flex basis-0 justify-end gap-6 sm:gap-8 md:grow" + // Theme toggle dropdown + div { + _class "relative z-10" + _xData "{ open: false, theme: localStorage.getItem('theme') || 'system' }" + _xInit """ + $watch('theme', (val) => { + localStorage.setItem('theme', val); + if (val === 'dark' || (val === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + }); + if (theme === 'dark' || (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)) { + document.documentElement.classList.add('dark'); + } + """ + button { + _type "button" + _class [ + "flex h-6 w-6 items-center justify-center rounded-lg shadow-md ring-1" + "shadow-black/5 ring-black/5 dark:bg-slate-700 dark:ring-white/5" + "dark:ring-inset" + ] + _xOn ("click", "open = !open") + // Light mode icon (sun) + sunIcon + moonIcon + } + // Dropdown menu + div { + _xShow "open" + _xOn ("click.away", "open = false") + _xTransition () + _class [ + "absolute right-0 top-full mt-3 w-36 overflow-hidden rounded-lg" + "bg-white py-1 text-sm font-semibold text-slate-700 shadow-lg ring-1" + "ring-slate-900/10 dark:bg-slate-800 dark:text-slate-300 dark:ring-0" + "dark:highlight-white/5" + ] + // Light option + button { + _type "button" + _class "flex w-full items-center gap-2 px-3 py-2 hover:bg-slate-100 dark:hover:bg-slate-700/50" + _xOn ("click", "theme = 'light'; open = false") + _xBind ("class", "theme === 'light' ? 'text-sky-500' : ''") + sunIconSmall + text "Light" + } + // Dark option + button { + _type "button" + _class "flex w-full items-center gap-2 px-3 py-2 hover:bg-slate-100 dark:hover:bg-slate-700/50" + _xOn ("click", "theme = 'dark'; open = false") + _xBind ("class", "theme === 'dark' ? 'text-sky-500' : ''") + moonIconSmall + text "Dark" + } + // System option + button { + _type "button" + _class "flex w-full items-center gap-2 px-3 py-2 hover:bg-slate-100 dark:hover:bg-slate-700/50" + _xOn ("click", "theme = 'system'; open = false") + _xBind ("class", "theme === 'system' ? 'text-sky-500' : ''") + monitorIcon + text "System" + } + } + } + // GitHub link + a { + _href "https://github.com/meiermade/FSharp.ViewEngine" + _class "group" + githubIcon + } + } + } + +let private navLink (currentPath: string) (href': string) (label': string) = + let isActive = currentPath = href' + li { + _class "relative" + a { + _class [ + "block w-full pl-3.5 before:pointer-events-none before:absolute" + "before:-left-1 before:top-1/2 before:h-1.5 before:w-1.5" + "before:-translate-y-1/2 before:rounded-full" + if isActive then + "font-semibold text-sky-500 before:bg-sky-500" + else + "text-slate-500 before:hidden before:bg-slate-300 hover:text-slate-600" + + " hover:before:block dark:text-slate-400 dark:before:bg-slate-700 dark:hover:text-slate-300" + ] + _href href' + label' + } + } + +let private sidebarNavigation (currentPath: string) = + nav { + _class "text-base lg:text-sm" + ul { + _role "list" + _class "space-y-9" + li { + h2 { + _class "font-display font-medium text-slate-900 dark:text-white" + "Getting started" + } + ul { + _role "list" + _class [ + "mt-2 space-y-2 border-l-2 border-slate-100" + "lg:mt-4 lg:space-y-4 lg:border-slate-200 dark:border-slate-800" + ] + navLink currentPath "/" "Introduction" + navLink currentPath "/installation" "Installation" + navLink currentPath "/quickstart" "Quickstart" + } + } + li { + h2 { + _class "font-display font-medium text-slate-900 dark:text-white" + "Extensions" + } + ul { + _role "list" + _class [ + "mt-2 space-y-2 border-l-2 border-slate-100" + "lg:mt-4 lg:space-y-4 lg:border-slate-200 dark:border-slate-800" + ] + navLink currentPath "/extensions/alpine" "Alpine" + navLink currentPath "/extensions/datastar" "Datastar" + navLink currentPath "/extensions/htmx" "HTMX" + navLink currentPath "/extensions/svg" "SVG" + navLink currentPath "/extensions/tailwind" "Tailwind" + } + } + } + } + +let private sidebar (currentPath: string) = + div { + _class "hidden lg:relative lg:block lg:flex-none" + div { + _class [ + "sticky top-[4.75rem] -ml-0.5 h-[calc(100vh-4.75rem)] w-64" + "overflow-y-auto overflow-x-hidden py-16 pl-0.5 pr-8 xl:w-72 xl:pr-16" + ] + sidebarNavigation currentPath + } + } + +let private tableOfContents (headings: (string * string) list) = + if List.isEmpty headings then + empty + else + nav { + _class "sticky top-[4.75rem] -mr-6 w-56 flex-none overflow-y-auto py-16 pr-6" + h2 { + _class "font-display text-sm font-medium text-zinc-900 dark:text-white" + "On this page" + } + ul { + _role "list" + _class "mt-4 space-y-3 text-sm" + for (title', anchor) in headings do + li { + a { + _href $"#{anchor}" + _class "text-zinc-500 hover:text-zinc-600 dark:text-zinc-400 dark:hover:text-zinc-300" + title' + } + } + } + } + +let layout (pageTitle: string) (currentPath: string) (headings: (string * string) list) (content: string) = + html { + _lang "en" + _class "h-full antialiased" + head { + meta { _charset "utf-8" } + meta { _name "viewport"; _content "width=device-width, initial-scale=1" } + title pageTitle + script { js "let t=localStorage.getItem('theme');if(t==='dark'||(!t||t==='system')&&window.matchMedia('(prefers-color-scheme: dark)').matches){document.documentElement.classList.add('dark')}" } + link { _rel "stylesheet"; _href "/css/output.css" } + script { _src "https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"; _defer true } + script { _src "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js" } + link { _rel "stylesheet"; _href "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" } + script { _src "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-fsharp.min.js" } + } + body { + _class "min-h-full bg-white dark:bg-slate-900" + pageHeader + div { + _class [ + "relative mx-auto flex max-w-8xl justify-center" + "sm:px-2 lg:px-8 xl:px-12" + ] + sidebar currentPath + div { + _class [ + "min-w-0 max-w-3xl flex-auto px-4 py-16" + "lg:max-w-none lg:pl-8 lg:pr-0 xl:px-16" + ] + article { + div { + _class "mb-8" + p { + _class "font-display text-sm font-medium text-sky-500" + if currentPath.StartsWith("/extensions") then + "Extensions" + else + "Getting started" + } + } + div { + _class "prose prose-slate dark:prose-invert max-w-none" + raw content + } + } + } + div { + _class [ + "hidden xl:sticky xl:top-[4.75rem] xl:-mr-6 xl:block" + "xl:h-[calc(100vh-4.75rem)] xl:flex-none xl:overflow-y-auto" + "xl:py-16 xl:pr-6" + ] + tableOfContents headings + } + } + } + } diff --git a/docs/src/Docs/docs/alpine.md b/docs/src/Docs/docs/alpine.md new file mode 100644 index 0000000..ca06fda --- /dev/null +++ b/docs/src/Docs/docs/alpine.md @@ -0,0 +1,185 @@ +# Alpine.js + +FSharp.ViewEngine provides type-safe Alpine.js directives through the `Alpine` type. + +## Setup + +Open the `Alpine` type to access Alpine.js directives: + +```fsharp +open FSharp.ViewEngine +open type Html +open type Alpine +``` + +## Directives + +### x-data + +Initialize a component's reactive data with `_xData`: + +```fsharp +div { + _xData "{ open: false, count: 0 }" + button { + _xOn ("click", "count++") + "Increment" + } + span { _xText "count" } +} +``` + +### x-init + +Run an expression when a component is initialized: + +```fsharp +div { + _xData "{ users: [] }" + _xInit "users = await (await fetch('/api/users')).json()" +} +``` + +### x-show + +Toggle the visibility of an element: + +```fsharp +div { + _xData "{ open: false }" + button { _xOn ("click", "open = !open"); "Toggle" } + div { _xShow "open"; "Content here" } +} +``` + +### x-if + +Conditionally add or remove an element from the DOM: + +```fsharp +template { _xIf "open"; div { "Shown when open is true" } } +``` + +### x-for + +Loop over a list and render elements: + +```fsharp +template { + _xFor "item in items" + li { _xText "item" } +} +``` + +### x-bind + +Dynamically set HTML attributes: + +```fsharp +div { + _xBind ("class", "open ? 'block' : 'hidden'") +} +``` + +### x-on + +Listen for browser events: + +```fsharp +button { + _xOn ("click", "handleClick()") + _xOn ("mouseenter", "hovering = true") + "Click me" +} +``` + +### x-text + +Set the text content of an element: + +```fsharp +span { _xText "message" } +``` + +### x-model + +Two-way data binding for form elements: + +```fsharp +div { + _xData "{ search: '' }" + input { _type "text"; _xModel "search" } + p { _xText "search" } +} +``` + +You can also use modifiers: + +```fsharp +input { _xModel ("value", ".debounce.500ms") } +``` + +### x-ref + +Reference elements directly: + +```fsharp +div { + input { _xRef "nameInput" } + button { _xOn ("click", "$refs.nameInput.focus()"); "Focus" } +} +``` + +## Additional Directives + +### x-effect + +Execute a script each time one of its dependencies change: + +```fsharp +div { _xEffect "console.log(count)" } +``` + +### x-transition + +Apply transition classes during enter/leave: + +```fsharp +div { + _xShow "open" + _xTransition () + "Animated content" +} +``` + +### x-cloak + +Hide an element until Alpine is initialized: + +```fsharp +div { _xCloak; "Hidden until Alpine loads" } +``` + +### x-teleport + +Move an element to another location in the DOM: + +```fsharp +div { _xTeleport "body"; "Teleported to body" } +``` + +### x-trap + +Trap focus within an element: + +```fsharp +div { _xTrap "open"; "Focus is trapped here" } +``` + +### x-id + +Scope generated IDs to the component: + +```fsharp +div { _xId "['dropdown']" } +``` diff --git a/docs/src/Docs/docs/datastar.md b/docs/src/Docs/docs/datastar.md new file mode 100644 index 0000000..018d86c --- /dev/null +++ b/docs/src/Docs/docs/datastar.md @@ -0,0 +1,313 @@ +# Datastar + +FSharp.ViewEngine provides type-safe Datastar attributes through the `Datastar` type. + +## Setup + +Open the `Datastar` type to access Datastar attributes: + +```fsharp +open FSharp.ViewEngine +open type Html +open type Datastar +``` + +## Generic Attribute + +### data-* + +Use `_ds` for any Datastar `data-*` attribute: + +```fsharp +div { + _ds ("star", "true") + _ds "loading" +} +``` + +## Core Attributes + +### data-signals + +Define reactive signals on an element: + +```fsharp +div { + _dsSignals ("count", "0") + _dsSignals ("name", "'World'") +} +``` + +### data-on + +Listen for events and run expressions: + +```fsharp +button { + _dsOn ("click", "$count++") + "Increment" +} +``` + +### data-bind + +Two-way bind a signal to an input element: + +```fsharp +input { _type "text"; _dsBind "name" } +input { _type "text"; _dsBind ("name", "value") } +``` + +### data-show + +Conditionally show or hide an element: + +```fsharp +div { _dsShow "$count > 0"; "Count is positive" } +``` + +### data-text + +Set the text content of an element reactively: + +```fsharp +span { _dsText "$count" } +``` + +### data-effect + +Run an expression whenever its dependencies change: + +```fsharp +div { _dsEffect "console.log($count)" } +``` + +### data-init + +Run an expression when the element is initialized: + +```fsharp +div { _dsInit "console.log('initialized')" } +``` + +### data-attr + +Dynamically set an HTML attribute: + +```fsharp +div { _dsAttr ("disabled", "$count === 0") } +``` + +### data-class + +Toggle a CSS class based on an expression: + +```fsharp +div { _dsClass ("active", "$isActive") } +``` + +### data-computed + +Define a computed signal derived from other signals: + +```fsharp +div { _dsComputed ("double", "$count * 2") } +``` + +### data-style + +Dynamically set a CSS style property: + +```fsharp +div { _dsStyle ("color", "$isError ? 'red' : 'green'") } +``` + +### data-ref + +Reference an element by name: + +```fsharp +input { _dsRef "myInput" } +input { _dsRef ("myInput", "value") } +``` + +### data-indicator + +Bind a loading indicator signal: + +```fsharp +button { _dsIndicator "loading" } +button { _dsIndicator ("loading", "true") } +``` + +### data-json-signals + +Merge JSON signals into the signal store: + +```fsharp +div { _dsJsonSignals """{"count": 0}""" } +div { _dsJsonSignals () } +``` + +### data-ignore + +Prevent Datastar from processing an element: + +```fsharp +div { _dsIgnore } +``` + +### data-ignore-morph + +Prevent morphing of an element during updates: + +```fsharp +div { _dsIgnoreMorph } +``` + +### data-on-intersect + +Run an expression when an element enters the viewport: + +```fsharp +div { _dsOnIntersect "$count++" } +``` + +### data-on-interval + +Run an expression on a timed interval: + +```fsharp +div { _dsOnInterval "$count++" } +``` + +### data-on-signal-patch + +Run an expression when signals are patched: + +```fsharp +div { _dsOnSignalPatch "console.log('patched')" } +``` + +### data-on-signal-patch-filter + +Filter which signal patches trigger the expression: + +```fsharp +div { _dsOnSignalPatchFilter "count" } +``` + +### data-preserve-attr + +Preserve specified attributes during morphing: + +```fsharp +div { _dsPreserveAttr "class" } +``` + +## Pro Attributes + +### data-animate + +Apply animations to an element: + +```fsharp +div { _dsAnimate "fadeIn 0.5s" } +``` + +### data-custom-validity + +Set custom validation messages: + +```fsharp +input { _dsCustomValidity "$name === '' ? 'Name is required' : ''" } +``` + +### data-on-raf + +Run an expression on every animation frame: + +```fsharp +canvas { _dsOnRaf "draw()" } +``` + +### data-on-resize + +Run an expression when the element is resized: + +```fsharp +div { _dsOnResize "console.log('resized')" } +``` + +### data-persist + +Persist signals to local storage: + +```fsharp +div { _dsPersist "count" } +div { _dsPersist ("count", "session") } +``` + +### data-query-string + +Sync signals with URL query parameters: + +```fsharp +div { _dsQueryString "count" } +div { _dsQueryString () } +``` + +### data-replace-url + +Replace the current URL: + +```fsharp +div { _dsReplaceUrl "/new-path" } +``` + +### data-rocket + +Prefetch pages for instant navigation: + +```fsharp +a { _dsRocket "true"; _href "/next-page"; "Next" } +``` + +### data-scroll-into-view + +Scroll the element into view: + +```fsharp +div { _dsScrollIntoView } +``` + +### data-view-transition + +Apply view transitions: + +```fsharp +div { _dsViewTransition "fade" } +``` + +## Complete Example + +Here's a complete example combining multiple Datastar attributes: + +```fsharp +div { + _dsSignals ("count", "0") + _dsSignals ("name", "'World'") + _dsComputed ("greeting", "'Hello, ' + $name + '!'") + + input { _type "text"; _dsBind "name" } + span { _dsText "$greeting" } + + button { + _dsOn ("click", "$count++") + _dsClass ("active", "$count > 0") + "Clicked " + } + span { _dsText "$count" } + span { _dsShow "$count > 0"; " times" } +} +``` diff --git a/docs/src/Docs/docs/home.md b/docs/src/Docs/docs/home.md new file mode 100644 index 0000000..017abe2 --- /dev/null +++ b/docs/src/Docs/docs/home.md @@ -0,0 +1,56 @@ +# FSharp.ViewEngine Documentation + +A powerful F# view engine for building HTML with type safety and composability. Inspired by Giraffe.ViewEngine and Feliz.ViewEngine. + +## Key Features + +- **Type-safe HTML generation** with F# +- **Built-in support for HTMX attributes** +- **Tailwind CSS integration** +- **Alpine.js directives support** +- **Composable and functional approach** +- **No runtime dependencies** + +## Quick Example + +```fsharp +open FSharp.ViewEngine +open type Html +open type Htmx +open type Tailwind + +let myPage = + html { + _lang "en" + head { + title "My App" + meta { _charset "utf-8" } + link { _href "/css/tailwind.css"; _rel "stylesheet" } + } + body { + _class "bg-gray-100" + div { + _class [ "container"; "mx-auto"; "p-4" ] + h1 { + _class [ "text-3xl"; "font-bold"; "text-blue-600"; "mb-4" ] + "Welcome!" + } + button { + _class [ "bg-blue-500"; "text-white"; "px-4"; "py-2"; "rounded" ] + _hxGet "/api/data" + _hxTarget "#content" + "Load Content" + } + div { + _id "content" + _class [ "mt-4" ] + } + } + } + } + |> Render.toHtmlDocString +``` + +## Getting Started + +To get started with FSharp.ViewEngine, check out the [Installation](installation) guide and then follow the [Quickstart](quickstart) tutorial. diff --git a/docs/src/Docs/docs/htmx.md b/docs/src/Docs/docs/htmx.md new file mode 100644 index 0000000..8b284aa --- /dev/null +++ b/docs/src/Docs/docs/htmx.md @@ -0,0 +1,206 @@ +# HTMX + +FSharp.ViewEngine provides type-safe HTMX attributes through the `Htmx` type. + +## Setup + +Open the `Htmx` type to access HTMX attributes: + +```fsharp +open FSharp.ViewEngine +open type Html +open type Htmx +``` + +## Request Attributes + +### hx-get + +Issue a GET request to a URL: + +```fsharp +button { + _hxGet "/api/data" + "Load Data" +} +``` + +### hx-post + +Issue a POST request to a URL: + +```fsharp +form { + _hxPost "/api/submit" + input { _type "text"; _name "email" } + button { "Submit" } +} +``` + +### hx-delete + +Issue a DELETE request to a URL: + +```fsharp +button { + _hxDelete "/api/items/1" + "Delete" +} +``` + +### Generic hx attribute + +Use `_hx` for any HTMX attribute not covered by a dedicated helper: + +```fsharp +div { + _hx ("put", "/api/items/1") + _hx ("patch", "/api/items/1") +} +``` + +## Targeting and Swapping + +### hx-target + +Specify the target element for the response: + +```fsharp +button { + _hxGet "/api/data" + _hxTarget "#result" + "Load into #result" +} +div { _id "result" } +``` + +### hx-swap + +Control how the response content is swapped in: + +```fsharp +button { + _hxGet "/api/items" + _hxSwap "beforeend" + "Append Items" +} +``` + +Common swap values: `innerHTML`, `outerHTML`, `beforebegin`, `afterbegin`, `beforeend`, `afterend`, `delete`, `none`. + +### hx-swap-oob + +Swap content out-of-band (outside the target): + +```fsharp +div { + _hxSwapOOB "true" + _id "notifications" + "Updated notification content" +} +``` + +## Triggering and Events + +### hx-trigger + +Specify the event that triggers the request: + +```fsharp +input { + _type "text" + _hxGet "/api/search" + _hxTrigger "keyup changed delay:500ms" + _hxTarget "#results" +} +``` + +### hx-on + +Listen for HTMX events: + +```fsharp +form { + _hxPost "/api/submit" + _hxOn ("htmx:beforeRequest", "showSpinner()") + _hxOn ("htmx:afterRequest", "hideSpinner()") +} +``` + +## Other Attributes + +### hx-indicator + +Show a loading indicator during requests: + +```fsharp +button { + _hxGet "/api/slow" + _hxIndicator "#spinner" + "Load" +} +div { _id "spinner"; _class "htmx-indicator"; "Loading..." } +``` + +### hx-include + +Include additional element values in the request: + +```fsharp +button { + _hxPost "/api/submit" + _hxInclude "[name='email']" + "Submit" +} +``` + +### hx-encoding + +Set the encoding type for requests: + +```fsharp +form { + _hxPost "/api/upload" + _hxEncoding "multipart/form-data" +} +``` + +### hx-vals + +Add additional values to the request: + +```fsharp +button { + _hxPost "/api/action" + _hxVals """{"key": "value"}""" + "Submit" +} +``` + +### hx-history + +Control the history behavior: + +```fsharp +div { _hxHistory "false" } +``` + +## Complete Example + +Here's a complete example combining multiple HTMX attributes: + +```fsharp +div { + _class "search-container" + input { + _type "text" + _name "q" + _hxGet "/api/search" + _hxTrigger "keyup changed delay:300ms" + _hxTarget "#search-results" + _hxIndicator "#search-spinner" + } + span { _id "search-spinner"; _class "htmx-indicator"; "Searching..." } + div { _id "search-results" } +} +``` diff --git a/fsharp-view-engine/src/App/docs/installation.md b/docs/src/Docs/docs/installation.md similarity index 100% rename from fsharp-view-engine/src/App/docs/installation.md rename to docs/src/Docs/docs/installation.md diff --git a/docs/src/Docs/docs/quickstart.md b/docs/src/Docs/docs/quickstart.md new file mode 100644 index 0000000..b576d97 --- /dev/null +++ b/docs/src/Docs/docs/quickstart.md @@ -0,0 +1,88 @@ +# Quickstart + +Get started with FSharp.ViewEngine in just a few steps. + +## Basic Usage + +Import the core modules and start building HTML: + +```fsharp +open FSharp.ViewEngine +open type Html + +let myView = + div { + _class "container" + h1 { "Hello, World!" } + p { "Welcome to FSharp.ViewEngine" } + } + +// Render to string +let htmlString = Render.toHtmlDocString myView +``` + +This will produce the following HTML: + +```html +
+

Hello, World!

+

Welcome to FSharp.ViewEngine

+
+``` + +## With HTMX and Tailwind CSS + +FSharp.ViewEngine includes built-in support for HTMX and Tailwind CSS: + +```fsharp +open FSharp.ViewEngine +open type Html +open type Htmx +open type Tailwind + +let interactiveView = + div { + _class [ "bg-blue-500"; "text-white"; "p-4"; "rounded" ] + button { + _class [ "bg-green-500"; "hover:bg-green-700"; "px-4"; "py-2"; "rounded" ] + _hxGet "/api/data" + _hxTarget "#result" + "Load Data" + } + div { + _id "result" + _class [ "mt-4" ] + } + } +``` + +## Complete HTML Document + +Here's how to create a complete HTML document: + +```fsharp +let completePage = + html { + _lang "en" + head { + title "My Page" + meta { _charset "utf-8" } + meta { _name "viewport"; _content "width=device-width, initial-scale=1" } + link { _rel "stylesheet"; _href "https://cdn.tailwindcss.com" } + } + body { + _class [ "bg-gray-100"; "font-sans" ] + div { + _class [ "container"; "mx-auto"; "px-4"; "py-8" ] + h1 { + _class [ "text-3xl"; "font-bold"; "text-gray-900"; "mb-4" ] + "Welcome to my site!" + } + p { + _class [ "text-lg"; "text-gray-600" ] + "This is built with FSharp.ViewEngine." + } + } + } + } +``` diff --git a/docs/src/Docs/docs/svg.md b/docs/src/Docs/docs/svg.md new file mode 100644 index 0000000..2713b26 --- /dev/null +++ b/docs/src/Docs/docs/svg.md @@ -0,0 +1,155 @@ +# SVG + +FSharp.ViewEngine provides type-safe SVG elements and attributes through the `Svg` type. + +## Setup + +Open the `Svg` type to access SVG elements and attributes: + +```fsharp +open FSharp.ViewEngine +open type Html +open type Svg +``` + +## Elements + +### svg + +The root SVG container element: + +```fsharp +svg { + _viewBox "0 0 24 24" + _width 24 + _height 24 + // child elements here +} +``` + +### path + +Define a shape using a path data string: + +```fsharp +svg { + _viewBox "0 0 24 24" + _fill "none" + path { + _d "M12 2L2 22h20L12 2z" + _stroke "currentColor" + _strokeWidth 2 + } +} +``` + +### circle + +Draw a circle: + +```fsharp +svg { + _viewBox "0 0 100 100" + circle { + _cx 50 + _cy 50 + _r 40 + _fill "blue" + _stroke "black" + _strokeWidth 2 + } +} +``` + +## Attributes + +### Dimensions + +Set the width and height of the SVG: + +```fsharp +svg { _width 48; _height 48 } +``` + +### viewBox + +Define the coordinate system and aspect ratio: + +```fsharp +svg { _viewBox "0 0 100 100" } +``` + +### Fill and Stroke + +Control the fill color and stroke styling: + +```fsharp +path { + _d "M0 0 L10 10" + _fill "none" + _stroke "red" + _strokeWidth 2 + _strokeLinecap "round" + _strokeLinejoin "round" +} +``` + +### Fill Rule and Clip Rule + +Control how overlapping paths are filled or clipped: + +```fsharp +path { + _d "M0 0 L10 10 L20 0 Z" + _fillRule "evenodd" + _clipRule "evenodd" +} +``` + +## Complete Example + +Here's a complete icon example: + +```fsharp +let checkIcon = + svg { + _viewBox "0 0 24 24" + _width 24 + _height 24 + _fill "none" + path { + _d "M5 13l4 4L19 7" + _stroke "currentColor" + _strokeWidth 2 + _strokeLinecap "round" + _strokeLinejoin "round" + } + } +``` + +And a more complex example with multiple elements: + +```fsharp +let statusIcon = + svg { + _viewBox "0 0 100 100" + _width 100 + _height 100 + circle { + _cx 50 + _cy 50 + _r 45 + _fill "green" + _stroke "darkgreen" + _strokeWidth 2 + } + path { + _d "M30 50 L45 65 L70 35" + _fill "none" + _stroke "white" + _strokeWidth 6 + _strokeLinecap "round" + _strokeLinejoin "round" + } + } +``` diff --git a/docs/src/Docs/docs/tailwind.md b/docs/src/Docs/docs/tailwind.md new file mode 100644 index 0000000..196647b --- /dev/null +++ b/docs/src/Docs/docs/tailwind.md @@ -0,0 +1,201 @@ +# Tailwind + +FSharp.ViewEngine provides custom elements for Tailwind UI components through the `Tailwind` type. + +## Setup + +Open the `Tailwind` type to access Tailwind custom elements: + +```fsharp +open FSharp.ViewEngine +open type Html +open type Tailwind +``` + +## Form Elements + +### Autocomplete + +Build an autocomplete input with filtered options: + +```fsharp +elAutocomplete { + _class "w-64" + input { _type "text"; _placeholder "Search..." } + elOptions { + elOption { "Option 1" } + elOption { "Option 2" } + elOption { "Option 3" } + } +} +``` + +### Select + +Create a custom select dropdown: + +```fsharp +elSelect { + _class "w-48" + elSelectedContent { "Choose an option" } + elOptions { + elOption { "Small" } + elOption { "Medium" } + elOption { "Large" } + } +} +``` + +## Overlay Elements + +### Dialog + +Build a modal dialog with a backdrop: + +```fsharp +elDialog { + elDialogBackdrop { _class "fixed inset-0 bg-black/30" } + elDialogPanel { + _class "mx-auto max-w-sm rounded bg-white p-6" + h2 { "Dialog Title" } + p { "Dialog content goes here." } + button { "Close" } + } +} +``` + +### Dropdown + +Create a dropdown menu: + +```fsharp +elDropdown { + button { "Options" } + elMenu { + _class "absolute mt-2 w-48 rounded bg-white shadow-lg" + a { _href "#"; "Edit" } + a { _href "#"; "Delete" } + } +} +``` + +## Navigation Elements + +### Tab Group + +Build a tabbed interface: + +```fsharp +elTabGroup { + elTabList { + _class "flex space-x-1 rounded-xl bg-blue-900/20 p-1" + button { "Tab 1" } + button { "Tab 2" } + button { "Tab 3" } + } + elTabPanels { + div { "Content for Tab 1" } + div { "Content for Tab 2" } + div { "Content for Tab 3" } + } +} +``` + +## Command Palette + +### Command Palette + +Build a command palette for search and navigation: + +```fsharp +elCommandPalette { + input { _type "text"; _placeholder "Search commands..." } + elCommandList { + elCommandGroup { + _class "p-2" + div { "Open File" } + div { "Run Command" } + } + elCommandPreview { + _class "p-4" + "Preview content here" + } + } + elNoResults { "No results found." } +} +``` + +## Attributes + +### popover + +Mark an element as a popover: + +```fsharp +div { _popover; "Popover content" } +``` + +### anchor + +Position an element relative to a reference using anchor positioning: + +```fsharp +div { + _anchor "bottom-start" + "Anchored content" +} +``` + +## Defaults + +Use `elDefaults` to set default values for child components: + +```fsharp +elDefaults { + _class "text-sm" + elSelect { + elOptions { + elOption { "A" } + elOption { "B" } + } + } +} +``` + +## Complete Example + +Here's a complete example combining several Tailwind UI elements: + +```fsharp +div { + _class "p-8" + elTabGroup { + elTabList { + _class "flex space-x-1 rounded-xl bg-blue-900/20 p-1" + button { _class "rounded-lg px-3 py-2"; "Search" } + button { _class "rounded-lg px-3 py-2"; "Browse" } + } + elTabPanels { + div { + elAutocomplete { + _class "mt-4 w-full" + input { _type "text"; _placeholder "Search items..." } + elOptions { + elOption { "Item 1" } + elOption { "Item 2" } + } + } + } + div { + elSelect { + _class "mt-4 w-full" + elOptions { + elOption { "Category A" } + elOption { "Category B" } + } + } + } + } + } +} +``` diff --git a/fsharp-view-engine/src/App/input.css b/docs/src/Docs/input.css similarity index 95% rename from fsharp-view-engine/src/App/input.css rename to docs/src/Docs/input.css index 6300d01..5fc0506 100644 --- a/fsharp-view-engine/src/App/input.css +++ b/docs/src/Docs/input.css @@ -54,3 +54,8 @@ font-size: 0.875rem !important; font-weight: 500 !important; } + +.prose code::before, +.prose code::after { + content: none !important; +} diff --git a/fsharp-view-engine/src/App/paket.references b/docs/src/Docs/paket.references similarity index 100% rename from fsharp-view-engine/src/App/paket.references rename to docs/src/Docs/paket.references diff --git a/docs/src/Docs/wwwroot/android-chrome-192x192.png b/docs/src/Docs/wwwroot/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..fdc6c412c8d939cbd823aef61ba6e29a29af8a3d GIT binary patch literal 16687 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 KMNUMnLSTZ1QM#W1 literal 0 HcmV?d00001 diff --git a/docs/src/Docs/wwwroot/android-chrome-512x512.png b/docs/src/Docs/wwwroot/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..a656cd0a2aabd6991d32966ab20251e1f17d09a2 GIT binary patch literal 44925 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 literal 0 HcmV?d00001 diff --git a/docs/src/Docs/wwwroot/css/output.css b/docs/src/Docs/wwwroot/css/output.css new file mode 100644 index 0000000..54ba522 --- /dev/null +++ b/docs/src/Docs/wwwroot/css/output.css @@ -0,0 +1,1760 @@ +/*! tailwindcss v4.1.11 | MIT License | https://tailwindcss.com */ +@layer properties; +@layer theme, base, components, utilities; +@layer theme { + :root, :host { + --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', + monospace; + --color-green-500: oklch(72.3% 0.219 149.579); + --color-green-700: oklch(52.7% 0.154 150.069); + --color-sky-500: oklch(68.5% 0.169 237.323); + --color-blue-500: oklch(62.3% 0.214 259.815); + --color-blue-600: oklch(54.6% 0.245 262.881); + --color-blue-900: oklch(37.9% 0.146 265.522); + --color-slate-100: oklch(96.8% 0.007 247.896); + --color-slate-200: oklch(92.9% 0.013 255.508); + --color-slate-300: oklch(86.9% 0.022 252.894); + --color-slate-400: oklch(70.4% 0.04 256.788); + --color-slate-500: oklch(55.4% 0.046 257.417); + --color-slate-600: oklch(44.6% 0.043 257.281); + --color-slate-700: oklch(37.2% 0.044 257.287); + --color-slate-800: oklch(27.9% 0.041 260.031); + --color-slate-900: oklch(20.8% 0.042 265.755); + --color-gray-100: oklch(96.7% 0.003 264.542); + --color-gray-600: oklch(44.6% 0.03 256.802); + --color-gray-900: oklch(21% 0.034 264.665); + --color-zinc-300: oklch(87.1% 0.006 286.286); + --color-zinc-400: oklch(70.5% 0.015 286.067); + --color-zinc-500: oklch(55.2% 0.016 285.938); + --color-zinc-600: oklch(44.2% 0.017 285.786); + --color-zinc-900: oklch(21% 0.006 285.885); + --color-black: #000; + --color-white: #fff; + --spacing: 0.25rem; + --container-sm: 24rem; + --container-3xl: 48rem; + --text-sm: 0.875rem; + --text-sm--line-height: calc(1.25 / 0.875); + --text-base: 1rem; + --text-base--line-height: calc(1.5 / 1); + --text-lg: 1.125rem; + --text-lg--line-height: calc(1.75 / 1.125); + --text-3xl: 1.875rem; + --text-3xl--line-height: calc(2.25 / 1.875); + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + --tracking-wider: 0.05em; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + --default-transition-duration: 150ms; + --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + --default-font-family: var(--font-sans); + --default-mono-font-family: var(--font-mono); + } +} +@layer base { + *, ::after, ::before, ::backdrop, ::file-selector-button { + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0 solid; + } + html, :host { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + tab-size: 4; + font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'); + font-feature-settings: var(--default-font-feature-settings, normal); + font-variation-settings: var(--default-font-variation-settings, normal); + -webkit-tap-highlight-color: transparent; + } + hr { + height: 0; + color: inherit; + border-top-width: 1px; + } + abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + } + h1, h2, h3, h4, h5, h6 { + font-size: inherit; + font-weight: inherit; + } + a { + color: inherit; + -webkit-text-decoration: inherit; + text-decoration: inherit; + } + b, strong { + font-weight: bolder; + } + code, kbd, samp, pre { + font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace); + font-feature-settings: var(--default-mono-font-feature-settings, normal); + font-variation-settings: var(--default-mono-font-variation-settings, normal); + font-size: 1em; + } + small { + font-size: 80%; + } + sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + sub { + bottom: -0.25em; + } + sup { + top: -0.5em; + } + table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; + } + :-moz-focusring { + outline: auto; + } + progress { + vertical-align: baseline; + } + summary { + display: list-item; + } + ol, ul, menu { + list-style: none; + } + img, svg, video, canvas, audio, iframe, embed, object { + display: block; + vertical-align: middle; + } + img, video { + max-width: 100%; + height: auto; + } + button, input, select, optgroup, textarea, ::file-selector-button { + font: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + letter-spacing: inherit; + color: inherit; + border-radius: 0; + background-color: transparent; + opacity: 1; + } + :where(select:is([multiple], [size])) optgroup { + font-weight: bolder; + } + :where(select:is([multiple], [size])) optgroup option { + padding-inline-start: 20px; + } + ::file-selector-button { + margin-inline-end: 4px; + } + ::placeholder { + opacity: 1; + } + @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { + ::placeholder { + color: currentcolor; + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, currentcolor 50%, transparent); + } + } + } + textarea { + resize: vertical; + } + ::-webkit-search-decoration { + -webkit-appearance: none; + } + ::-webkit-date-and-time-value { + min-height: 1lh; + text-align: inherit; + } + ::-webkit-datetime-edit { + display: inline-flex; + } + ::-webkit-datetime-edit-fields-wrapper { + padding: 0; + } + ::-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-block: 0; + } + :-moz-ui-invalid { + box-shadow: none; + } + button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button { + appearance: button; + } + ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { + height: auto; + } + [hidden]:where(:not([hidden='until-found'])) { + display: none !important; + } +} +@layer utilities { + .collapse { + visibility: collapse; + } + .visible { + visibility: visible; + } + .absolute { + position: absolute; + } + .fixed { + position: fixed; + } + .relative { + position: relative; + } + .sticky { + position: sticky; + } + .inset-0 { + inset: calc(var(--spacing) * 0); + } + .top-0 { + top: calc(var(--spacing) * 0); + } + .top-\[4\.75rem\] { + top: 4.75rem; + } + .top-full { + top: 100%; + } + .right-0 { + right: calc(var(--spacing) * 0); + } + .z-10 { + z-index: 10; + } + .z-50 { + z-index: 50; + } + .container { + width: 100%; + @media (width >= 40rem) { + max-width: 40rem; + } + @media (width >= 48rem) { + max-width: 48rem; + } + @media (width >= 64rem) { + max-width: 64rem; + } + @media (width >= 80rem) { + max-width: 80rem; + } + @media (width >= 96rem) { + max-width: 96rem; + } + } + .mx-auto { + margin-inline: auto; + } + .prose { + color: var(--tw-prose-body); + max-width: 65ch; + :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; + } + :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-lead); + font-size: 1.25em; + line-height: 1.6; + margin-top: 1.2em; + margin-bottom: 1.2em; + } + :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-links); + text-decoration: underline; + font-weight: 500; + } + :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-bold); + font-weight: 600; + } + :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + } + :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + } + :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + } + :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: decimal; + margin-top: 1.25em; + margin-bottom: 1.25em; + padding-inline-start: 1.625em; + } + :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: upper-alpha; + } + :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: lower-alpha; + } + :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: upper-alpha; + } + :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: lower-alpha; + } + :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: upper-roman; + } + :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: lower-roman; + } + :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: upper-roman; + } + :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: lower-roman; + } + :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: decimal; + } + :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: disc; + margin-top: 1.25em; + margin-bottom: 1.25em; + padding-inline-start: 1.625em; + } + :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { + font-weight: 400; + color: var(--tw-prose-counters); + } + :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { + color: var(--tw-prose-bullets); + } + :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 600; + margin-top: 1.25em; + } + :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-color: var(--tw-prose-hr); + border-top-width: 1; + margin-top: 3em; + margin-bottom: 3em; + } + :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 500; + font-style: italic; + color: var(--tw-prose-quotes); + border-inline-start-width: 0.25rem; + border-inline-start-color: var(--tw-prose-quote-borders); + quotes: "\201C""\201D""\2018""\2019"; + margin-top: 1.6em; + margin-bottom: 1.6em; + padding-inline-start: 1em; + } + :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { + content: open-quote; + } + :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { + content: close-quote; + } + :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 800; + font-size: 2.25em; + margin-top: 0; + margin-bottom: 0.8888889em; + line-height: 1.1111111; + } + :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 900; + color: inherit; + } + :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 700; + font-size: 1.5em; + margin-top: 2em; + margin-bottom: 1em; + line-height: 1.3333333; + } + :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 800; + color: inherit; + } + :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 600; + font-size: 1.25em; + margin-top: 1.6em; + margin-bottom: 0.6em; + line-height: 1.6; + } + :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 700; + color: inherit; + } + :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 600; + margin-top: 1.5em; + margin-bottom: 0.5em; + line-height: 1.5; + } + :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 700; + color: inherit; + } + :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; + } + :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + display: block; + margin-top: 2em; + margin-bottom: 2em; + } + :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; + } + :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 500; + font-family: inherit; + color: var(--tw-prose-kbd); + box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); + font-size: 0.875em; + border-radius: 0.3125rem; + padding-top: 0.1875em; + padding-inline-end: 0.375em; + padding-bottom: 0.1875em; + padding-inline-start: 0.375em; + } + :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-code); + font-weight: 600; + font-size: 0.875em; + } + :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { + content: "`"; + } + :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { + content: "`"; + } + :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + } + :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + } + :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + font-size: 0.875em; + } + :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + font-size: 0.9em; + } + :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + } + :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + } + :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + } + :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-pre-code); + background-color: var(--tw-prose-pre-bg); + overflow-x: auto; + font-weight: 400; + font-size: 0.875em; + line-height: 1.7142857; + margin-top: 1.7142857em; + margin-bottom: 1.7142857em; + border-radius: 0.375rem; + padding-top: 0.8571429em; + padding-inline-end: 1.1428571em; + padding-bottom: 0.8571429em; + padding-inline-start: 1.1428571em; + } + :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + background-color: transparent; + border-width: 0; + border-radius: 0; + padding: 0; + font-weight: inherit; + color: inherit; + font-size: inherit; + font-family: inherit; + line-height: inherit; + } + :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { + content: none; + } + :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { + content: none; + } + :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + width: 100%; + table-layout: auto; + margin-top: 2em; + margin-bottom: 2em; + font-size: 0.875em; + line-height: 1.7142857; + } + :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-bottom-width: 1px; + border-bottom-color: var(--tw-prose-th-borders); + } + :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 600; + vertical-align: bottom; + padding-inline-end: 0.5714286em; + padding-bottom: 0.5714286em; + padding-inline-start: 0.5714286em; + } + :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-bottom-width: 1px; + border-bottom-color: var(--tw-prose-td-borders); + } + :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-bottom-width: 0; + } + :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + vertical-align: baseline; + } + :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-top-width: 1px; + border-top-color: var(--tw-prose-th-borders); + } + :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + vertical-align: top; + } + :where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + text-align: start; + } + :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + margin-bottom: 0; + } + :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-captions); + font-size: 0.875em; + line-height: 1.4285714; + margin-top: 0.8571429em; + } + --tw-prose-body: oklch(37.3% 0.034 259.733); + --tw-prose-headings: oklch(21% 0.034 264.665); + --tw-prose-lead: oklch(44.6% 0.03 256.802); + --tw-prose-links: oklch(21% 0.034 264.665); + --tw-prose-bold: oklch(21% 0.034 264.665); + --tw-prose-counters: oklch(55.1% 0.027 264.364); + --tw-prose-bullets: oklch(87.2% 0.01 258.338); + --tw-prose-hr: oklch(92.8% 0.006 264.531); + --tw-prose-quotes: oklch(21% 0.034 264.665); + --tw-prose-quote-borders: oklch(92.8% 0.006 264.531); + --tw-prose-captions: oklch(55.1% 0.027 264.364); + --tw-prose-kbd: oklch(21% 0.034 264.665); + --tw-prose-kbd-shadows: NaN NaN NaN; + --tw-prose-code: oklch(21% 0.034 264.665); + --tw-prose-pre-code: oklch(92.8% 0.006 264.531); + --tw-prose-pre-bg: oklch(27.8% 0.033 256.848); + --tw-prose-th-borders: oklch(87.2% 0.01 258.338); + --tw-prose-td-borders: oklch(92.8% 0.006 264.531); + --tw-prose-invert-body: oklch(87.2% 0.01 258.338); + --tw-prose-invert-headings: #fff; + --tw-prose-invert-lead: oklch(70.7% 0.022 261.325); + --tw-prose-invert-links: #fff; + --tw-prose-invert-bold: #fff; + --tw-prose-invert-counters: oklch(70.7% 0.022 261.325); + --tw-prose-invert-bullets: oklch(44.6% 0.03 256.802); + --tw-prose-invert-hr: oklch(37.3% 0.034 259.733); + --tw-prose-invert-quotes: oklch(96.7% 0.003 264.542); + --tw-prose-invert-quote-borders: oklch(37.3% 0.034 259.733); + --tw-prose-invert-captions: oklch(70.7% 0.022 261.325); + --tw-prose-invert-kbd: #fff; + --tw-prose-invert-kbd-shadows: 255 255 255; + --tw-prose-invert-code: #fff; + --tw-prose-invert-pre-code: oklch(87.2% 0.01 258.338); + --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); + --tw-prose-invert-th-borders: oklch(44.6% 0.03 256.802); + --tw-prose-invert-td-borders: oklch(37.3% 0.034 259.733); + font-size: 1rem; + line-height: 1.75; + :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + margin-bottom: 0; + } + :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.5em; + margin-bottom: 0.5em; + } + :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0.375em; + } + :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0.375em; + } + :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; + } + :where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + } + :where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 1.25em; + } + :where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + } + :where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 1.25em; + } + :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; + } + :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; + } + :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.5em; + padding-inline-start: 1.625em; + } + :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0; + } + :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0; + } + :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-top: 0.5714286em; + padding-inline-end: 0.5714286em; + padding-bottom: 0.5714286em; + padding-inline-start: 0.5714286em; + } + :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0; + } + :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0; + } + :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; + } + :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 0; + } + } + .mt-2 { + margin-top: calc(var(--spacing) * 2); + } + .mt-3 { + margin-top: calc(var(--spacing) * 3); + } + .mt-4 { + margin-top: calc(var(--spacing) * 4); + } + .-mr-6 { + margin-right: calc(var(--spacing) * -6); + } + .mb-4 { + margin-bottom: calc(var(--spacing) * 4); + } + .mb-8 { + margin-bottom: calc(var(--spacing) * 8); + } + .-ml-0\.5 { + margin-left: calc(var(--spacing) * -0.5); + } + .block { + display: block; + } + .flex { + display: flex; + } + .hidden { + display: none; + } + .inline { + display: inline; + } + .size-4 { + width: calc(var(--spacing) * 4); + height: calc(var(--spacing) * 4); + } + .h-5 { + height: calc(var(--spacing) * 5); + } + .h-6 { + height: calc(var(--spacing) * 6); + } + .h-\[calc\(100vh-4\.75rem\)\] { + height: calc(100vh - 4.75rem); + } + .h-full { + height: 100%; + } + .min-h-full { + min-height: 100%; + } + .w-5 { + width: calc(var(--spacing) * 5); + } + .w-6 { + width: calc(var(--spacing) * 6); + } + .w-36 { + width: calc(var(--spacing) * 36); + } + .w-48 { + width: calc(var(--spacing) * 48); + } + .w-56 { + width: calc(var(--spacing) * 56); + } + .w-64 { + width: calc(var(--spacing) * 64); + } + .w-full { + width: 100%; + } + .max-w-3xl { + max-width: var(--container-3xl); + } + .max-w-none { + max-width: none; + } + .max-w-sm { + max-width: var(--container-sm); + } + .min-w-0 { + min-width: calc(var(--spacing) * 0); + } + .flex-auto { + flex: auto; + } + .flex-none { + flex: none; + } + .basis-0 { + flex-basis: calc(var(--spacing) * 0); + } + .transform { + transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); + } + .flex-wrap { + flex-wrap: wrap; + } + .items-center { + align-items: center; + } + .justify-between { + justify-content: space-between; + } + .justify-center { + justify-content: center; + } + .justify-end { + justify-content: flex-end; + } + .gap-2 { + gap: calc(var(--spacing) * 2); + } + .gap-4 { + gap: calc(var(--spacing) * 4); + } + .gap-6 { + gap: calc(var(--spacing) * 6); + } + .space-y-2 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-y-3 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-y-9 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 9) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 9) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-x-1 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 1) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-x-reverse))); + } + } + .overflow-hidden { + overflow: hidden; + } + .overflow-x-hidden { + overflow-x: hidden; + } + .overflow-y-auto { + overflow-y: auto; + } + .rounded { + border-radius: 0.25rem; + } + .rounded-lg { + border-radius: var(--radius-lg); + } + .rounded-xl { + border-radius: var(--radius-xl); + } + .border-l-2 { + border-left-style: var(--tw-border-style); + border-left-width: 2px; + } + .border-slate-100 { + border-color: var(--color-slate-100); + } + .bg-black\/30 { + background-color: color-mix(in srgb, #000 30%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-black) 30%, transparent); + } + } + .bg-blue-500 { + background-color: var(--color-blue-500); + } + .bg-blue-900\/20 { + background-color: color-mix(in srgb, oklch(37.9% 0.146 265.522) 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-blue-900) 20%, transparent); + } + } + .bg-gray-100 { + background-color: var(--color-gray-100); + } + .bg-green-500 { + background-color: var(--color-green-500); + } + .bg-white { + background-color: var(--color-white); + } + .fill-slate-400 { + fill: var(--color-slate-400); + } + .stroke-sky-500 { + stroke: var(--color-sky-500); + } + .p-1 { + padding: calc(var(--spacing) * 1); + } + .p-2 { + padding: calc(var(--spacing) * 2); + } + .p-4 { + padding: calc(var(--spacing) * 4); + } + .p-6 { + padding: calc(var(--spacing) * 6); + } + .p-8 { + padding: calc(var(--spacing) * 8); + } + .px-3 { + padding-inline: calc(var(--spacing) * 3); + } + .px-4 { + padding-inline: calc(var(--spacing) * 4); + } + .py-1 { + padding-block: calc(var(--spacing) * 1); + } + .py-2 { + padding-block: calc(var(--spacing) * 2); + } + .py-5 { + padding-block: calc(var(--spacing) * 5); + } + .py-8 { + padding-block: calc(var(--spacing) * 8); + } + .py-16 { + padding-block: calc(var(--spacing) * 16); + } + .pr-6 { + padding-right: calc(var(--spacing) * 6); + } + .pr-8 { + padding-right: calc(var(--spacing) * 8); + } + .pl-0\.5 { + padding-left: calc(var(--spacing) * 0.5); + } + .pl-3\.5 { + padding-left: calc(var(--spacing) * 3.5); + } + .font-sans { + font-family: var(--font-sans); + } + .text-3xl { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); + } + .text-base { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + } + .text-lg { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + } + .text-sm { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .font-bold { + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); + } + .font-medium { + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + } + .font-semibold { + --tw-font-weight: var(--font-weight-semibold); + font-weight: var(--font-weight-semibold); + } + .tracking-wider { + --tw-tracking: var(--tracking-wider); + letter-spacing: var(--tracking-wider); + } + .text-blue-600 { + color: var(--color-blue-600); + } + .text-gray-600 { + color: var(--color-gray-600); + } + .text-gray-900 { + color: var(--color-gray-900); + } + .text-sky-500 { + color: var(--color-sky-500); + } + .text-slate-500 { + color: var(--color-slate-500); + } + .text-slate-700 { + color: var(--color-slate-700); + } + .text-slate-900 { + color: var(--color-slate-900); + } + .text-white { + color: var(--color-white); + } + .text-zinc-500 { + color: var(--color-zinc-500); + } + .text-zinc-900 { + color: var(--color-zinc-900); + } + .antialiased { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + .shadow-lg { + --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .shadow-md { + --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .ring-1 { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .shadow-black\/5 { + --tw-shadow-color: color-mix(in srgb, #000 5%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-black) 5%, transparent) var(--tw-shadow-alpha), transparent); + } + } + .shadow-slate-900\/5 { + --tw-shadow-color: color-mix(in srgb, oklch(20.8% 0.042 265.755) 5%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-slate-900) 5%, transparent) var(--tw-shadow-alpha), transparent); + } + } + .ring-black\/5 { + --tw-ring-color: color-mix(in srgb, #000 5%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --tw-ring-color: color-mix(in oklab, var(--color-black) 5%, transparent); + } + } + .ring-slate-900\/10 { + --tw-ring-color: color-mix(in srgb, oklch(20.8% 0.042 265.755) 10%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --tw-ring-color: color-mix(in oklab, var(--color-slate-900) 10%, transparent); + } + } + .transition { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .duration-500 { + --tw-duration: 500ms; + transition-duration: 500ms; + } + .prose-slate { + --tw-prose-body: oklch(37.2% 0.044 257.287); + --tw-prose-headings: oklch(20.8% 0.042 265.755); + --tw-prose-lead: oklch(44.6% 0.043 257.281); + --tw-prose-links: oklch(20.8% 0.042 265.755); + --tw-prose-bold: oklch(20.8% 0.042 265.755); + --tw-prose-counters: oklch(55.4% 0.046 257.417); + --tw-prose-bullets: oklch(86.9% 0.022 252.894); + --tw-prose-hr: oklch(92.9% 0.013 255.508); + --tw-prose-quotes: oklch(20.8% 0.042 265.755); + --tw-prose-quote-borders: oklch(92.9% 0.013 255.508); + --tw-prose-captions: oklch(55.4% 0.046 257.417); + --tw-prose-kbd: oklch(20.8% 0.042 265.755); + --tw-prose-kbd-shadows: NaN NaN NaN; + --tw-prose-code: oklch(20.8% 0.042 265.755); + --tw-prose-pre-code: oklch(92.9% 0.013 255.508); + --tw-prose-pre-bg: oklch(27.9% 0.041 260.031); + --tw-prose-th-borders: oklch(86.9% 0.022 252.894); + --tw-prose-td-borders: oklch(92.9% 0.013 255.508); + --tw-prose-invert-body: oklch(86.9% 0.022 252.894); + --tw-prose-invert-headings: #fff; + --tw-prose-invert-lead: oklch(70.4% 0.04 256.788); + --tw-prose-invert-links: #fff; + --tw-prose-invert-bold: #fff; + --tw-prose-invert-counters: oklch(70.4% 0.04 256.788); + --tw-prose-invert-bullets: oklch(44.6% 0.043 257.281); + --tw-prose-invert-hr: oklch(37.2% 0.044 257.287); + --tw-prose-invert-quotes: oklch(96.8% 0.007 247.896); + --tw-prose-invert-quote-borders: oklch(37.2% 0.044 257.287); + --tw-prose-invert-captions: oklch(70.4% 0.04 256.788); + --tw-prose-invert-kbd: #fff; + --tw-prose-invert-kbd-shadows: 255 255 255; + --tw-prose-invert-code: #fff; + --tw-prose-invert-pre-code: oklch(86.9% 0.022 252.894); + --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); + --tw-prose-invert-th-borders: oklch(44.6% 0.043 257.281); + --tw-prose-invert-td-borders: oklch(37.2% 0.044 257.287); + } + .group-hover\:fill-slate-500 { + &:is(:where(.group):hover *) { + @media (hover: hover) { + fill: var(--color-slate-500); + } + } + } + .before\:pointer-events-none { + &::before { + content: var(--tw-content); + pointer-events: none; + } + } + .before\:absolute { + &::before { + content: var(--tw-content); + position: absolute; + } + } + .before\:top-1\/2 { + &::before { + content: var(--tw-content); + top: calc(1/2 * 100%); + } + } + .before\:-left-1 { + &::before { + content: var(--tw-content); + left: calc(var(--spacing) * -1); + } + } + .before\:hidden { + &::before { + content: var(--tw-content); + display: none; + } + } + .before\:h-1\.5 { + &::before { + content: var(--tw-content); + height: calc(var(--spacing) * 1.5); + } + } + .before\:w-1\.5 { + &::before { + content: var(--tw-content); + width: calc(var(--spacing) * 1.5); + } + } + .before\:-translate-y-1\/2 { + &::before { + content: var(--tw-content); + --tw-translate-y: calc(calc(1/2 * 100%) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + } + .before\:rounded-full { + &::before { + content: var(--tw-content); + border-radius: calc(infinity * 1px); + } + } + .before\:bg-sky-500 { + &::before { + content: var(--tw-content); + background-color: var(--color-sky-500); + } + } + .before\:bg-slate-300 { + &::before { + content: var(--tw-content); + background-color: var(--color-slate-300); + } + } + .hover\:bg-green-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-green-700); + } + } + } + .hover\:bg-slate-100 { + &:hover { + @media (hover: hover) { + background-color: var(--color-slate-100); + } + } + } + .hover\:text-slate-600 { + &:hover { + @media (hover: hover) { + color: var(--color-slate-600); + } + } + } + .hover\:text-zinc-600 { + &:hover { + @media (hover: hover) { + color: var(--color-zinc-600); + } + } + } + .hover\:before\:block { + &:hover { + @media (hover: hover) { + &::before { + content: var(--tw-content); + display: block; + } + } + } + } + .sm\:gap-8 { + @media (width >= 40rem) { + gap: calc(var(--spacing) * 8); + } + } + .sm\:px-2 { + @media (width >= 40rem) { + padding-inline: calc(var(--spacing) * 2); + } + } + .sm\:px-6 { + @media (width >= 40rem) { + padding-inline: calc(var(--spacing) * 6); + } + } + .md\:grow { + @media (width >= 48rem) { + flex-grow: 1; + } + } + .lg\:relative { + @media (width >= 64rem) { + position: relative; + } + } + .lg\:mt-4 { + @media (width >= 64rem) { + margin-top: calc(var(--spacing) * 4); + } + } + .lg\:block { + @media (width >= 64rem) { + display: block; + } + } + .lg\:hidden { + @media (width >= 64rem) { + display: none; + } + } + .lg\:max-w-none { + @media (width >= 64rem) { + max-width: none; + } + } + .lg\:flex-none { + @media (width >= 64rem) { + flex: none; + } + } + .lg\:space-y-4 { + @media (width >= 64rem) { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); + } + } + } + .lg\:border-slate-200 { + @media (width >= 64rem) { + border-color: var(--color-slate-200); + } + } + .lg\:px-8 { + @media (width >= 64rem) { + padding-inline: calc(var(--spacing) * 8); + } + } + .lg\:pr-0 { + @media (width >= 64rem) { + padding-right: calc(var(--spacing) * 0); + } + } + .lg\:pl-8 { + @media (width >= 64rem) { + padding-left: calc(var(--spacing) * 8); + } + } + .lg\:text-sm { + @media (width >= 64rem) { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + } + .xl\:sticky { + @media (width >= 80rem) { + position: sticky; + } + } + .xl\:top-\[4\.75rem\] { + @media (width >= 80rem) { + top: 4.75rem; + } + } + .xl\:-mr-6 { + @media (width >= 80rem) { + margin-right: calc(var(--spacing) * -6); + } + } + .xl\:block { + @media (width >= 80rem) { + display: block; + } + } + .xl\:h-\[calc\(100vh-4\.75rem\)\] { + @media (width >= 80rem) { + height: calc(100vh - 4.75rem); + } + } + .xl\:w-72 { + @media (width >= 80rem) { + width: calc(var(--spacing) * 72); + } + } + .xl\:flex-none { + @media (width >= 80rem) { + flex: none; + } + } + .xl\:overflow-y-auto { + @media (width >= 80rem) { + overflow-y: auto; + } + } + .xl\:px-12 { + @media (width >= 80rem) { + padding-inline: calc(var(--spacing) * 12); + } + } + .xl\:px-16 { + @media (width >= 80rem) { + padding-inline: calc(var(--spacing) * 16); + } + } + .xl\:py-16 { + @media (width >= 80rem) { + padding-block: calc(var(--spacing) * 16); + } + } + .xl\:pr-6 { + @media (width >= 80rem) { + padding-right: calc(var(--spacing) * 6); + } + } + .xl\:pr-16 { + @media (width >= 80rem) { + padding-right: calc(var(--spacing) * 16); + } + } + .dark\:block { + &:where(.dark, .dark *) { + display: block; + } + } + .dark\:hidden { + &:where(.dark, .dark *) { + display: none; + } + } + .dark\:border-slate-800 { + &:where(.dark, .dark *) { + border-color: var(--color-slate-800); + } + } + .dark\:bg-slate-700 { + &:where(.dark, .dark *) { + background-color: var(--color-slate-700); + } + } + .dark\:bg-slate-800 { + &:where(.dark, .dark *) { + background-color: var(--color-slate-800); + } + } + .dark\:bg-slate-900 { + &:where(.dark, .dark *) { + background-color: var(--color-slate-900); + } + } + .dark\:bg-slate-900\/75 { + &:where(.dark, .dark *) { + background-color: color-mix(in srgb, oklch(20.8% 0.042 265.755) 75%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-slate-900) 75%, transparent); + } + } + } + .dark\:text-slate-300 { + &:where(.dark, .dark *) { + color: var(--color-slate-300); + } + } + .dark\:text-slate-400 { + &:where(.dark, .dark *) { + color: var(--color-slate-400); + } + } + .dark\:text-white { + &:where(.dark, .dark *) { + color: var(--color-white); + } + } + .dark\:text-zinc-400 { + &:where(.dark, .dark *) { + color: var(--color-zinc-400); + } + } + .dark\:shadow-none { + &:where(.dark, .dark *) { + --tw-shadow: 0 0 #0000; + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + } + .dark\:ring-0 { + &:where(.dark, .dark *) { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + } + .dark\:ring-white\/5 { + &:where(.dark, .dark *) { + --tw-ring-color: color-mix(in srgb, #fff 5%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --tw-ring-color: color-mix(in oklab, var(--color-white) 5%, transparent); + } + } + } + .dark\:backdrop-blur { + &:where(.dark, .dark *) { + --tw-backdrop-blur: blur(8px); + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } + } + .dark\:prose-invert { + &:where(.dark, .dark *) { + --tw-prose-body: var(--tw-prose-invert-body); + --tw-prose-headings: var(--tw-prose-invert-headings); + --tw-prose-lead: var(--tw-prose-invert-lead); + --tw-prose-links: var(--tw-prose-invert-links); + --tw-prose-bold: var(--tw-prose-invert-bold); + --tw-prose-counters: var(--tw-prose-invert-counters); + --tw-prose-bullets: var(--tw-prose-invert-bullets); + --tw-prose-hr: var(--tw-prose-invert-hr); + --tw-prose-quotes: var(--tw-prose-invert-quotes); + --tw-prose-quote-borders: var(--tw-prose-invert-quote-borders); + --tw-prose-captions: var(--tw-prose-invert-captions); + --tw-prose-kbd: var(--tw-prose-invert-kbd); + --tw-prose-kbd-shadows: var(--tw-prose-invert-kbd-shadows); + --tw-prose-code: var(--tw-prose-invert-code); + --tw-prose-pre-code: var(--tw-prose-invert-pre-code); + --tw-prose-pre-bg: var(--tw-prose-invert-pre-bg); + --tw-prose-th-borders: var(--tw-prose-invert-th-borders); + --tw-prose-td-borders: var(--tw-prose-invert-td-borders); + } + } + .dark\:ring-inset { + &:where(.dark, .dark *) { + --tw-ring-inset: inset; + } + } + .dark\:group-hover\:fill-slate-300 { + &:where(.dark, .dark *) { + &:is(:where(.group):hover *) { + @media (hover: hover) { + fill: var(--color-slate-300); + } + } + } + } + .dark\:before\:bg-slate-700 { + &:where(.dark, .dark *) { + &::before { + content: var(--tw-content); + background-color: var(--color-slate-700); + } + } + } + .dark\:hover\:bg-slate-700\/50 { + &:where(.dark, .dark *) { + &:hover { + @media (hover: hover) { + background-color: color-mix(in srgb, oklch(37.2% 0.044 257.287) 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-slate-700) 50%, transparent); + } + } + } + } + } + .dark\:hover\:text-slate-300 { + &:where(.dark, .dark *) { + &:hover { + @media (hover: hover) { + color: var(--color-slate-300); + } + } + } + } + .dark\:hover\:text-zinc-300 { + &:where(.dark, .dark *) { + &:hover { + @media (hover: hover) { + color: var(--color-zinc-300); + } + } + } + } +} +.prose pre { + position: relative; + border-radius: 0.75rem; + background-color: rgb(15 23 42); + border: 1px solid rgb(30 41 59); + box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); + overflow-x: auto; +} +.prose pre code { + background-color: transparent !important; + border-radius: 0; + padding: 0; + color: rgb(226 232 240); + font-size: 0.875rem; + line-height: 1.7; + font-family: 'Fira Code', 'JetBrains Mono', 'Monaco', 'Cascadia Code', 'Segoe UI Mono', 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; +} +.prose pre code .hljs-keyword { + color: rgb(168 85 247); +} +.prose pre code .hljs-string { + color: rgb(34 197 94); +} +.prose pre code .hljs-comment { + color: rgb(148 163 184); + font-style: italic; +} +.prose pre code .hljs-function { + color: rgb(59 130 246); +} +.prose pre code .hljs-number { + color: rgb(251 146 60); +} +.prose :not(pre) > code { + background-color: rgb(51 65 85) !important; + color: rgb(226 232 240) !important; + padding: 0.25rem 0.5rem !important; + border-radius: 0.375rem !important; + font-size: 0.875rem !important; + font-weight: 500 !important; +} +.prose code::before, .prose code::after { + content: none !important; +} +@property --tw-rotate-x { + syntax: "*"; + inherits: false; +} +@property --tw-rotate-y { + syntax: "*"; + inherits: false; +} +@property --tw-rotate-z { + syntax: "*"; + inherits: false; +} +@property --tw-skew-x { + syntax: "*"; + inherits: false; +} +@property --tw-skew-y { + syntax: "*"; + inherits: false; +} +@property --tw-space-y-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-space-x-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-border-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-font-weight { + syntax: "*"; + inherits: false; +} +@property --tw-tracking { + syntax: "*"; + inherits: false; +} +@property --tw-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-inset-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-inset-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-inset-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-ring-color { + syntax: "*"; + inherits: false; +} +@property --tw-ring-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-inset-ring-color { + syntax: "*"; + inherits: false; +} +@property --tw-inset-ring-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-ring-inset { + syntax: "*"; + inherits: false; +} +@property --tw-ring-offset-width { + syntax: ""; + inherits: false; + initial-value: 0px; +} +@property --tw-ring-offset-color { + syntax: "*"; + inherits: false; + initial-value: #fff; +} +@property --tw-ring-offset-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-duration { + syntax: "*"; + inherits: false; +} +@property --tw-content { + syntax: "*"; + initial-value: ""; + inherits: false; +} +@property --tw-translate-x { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-translate-y { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-translate-z { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-backdrop-blur { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-invert { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-sepia { + syntax: "*"; + inherits: false; +} +@layer properties { + @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { + *, ::before, ::after, ::backdrop { + --tw-rotate-x: initial; + --tw-rotate-y: initial; + --tw-rotate-z: initial; + --tw-skew-x: initial; + --tw-skew-y: initial; + --tw-space-y-reverse: 0; + --tw-space-x-reverse: 0; + --tw-border-style: solid; + --tw-font-weight: initial; + --tw-tracking: initial; + --tw-shadow: 0 0 #0000; + --tw-shadow-color: initial; + --tw-shadow-alpha: 100%; + --tw-inset-shadow: 0 0 #0000; + --tw-inset-shadow-color: initial; + --tw-inset-shadow-alpha: 100%; + --tw-ring-color: initial; + --tw-ring-shadow: 0 0 #0000; + --tw-inset-ring-color: initial; + --tw-inset-ring-shadow: 0 0 #0000; + --tw-ring-inset: initial; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-duration: initial; + --tw-content: ""; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-translate-z: 0; + --tw-backdrop-blur: initial; + --tw-backdrop-brightness: initial; + --tw-backdrop-contrast: initial; + --tw-backdrop-grayscale: initial; + --tw-backdrop-hue-rotate: initial; + --tw-backdrop-invert: initial; + --tw-backdrop-opacity: initial; + --tw-backdrop-saturate: initial; + --tw-backdrop-sepia: initial; + } + } +} diff --git a/docs/src/Docs/wwwroot/favicon-16x16.png b/docs/src/Docs/wwwroot/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..18875a42e0d2df7d810c39d9402665196f2f0b6a GIT binary patch literal 765 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 literal 0 HcmV?d00001 diff --git a/docs/src/Docs/wwwroot/favicon.ico b/docs/src/Docs/wwwroot/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..719dd278081fde57d8f2f086e170fe5bde7940e6 GIT binary patch literal 15406 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 F@L&BGdX@kH literal 0 HcmV?d00001 diff --git a/docs/src/Docs/wwwroot/logo.png b/docs/src/Docs/wwwroot/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d75e5fdbd5b5481bae8c3a697e6cc0199cee474f GIT binary patch literal 73569 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%0D9-P)^%Yb3u)S^eaFd|^;87jtK`3j!@GAX@ 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%0D9-P)^%Yb3u)S^eaFd|^;87jtK`3j!@GAX@ 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 + + + + + + + + + + + + + + + + + + diff --git a/fsharp-view-engine/FSharp.ViewEngine.sln b/fsharp-view-engine/FSharp.ViewEngine.sln deleted file mode 100644 index 01a0d46..0000000 --- a/fsharp-view-engine/FSharp.ViewEngine.sln +++ /dev/null @@ -1,48 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30114.105 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EA093A44-5365-45ED-B8FB-C506C95405A6}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.ViewEngine", "src\FSharp.ViewEngine\FSharp.ViewEngine.fsproj", "{4093E9E9-D923-4945-A458-C1F861C3FD1D}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Build", "src\Build\Build.fsproj", "{2562C7E1-2366-4DB0-9A86-278B8AA5117B}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests", "src\Tests\Tests.fsproj", "{65C2946A-1B1E-45AB-8196-DFE772FA9240}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "App", "src\App\App.fsproj", "{ADA5276C-21C3-4633-B83F-F50A93D5FF36}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4093E9E9-D923-4945-A458-C1F861C3FD1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4093E9E9-D923-4945-A458-C1F861C3FD1D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4093E9E9-D923-4945-A458-C1F861C3FD1D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4093E9E9-D923-4945-A458-C1F861C3FD1D}.Release|Any CPU.Build.0 = Release|Any CPU - {2562C7E1-2366-4DB0-9A86-278B8AA5117B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2562C7E1-2366-4DB0-9A86-278B8AA5117B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2562C7E1-2366-4DB0-9A86-278B8AA5117B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2562C7E1-2366-4DB0-9A86-278B8AA5117B}.Release|Any CPU.Build.0 = Release|Any CPU - {65C2946A-1B1E-45AB-8196-DFE772FA9240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {65C2946A-1B1E-45AB-8196-DFE772FA9240}.Debug|Any CPU.Build.0 = Debug|Any CPU - {65C2946A-1B1E-45AB-8196-DFE772FA9240}.Release|Any CPU.ActiveCfg = Release|Any CPU - {65C2946A-1B1E-45AB-8196-DFE772FA9240}.Release|Any CPU.Build.0 = Release|Any CPU - {ADA5276C-21C3-4633-B83F-F50A93D5FF36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ADA5276C-21C3-4633-B83F-F50A93D5FF36}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ADA5276C-21C3-4633-B83F-F50A93D5FF36}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ADA5276C-21C3-4633-B83F-F50A93D5FF36}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {4093E9E9-D923-4945-A458-C1F861C3FD1D} = {EA093A44-5365-45ED-B8FB-C506C95405A6} - {2562C7E1-2366-4DB0-9A86-278B8AA5117B} = {EA093A44-5365-45ED-B8FB-C506C95405A6} - {65C2946A-1B1E-45AB-8196-DFE772FA9240} = {EA093A44-5365-45ED-B8FB-C506C95405A6} - {ADA5276C-21C3-4633-B83F-F50A93D5FF36} = {EA093A44-5365-45ED-B8FB-C506C95405A6} - EndGlobalSection -EndGlobal diff --git a/fsharp-view-engine/src/App/Handlers.fs b/fsharp-view-engine/src/App/Handlers.fs deleted file mode 100644 index d2a1ef4..0000000 --- a/fsharp-view-engine/src/App/Handlers.fs +++ /dev/null @@ -1,39 +0,0 @@ -namespace App - -open System -open System.IO -open Giraffe -open Microsoft.AspNetCore.Http -open Markdig -open FSharp.ViewEngine - -module Handlers = - - let private markdownPipeline = MarkdownPipelineBuilder().UseAdvancedExtensions().Build() - - let private readMarkdownFile (fileName: string) = - let filePath = Path.Combine(AppContext.BaseDirectory, "docs", fileName + ".md") - if File.Exists(filePath) then - let content = File.ReadAllText(filePath) - Markdown.ToHtml(content, markdownPipeline) - else - "

Page Not Found

The requested page could not be found.

" - - let private renderPage (title: string) (fileName: string) : HttpHandler = - fun next ctx -> task { - let currentPath = ctx.Request.Path.Value - let markdownContent = readMarkdownFile fileName - let content = Views.layout title currentPath markdownContent - let html = Element.render content - return! htmlString html next ctx - } - - // Route handlers - let homeHandler : HttpHandler = - renderPage "FSharp.ViewEngine Documentation" "home" - - let installationHandler : HttpHandler = - renderPage "Installation - FSharp.ViewEngine" "installation" - - let quickstartHandler : HttpHandler = - renderPage "Quickstart - FSharp.ViewEngine" "quickstart" diff --git a/fsharp-view-engine/src/App/Views.fs b/fsharp-view-engine/src/App/Views.fs deleted file mode 100644 index 5a335a4..0000000 --- a/fsharp-view-engine/src/App/Views.fs +++ /dev/null @@ -1,324 +0,0 @@ -module App.Views - -open FSharp.ViewEngine -open type Html -open type Alpine - -type Page = - { title:string } - -let magnifyingGlassIcon = raw """ - - - - """ -let menuIcon = raw """ - - - - """ -let githubIcon = raw """""" -let sunIcon = raw """""" -let moonIcon = raw """""" -let sunIconSmall = raw """""" -let moonIconSmall = raw """""" -let monitorIcon = raw """""" - -let private pageHeader = - header [ - _class [ - "sticky top-0 z-50 flex flex-none flex-wrap items-center justify-between" - "bg-white px-4 py-5 shadow-md shadow-slate-900/5 transition duration-500" - "sm:px-6 lg:px-8 dark:shadow-none dark:bg-slate-900/75 dark:backdrop-blur" - ] - _children [ - // Left section: hamburger + logo - div [ - _class "flex items-center gap-4" - _children [ - // Mobile menu button (hidden on desktop) - div [ - _class "flex lg:hidden" - _children [ - button [ - _type "button" - _class "relative text-slate-500 hover:text-slate-600 dark:text-slate-400 dark:hover:text-slate-300" - _children menuIcon - ] - ] - ] - // Logo - a [ - _href "/" - _class "text-sm font-semibold tracking-wider text-slate-700 dark:text-white" - _children "FSharp.ViewEngine" - ] - ] - ] - // Right section with theme toggle and GitHub - div [ - _class "relative flex basis-0 justify-end gap-6 sm:gap-8 md:grow" - _children [ - // Theme toggle dropdown - div [ - _class "relative z-10" - _xData "{ open: false, theme: localStorage.getItem('theme') || 'system' }" - _xInit """ - $watch('theme', (val) => { - localStorage.setItem('theme', val); - if (val === 'dark' || (val === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)) { - document.documentElement.classList.add('dark'); - } else { - document.documentElement.classList.remove('dark'); - } - }); - if (theme === 'dark' || (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)) { - document.documentElement.classList.add('dark'); - } - """ - _children [ - button [ - _type "button" - _class [ - "flex h-6 w-6 items-center justify-center rounded-lg shadow-md ring-1" - "shadow-black/5 ring-black/5 dark:bg-slate-700 dark:ring-white/5" - "dark:ring-inset" - ] - _xOn ("click", "open = !open") - _children [ - // Light mode icon (sun) - sunIcon - moonIcon - ] - ] - // Dropdown menu - div [ - _xShow "open" - _xOn ("click.away", "open = false") - _xTransition () - _class [ - "absolute right-0 top-full mt-3 w-36 overflow-hidden rounded-lg" - "bg-white py-1 text-sm font-semibold text-slate-700 shadow-lg ring-1" - "ring-slate-900/10 dark:bg-slate-800 dark:text-slate-300 dark:ring-0" - "dark:highlight-white/5" - ] - _children [ - // Light option - button [ - _type "button" - _class "flex w-full items-center gap-2 px-3 py-2 hover:bg-slate-100 dark:hover:bg-slate-700/50" - _xOn ("click", "theme = 'light'; open = false") - _xBind ("class", "theme === 'light' ? 'text-sky-500' : ''") - _children [ - sunIconSmall - text "Light" - ] - ] - // Dark option - button [ - _type "button" - _class "flex w-full items-center gap-2 px-3 py-2 hover:bg-slate-100 dark:hover:bg-slate-700/50" - _xOn ("click", "theme = 'dark'; open = false") - _xBind ("class", "theme === 'dark' ? 'text-sky-500' : ''") - _children [ - moonIconSmall - text "Dark" - ] - ] - // System option - button [ - _type "button" - _class "flex w-full items-center gap-2 px-3 py-2 hover:bg-slate-100 dark:hover:bg-slate-700/50" - _xOn ("click", "theme = 'system'; open = false") - _xBind ("class", "theme === 'system' ? 'text-sky-500' : ''") - _children [ - monitorIcon - text "System" - ] - ] - ] - ] - ] - ] - // GitHub link - a [ - _href "https://github.com/meiermade/FSharp.ViewEngine" - _class "group" - _children [ - githubIcon - ] - ] - ] - ] - ] - ] - -let private navLink (currentPath: string) (href: string) (label: string) = - let isActive = currentPath = href - li [ - _class "relative" - _children [ - a [ - _class [ - "block w-full pl-3.5 before:pointer-events-none before:absolute" - "before:-left-1 before:top-1/2 before:h-1.5 before:w-1.5" - "before:-translate-y-1/2 before:rounded-full" - if isActive then - "font-semibold text-sky-500 before:bg-sky-500" - else - "text-slate-500 before:hidden before:bg-slate-300 hover:text-slate-600" - + " hover:before:block dark:text-slate-400 dark:before:bg-slate-700 dark:hover:text-slate-300" - ] - _href href - _children label - ] - ] - ] - -let private sidebarNavigation (currentPath: string) = - nav [ - _class "text-base lg:text-sm" - _children [ - ul [ - _role "list" - _class "space-y-9" - _children [ - li [ - _children [ - h2 [ - _class "font-display font-medium text-slate-900 dark:text-white" - _children "Getting started" - ] - ul [ - _role "list" - _class [ - "mt-2 space-y-2 border-l-2 border-slate-100" - "lg:mt-4 lg:space-y-4 lg:border-slate-200 dark:border-slate-800" - ] - _children [ - navLink currentPath "/" "Introduction" - navLink currentPath "/installation" "Installation" - navLink currentPath "/quickstart" "Quickstart" - ] - ] - ] - ] - ] - ] - ] - ] - -let private sidebar (currentPath: string) = - div [ - _class "hidden lg:relative lg:block lg:flex-none" - _children [ - div [ - _class [ - "sticky top-[4.75rem] -ml-0.5 h-[calc(100vh-4.75rem)] w-64" - "overflow-y-auto overflow-x-hidden py-16 pl-0.5 pr-8 xl:w-72 xl:pr-16" - ] - _children [ - sidebarNavigation currentPath - ] - ] - ] - ] - -let private tableOfContents (headings: (string * string) list) = - if List.isEmpty headings then - empty - else - nav [ - _class "sticky top-[4.75rem] -mr-6 w-56 flex-none overflow-y-auto py-16 pr-6" - _children [ - h2 [ - _class "font-display text-sm font-medium text-zinc-900 dark:text-white" - _children "On this page" - ] - ul [ - _role "list" - _class "mt-4 space-y-3 text-sm" - _children [ - for (title, anchor) in headings do - yield li [ - _children [ - a [ - _href $"#{anchor}" - _class "text-zinc-500 hover:text-zinc-600 dark:text-zinc-400 dark:hover:text-zinc-300" - _children title - ] - ] - ] - ] - ] - ] - ] - -let layout (pageTitle: string) (currentPath: string) (content: string) = - html [ - _lang "en" - _class "h-full antialiased" - _children [ - head [ - meta [ _charset "utf-8" ] - meta [ _name "viewport"; _content "width=device-width, initial-scale=1" ] - title pageTitle - script "let t=localStorage.getItem('theme');if(t==='dark'||(!t||t==='system')&&window.matchMedia('(prefers-color-scheme: dark)').matches){document.documentElement.classList.add('dark')}" - link [ _rel "stylesheet"; _href "/css/output.css" ] - script [ _src "https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"; KeyValue ("defer", "true") ] - script [ _src "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js" ] - link [ _rel "stylesheet"; _href "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" ] - script [ _src "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-fsharp.min.js" ] - ] - body [ - _class "min-h-full bg-white dark:bg-slate-900" - _children [ - pageHeader - div [ - _class [ - "relative mx-auto flex max-w-8xl justify-center" - "sm:px-2 lg:px-8 xl:px-12" - ] - _children [ - sidebar currentPath - div [ - _class [ - "min-w-0 max-w-3xl flex-auto px-4 py-16" - "lg:max-w-none lg:pl-8 lg:pr-0 xl:px-16" - ] - _children [ - article [ - _children [ - div [ - _class "mb-8" - _children [ - p [ - _class "font-display text-sm font-medium text-sky-500" - _children "Getting started" - ] - ] - ] - div [ - _class "prose prose-slate dark:prose-invert max-w-none" - _children [ raw content ] - ] - ] - ] - ] - ] - div [ - _class [ - "hidden xl:sticky xl:top-[4.75rem] xl:-mr-6 xl:block" - "xl:h-[calc(100vh-4.75rem)] xl:flex-none xl:overflow-y-auto" - "xl:py-16 xl:pr-6" - ] - _children [ - tableOfContents [] - ] - ] - ] - ] - ] - ] - ] - ] diff --git a/fsharp-view-engine/src/App/docs/home.md b/fsharp-view-engine/src/App/docs/home.md deleted file mode 100644 index 9ef741d..0000000 --- a/fsharp-view-engine/src/App/docs/home.md +++ /dev/null @@ -1,62 +0,0 @@ -# FSharp.ViewEngine Documentation - -A powerful F# view engine for building HTML with type safety and composability. Inspired by Giraffe.ViewEngine and Feliz.ViewEngine. - -## Key Features - -- **Type-safe HTML generation** with F# -- **Built-in support for HTMX attributes** -- **Tailwind CSS integration** -- **Alpine.js directives support** -- **Composable and functional approach** -- **No runtime dependencies** - -## Quick Example - -```fsharp -open FSharp.ViewEngine -open type Html -open type Htmx -open type Tailwind - -let myPage = - html [ - _lang "en" - _children [ - head [ - title "My App" - meta [ _charset "utf-8" ] - link [ _href "/css/tailwind.css"; _rel "stylesheet" ] - ] - body [ - _class "bg-gray-100" - _children [ - div [ - _class [ "container"; "mx-auto"; "p-4" ] - _children [ - h1 [ - _class [ "text-3xl"; "font-bold"; "text-blue-600"; "mb-4" ] - _children "Welcome!" - ] - button [ - _class [ "bg-blue-500"; "text-white"; "px-4"; "py-2"; "rounded" ] - _hxGet "/api/data" - _hxTarget "#content" - _children "Load Content" - ] - div [ - _id "content" - _class [ "mt-4" ] - ] - ] - ] - ] - ] - ] - ] - |> Element.render -``` - -## Getting Started - -To get started with FSharp.ViewEngine, check out the [Installation](installation) guide and then follow the [Quickstart](quickstart) tutorial. \ No newline at end of file diff --git a/fsharp-view-engine/src/App/docs/quickstart.md b/fsharp-view-engine/src/App/docs/quickstart.md deleted file mode 100644 index 76ab000..0000000 --- a/fsharp-view-engine/src/App/docs/quickstart.md +++ /dev/null @@ -1,98 +0,0 @@ -# Quickstart - -Get started with FSharp.ViewEngine in just a few steps. - -## Basic Usage - -Import the core modules and start building HTML: - -```fsharp -open FSharp.ViewEngine -open type Html - -let myView = - div [ - _class "container" - _children [ - h1 [ _children "Hello, World!" ] - p [ _children "Welcome to FSharp.ViewEngine" ] - ] - ] - -// Render to string -let htmlString = Element.render myView -``` - -This will produce the following HTML: - -```html -
-

Hello, World!

-

Welcome to FSharp.ViewEngine

-
-``` - -## With HTMX and Tailwind CSS - -FSharp.ViewEngine includes built-in support for HTMX and Tailwind CSS: - -```fsharp -open FSharp.ViewEngine -open type Html -open type Htmx -open type Tailwind - -let interactiveView = - div [ - _class [ "bg-blue-500"; "text-white"; "p-4"; "rounded" ] - _children [ - button [ - _class [ "bg-green-500"; "hover:bg-green-700"; "px-4"; "py-2"; "rounded" ] - _hxGet "/api/data" - _hxTarget "#result" - _children "Load Data" - ] - div [ - _id "result" - _class [ "mt-4" ] - ] - ] - ] -``` - -## Complete HTML Document - -Here's how to create a complete HTML document: - -```fsharp -let completePage = - html [ - _lang "en" - _children [ - head [ - title [ _children "My Page" ] - meta [ _charset "utf-8" ] - meta [ _name "viewport"; _content "width=device-width, initial-scale=1" ] - link [ _rel "stylesheet"; _href "https://cdn.tailwindcss.com" ] - ] - body [ - _class [ "bg-gray-100"; "font-sans" ] - _children [ - div [ - _class [ "container"; "mx-auto"; "px-4"; "py-8" ] - _children [ - h1 [ - _class [ "text-3xl"; "font-bold"; "text-gray-900"; "mb-4" ] - _children "Welcome to my site!" - ] - p [ - _class [ "text-lg"; "text-gray-600" ] - _children "This is built with FSharp.ViewEngine." - ] - ] - ] - ] - ] - ] - ] -``` \ No newline at end of file diff --git a/fsharp-view-engine/src/FSharp.ViewEngine/Alpine.fs b/fsharp-view-engine/src/FSharp.ViewEngine/Alpine.fs deleted file mode 100644 index 57050e1..0000000 --- a/fsharp-view-engine/src/FSharp.ViewEngine/Alpine.fs +++ /dev/null @@ -1,38 +0,0 @@ -namespace FSharp.ViewEngine - -type Alpine = - static member _by(value:string) = KeyValue("by", value) - static member _x (key:string, ?value:string) = match value with Some v -> KeyValue ($"x-{key}", v) | None -> Boolean $"x-{key}" - static member _xOn (event:string, v:string) = KeyValue ($"x-on:{event}", v) - static member _xOn (event:string) = Boolean $"x-on:{event}" - static member _xInit (value:string) = KeyValue ("x-init", value) - static member _xData (value:string) = KeyValue ("x-data", value) - static member _xRef (value:string) = KeyValue ("x-ref", value) - static member _xText (value:string) = KeyValue ("x-text", value) - static member _xBind (attr:string, value:string) = KeyValue ($"x-bind:{attr}", value) - static member _xShow (value:string) = KeyValue ("x-show", value) - static member _xIf (value:string) = KeyValue ("x-if", value) - static member _xFor (value:string) = KeyValue ("x-for", value) - static member _xModel (value:string, ?modifier:string) = - match modifier with - | Some modifier -> KeyValue ($"x-model{modifier}", value) - | None -> KeyValue("x-model", value) - static member _xModelable (value:string) = KeyValue ("x-modelable", value) - static member _xId (value:string) = KeyValue ("x-id", value) - static member _xEffect (value:string) = KeyValue ("x-effect", value) - static member _xTransition (?value:string, ?modifier:string) = - match value, modifier with - | Some value, Some modifier -> KeyValue ($"x-transition{modifier}", value) - | Some value, None -> KeyValue ("x-transition", value) - | None, Some modifier -> Boolean $"x-transition{modifier}" - | None, None -> Boolean "x-transition" - static member _xTrap (value:string, ?modifier:string) = - match modifier with - | Some modifier -> KeyValue ($"x-trap{modifier}", value) - | None -> KeyValue ("x-trap", value) - static member _xCloak = Boolean "x-cloak" - static member _xAnchor (value:string, ?modifier:string) = - match modifier with - | Some m -> KeyValue ($"x-anchor{m}", value) - | None -> KeyValue ("x-anchor", value) - static member _xTeleport(value:string) = KeyValue("x-teleport", value) diff --git a/fsharp-view-engine/src/FSharp.ViewEngine/Core.fs b/fsharp-view-engine/src/FSharp.ViewEngine/Core.fs deleted file mode 100644 index 927e33a..0000000 --- a/fsharp-view-engine/src/FSharp.ViewEngine/Core.fs +++ /dev/null @@ -1,62 +0,0 @@ -namespace FSharp.ViewEngine - -type Attribute = - | KeyValue of string * string // e.g., div [ _class "text-xl" ] ->
- | Boolean of string // e.g., button [ _disabled ] -> - | Children of Element seq // e.g., div [ p "Hello" ] ->

Hello

- | Noop // No op - -and Element = - | Raw of string // Raw content - | Text of string // Text content (html encoded) - | Tag of string * Attribute seq // e.g.,

Hello

- | Void of string * Attribute seq // e.g.,
- | Fragment of Element seq // Directly render children - | Noop // No op - -module private ViewBuilder = - open System.Text - open System.Web - - let inline (+=) (sb:StringBuilder) (s:string) = sb.Append(s) - let inline (+!) (sb:StringBuilder) (s:string) = sb.Append(s) |> ignore - - let encode (s:string) = HttpUtility.HtmlEncode(s) - - let rec buildElement (el:Element) (sb:StringBuilder) = - match el with - | Raw text -> sb +! text - | Text text -> sb +! encode text - | Tag (tag, attributes) -> - sb += "<" +! tag - let children = ResizeArray() - for attr in attributes do - match attr with - | KeyValue (key, value) -> sb += " " += key += "=\"" += value +! "\"" - | Boolean key -> sb += " " +! key - | Children elements -> children.AddRange(elements) - | Attribute.Noop -> () - sb +! ">" - for child in children do buildElement child sb - sb += "" - | Void (tag, attributes) -> - sb += "<" +! tag - for attr in attributes do - match attr with - | KeyValue (key, value) -> sb += " " += key += "=\"" += value +! "\"" - | Boolean key -> sb += " " +! key - | Children _ -> failwith "void elements cannot have children" - | Attribute.Noop -> () - sb +! ">" - | Fragment children -> for child in children do buildElement child sb - | Element.Noop -> () - -[] -module Element = - open System.Text - open ViewBuilder - - let render (element:Element) = - let sb = StringBuilder() - buildElement element sb - sb.ToString() diff --git a/fsharp-view-engine/src/FSharp.ViewEngine/Html.fs b/fsharp-view-engine/src/FSharp.ViewEngine/Html.fs deleted file mode 100644 index 3fde1c8..0000000 --- a/fsharp-view-engine/src/FSharp.ViewEngine/Html.fs +++ /dev/null @@ -1,122 +0,0 @@ -namespace FSharp.ViewEngine -open JetBrains.Annotations - -type Html = - static member empty = Element.Noop - static member fragment (children:Element seq) = Fragment children - static member raw ([]v:string) = Raw v - static member text (v:string) = Text v - static member html (attrs:Attribute list) = Fragment [ Void ("!DOCTYPE", [ Boolean "html" ]); Tag ("html", attrs) ] - static member head (children:Element list) = Tag ("head", [ Children children ]) - static member title (value:string) = Tag ("title", [ Children [ Text value ] ]) - static member meta (attrs:Attribute seq) = Void ("meta", attrs) - static member link (attrs:Attribute seq) = Void ("link", attrs) - static member script (attrs:Attribute seq) = Tag ("script", attrs) - static member script (value:string) = Tag ("script", [ Children [ Raw value ]]) - static member body (attrs:Attribute seq) = Tag ("body", attrs) - static member main (attrs:Attribute seq) = Tag ("main", attrs) - static member header (attrs:Attribute seq) = Tag ("header", attrs) - static member footer (attrs:Attribute seq) = Tag ("footer", attrs) - static member nav (attrs:Attribute seq) = Tag ("nav", attrs) - static member h1 (attrs:Attribute seq) = Tag ("h1", attrs) - static member h2 (attrs:Attribute seq) = Tag ("h2", attrs) - static member h3 (attrs:Attribute seq) = Tag ("h3", attrs) - static member h4 (attrs:Attribute seq) = Tag ("h4", attrs) - static member div (attrs:Attribute seq) = Tag ("div", attrs) - static member div (children:Element seq) = Tag ("div", [ Children children ]) - static member p (attrs:Attribute seq) = Tag ("p", attrs) - static member p (text:string) = Tag ("p", [ Children [ Text text ] ]) - static member span (attrs:Attribute seq) = Tag ("span", attrs) - static member a (attrs:Attribute seq) = Tag ("a", attrs) - static member button (attrs:Attribute seq) = Tag ("button", attrs) - static member img (attrs:Attribute seq) = Tag ("img", attrs) - static member code (attrs:Attribute seq) = Tag ("code", attrs) - static member pre (attrs:Attribute seq) = Tag ("pre", attrs) - static member br = Void ("br", []) - static member ul (attrs:Attribute seq) = Tag ("ul", attrs) - static member ol (attrs:Attribute seq) = Tag ("ol", attrs) - static member li (attrs:Attribute seq) = Tag ("li", attrs) - static member blockquote (attrs:Attribute seq) = Tag ("blockquote", attrs) - static member article (attrs:Attribute seq) = Tag("article", attrs) - static member dialog (attrs:Attribute seq) = Tag("dialog", attrs) - static member time (attrs:Attribute seq) = Tag("time", attrs) - static member form (attrs:Attribute seq) = Tag("form", attrs) - static member input (attrs:Attribute seq) = Tag("input", attrs) - static member label (attrs:Attribute seq) = Tag("label", attrs) - static member textarea (attrs:Attribute seq) = Tag("textarea", attrs) - static member select (attrs:Attribute seq) = Tag("select", attrs) - static member option (attrs:Attribute seq) = Tag("option", attrs) - static member table (attrs:Attribute seq) = Tag("table", attrs) - static member thead (attrs:Attribute seq) = Tag("thead", attrs) - static member thead (children:Element seq) = Tag("thead", [ Children children ]) - static member tr (attrs:Attribute seq) = Tag("tr", attrs) - static member tr (children:Element seq) = Tag("tr", [ Children children ]) - static member th (attrs:Attribute seq) = Tag("th", attrs) - static member tbody (attrs:Attribute seq) = Tag("tbody", attrs) - static member td (attrs:Attribute seq) = Tag("td", attrs) - static member dl (attrs:Attribute seq) = Tag("dl", attrs) - static member dt (attrs:Attribute seq) = Tag("dt", attrs) - static member dd (attrs:Attribute seq) = Tag("dd", attrs) - static member template (attrs:Attribute seq) = Tag("template", attrs) - static member iframe (attrs:Attribute seq) = Tag ("iframe", attrs) - - static member _empty = Attribute.Noop - static member _id (v:string) = KeyValue ("id", v) - static member _class (v:string) = KeyValue ("class", v) - static member _class (v:string seq) = KeyValue ("class", v |> String.concat " ") - static member _style (v:string) = KeyValue ("style", v) - static member _children (v:Element seq) = Children v - static member _children (v:Element) = Children [ v ] - static member _children (v:string) = Children [ Text v ] - static member _lang (v:string) = KeyValue ("lang", v) - static member _charset (v:string) = KeyValue ("charset", v) - static member _name (v:string) = KeyValue ("name", v) - static member _content (v:string) = KeyValue ("content", v) - static member _href (v:string) = KeyValue ("href", v) - static member _rel (v:string) = KeyValue ("rel", v) - static member _src (v:string) = KeyValue ("src", v) - static member _async (v:bool) = if v then Boolean "async" else Attribute.Noop - static member _defer (v:bool) = if v then Boolean "defer" else Attribute.Noop - static member _action (v:string) = KeyValue("action", v) - static member _method (v:string) = KeyValue("method", v) - static member _formmethod (v:string) = KeyValue("formmethod", v) - static member _type (v:string) = KeyValue("type", v) - static member _for (v:string) = KeyValue("for", v) - static member _rows (v:int) = KeyValue("rows", string v) - static member _cols (v:int) = KeyValue("cols", string v) - static member _data (attr:string, ?v:string) = let key = $"data-{attr}" in match v with Some v -> KeyValue (key, v) | None -> Boolean(key) - static member _datetime (v:string) = KeyValue("datetime", v) - static member _width (v:string) = KeyValue("width", v) - static member _height (v:string) = KeyValue("height", v) - static member _value (v:string) = KeyValue("value", v) - static member _hidden (v:bool) = if v then Boolean("hidden") else Attribute.Noop - static member _required (v:bool) = if v then Boolean("required") else Attribute.Noop - static member _disabled (v:bool) = if v then Boolean("disabled") else Attribute.Noop - static member _readonly (v:bool) = if v then Boolean("readonly") else Attribute.Noop - static member _multiple (v:bool) = if v then Boolean("multiple") else Attribute.Noop - static member _selected (v:bool) = if v then Boolean("selected") else Attribute.Noop - static member _min (v:string) = KeyValue("min", v) - static member _min (v:float) = KeyValue("min", string v) - static member _minlength (v:string) = KeyValue("minlength", v) - static member _minlength (v:int) = KeyValue("minlength", string v) - static member _max (v:string) = KeyValue("max", v) - static member _max (v:float) = KeyValue("max", string v) - static member _maxlength (v:string) = KeyValue("maxlength", v) - static member _maxlength (v:int) = KeyValue("maxlength", string v) - static member _step (v:string) = KeyValue("step", v) - static member _step (v:float) = KeyValue("step", string v) - static member _checked (v:bool) = if v then Boolean("checked") else Attribute.Noop - static member _role (v:string) = KeyValue("role", v) - static member _ariaLabelledby (v:string) = KeyValue("aria-labelledby", v) - static member _ariaDescribedby (v:string) = KeyValue("aria-describedby", v) - static member _ariaModal (v:string) = KeyValue("aria-modal", v) - static member _placeholder value = KeyValue ("placeholder", value) - static member _autocomplete value = KeyValue ("autocomplete", value) - static member _pattern value = KeyValue ("pattern", value) - static member _accept value = KeyValue ("accept", value) - static member _title value = KeyValue ("title", value) - static member _wrap value = KeyValue ("wrap", value) - static member _size (value:int) = KeyValue ("size", string value) - static member _colspan (value:int) = KeyValue ("colspan", string value) - static member _onload(value:string) = KeyValue("onload", value) - static member _crossorigin = Boolean("crossorigin") diff --git a/fsharp-view-engine/src/FSharp.ViewEngine/Htmx.fs b/fsharp-view-engine/src/FSharp.ViewEngine/Htmx.fs deleted file mode 100644 index c8939b3..0000000 --- a/fsharp-view-engine/src/FSharp.ViewEngine/Htmx.fs +++ /dev/null @@ -1,17 +0,0 @@ -namespace FSharp.ViewEngine - -type Htmx = - static member _hx (key:string, value:string) = KeyValue ($"hx-{key}", value) - static member _hxGet (v:string) = KeyValue ("hx-get", v) - static member _hxPost (v:string) = KeyValue("hx-post", v) - static member _hxDelete (v:string) = KeyValue("hx-delete", v) - static member _hxTrigger (v:string) = KeyValue ("hx-trigger", v) - static member _hxTarget (v:string) = KeyValue ("hx-target", v) - static member _hxIndicator (v:string) = KeyValue ("hx-indicator", v) - static member _hxInclude (v:string) = KeyValue ("hx-include", v) - static member _hxSwap (v:string) = KeyValue ("hx-swap", v) - static member _hxSwapOOB (v:string) = KeyValue ("hx-swap-oob", v) - static member _hxEncoding (value:string) = KeyValue("hx-encoding", value) - static member _hxOn (event:string, value:string) = KeyValue($"hx-on:{event}", value) - static member _hxHistory (value:string) = KeyValue("hx-history", value) - static member _hxVals(value:string) = KeyValue ("hx-vals", value) diff --git a/fsharp-view-engine/src/FSharp.ViewEngine/Svg.fs b/fsharp-view-engine/src/FSharp.ViewEngine/Svg.fs deleted file mode 100644 index 0f0e914..0000000 --- a/fsharp-view-engine/src/FSharp.ViewEngine/Svg.fs +++ /dev/null @@ -1,22 +0,0 @@ -namespace FSharp.ViewEngine - -type Svg = - static member svg (attrs:Attribute seq) = Tag ("svg", attrs) - static member path (attrs:Attribute seq) = Tag ("path", attrs) - static member circle (attrs:Attribute seq) = Tag ("circle", attrs) - - static member _viewBox (v:string) = KeyValue ("viewBox", v) - static member _width (v:int) = KeyValue ("width", string v) - static member _height (v:int) = KeyValue ("height", string v) - static member _fill (v:string) = KeyValue ("fill", v) - static member _stroke (v:string) = KeyValue ("stroke", v) - static member _strokeWidth (v:int) = KeyValue ("stroke-width", string v) - static member _strokeLinecap (v:string) = KeyValue ("stroke-linecap", v) - static member _strokeLinejoin (v:string) = KeyValue ("stroke-linejoin", v) - static member _fillRule (v:string) = KeyValue ("fill-rule", v) - static member _clipRule (v:string) = KeyValue ("clip-rule", v) - static member _d (v:string) = KeyValue ("d", v) - static member _cx (v:int) = KeyValue ("cx", string v) - static member _cy (v:int) = KeyValue ("cy", string v) - static member _r (v:int) = KeyValue ("r", string v) - diff --git a/fsharp-view-engine/src/FSharp.ViewEngine/Tailwind.fs b/fsharp-view-engine/src/FSharp.ViewEngine/Tailwind.fs deleted file mode 100644 index c9b9d5d..0000000 --- a/fsharp-view-engine/src/FSharp.ViewEngine/Tailwind.fs +++ /dev/null @@ -1,24 +0,0 @@ -namespace FSharp.ViewEngine - -type Tailwind = - static member _popover = Boolean "popover" - static member _anchor (position:string) = KeyValue ("anchor", position) - static member elAutocomplete (attrs:Attribute seq) = Tag ("el-autocomplete", attrs) - static member elOptions (attrs:Attribute seq) = Tag ("el-options", attrs) - static member elOption (attrs:Attribute seq) = Tag ("el-option", attrs) - static member elSelect (attrs:Attribute seq) = Tag ("el-select", attrs) - static member elSelectedContent (attrs:Attribute seq) = Tag ("el-selectedcontent", attrs) - static member elDropdown (attrs:Attribute seq) = Tag ("el-dropdown", attrs) - static member elMenu (attrs:Attribute seq) = Tag ("el-menu", attrs) - static member elDialog (attrs:Attribute seq) = Tag ("el-dialog", attrs) - static member elDialogBackdrop (attrs:Attribute seq) = Tag ("el-dialog-backdrop", attrs) - static member elDialogPanel (attrs:Attribute seq) = Tag ("el-dialog-panel", attrs) - static member elCommandPalette (attrs:Attribute seq) = Tag ("el-command-palette", attrs) - static member elCommandList (attrs:Attribute seq) = Tag ("el-command-list", attrs) - static member elCommandGroup (attrs:Attribute seq) = Tag ("el-command-group", attrs) - static member elCommandPreview (attrs:Attribute seq) = Tag ("el-command-preview", attrs) - static member elDefaults (attrs:Attribute seq) = Tag ("el-defaults", attrs) - static member elNoResults (attrs:Attribute seq) = Tag ("el-no-results", attrs) - static member elTabGroup (attrs:Attribute seq) = Tag ("el-tab-group", attrs) - static member elTabList (attrs:Attribute seq) = Tag ("el-tab-list", attrs) - static member elTabPanels (attrs:Attribute seq) = Tag ("el-tab-panels", attrs) diff --git a/fsharp-view-engine/src/Tests/Tests.fs b/fsharp-view-engine/src/Tests/Tests.fs deleted file mode 100644 index 3de527b..0000000 --- a/fsharp-view-engine/src/Tests/Tests.fs +++ /dev/null @@ -1,165 +0,0 @@ -module Tests - -open FSharp.ViewEngine -open System.Text.Json -open System.Text.RegularExpressions -open Expecto -open type Html -open type Htmx -open type Alpine -open type Svg -open type Tailwind - -module String = - let replace (oldValue:string) (newValue:string) (s:string) = s.Replace(oldValue, newValue) - let clean (s:string) = Regex.Replace(s, @"\s{2,}|\r|\n|\r\n", "") - -[] -let tests = - testList "ViewEngine Tests" [ - test "Should render html document" { - let actual = - let xData = - {| showContent = false; x = [ 1; 2; 3 ]; y = [ "a"; "b"; "c" ] |} - |> JsonSerializer.Serialize - |> String.replace "\"" "'" - html [ - _lang "en" - _children [ - head [ - title "Test" - meta [ _charset "utf-8" ] - link [ _href "/css/compiled.css"; _rel "stylesheet" ] - ] - body [ - _xData xData - _class "bg-gray-50" - _children [ - div [ - _id "page" - _class [ "flex"; "flex-col" ] - _children [ - h1 [ _hxGet "/hello"; _hxTarget "#page"; _children "Hello" ] - h1 [ _hxGet "/world"; _hxTarget "#page"; _children "World" ] - ] - ] - br - div [ - _xShow "showContent" - _children [ - h2 [ _children "Content" ] - p [ _children "Some content" ] - raw "

Some more content

" - pre [ - _class "language-html" - _children [ - code [ - _class "language-html" - _children [ - text "

Even more content

" - ] - ] - ] - ] - ul [ - _children [ - li [ _children "One" ] - li [ _children "Two" ] - ] - ] - a [ - _href "https://github.com/meiermade/FSharp.ViewEngine" - _class "rounded-lg text-gray-800 font-semibold flex items-center gap-3 p-1" - _children [ - svg [ - _viewBox "0 0 24 24" - _class "h-6 w-6 fill-current" - _children [ - path [ - _fillRule "evenodd" - _clipRule "evenodd" - _d "M12 2C6.477 2 2 6.463 2 11.97c0 4.404 2.865 8.14 6.839 9.458.5.092.682-.216.682-.48 0-.236-.008-.864-.013-1.695-2.782.602-3.369-1.337-3.369-1.337-.454-1.151-1.11-1.458-1.11-1.458-.908-.618.069-.606.069-.606 1.003.07 1.531 1.027 1.531 1.027.892 1.524 2.341 1.084 2.91.828.092-.643.35-1.083.636-1.332-2.22-.251-4.555-1.107-4.555-4.927 0-1.088.39-1.979 1.029-2.675-.103-.252-.446-1.266.098-2.638 0 0 .84-.268 2.75 1.022A9.607 9.607 0 0 1 12 6.82c.85.004 1.705.114 2.504.336 1.909-1.29 2.747-1.022 2.747-1.022.546 1.372.202 2.386.1 2.638.64.696 1.028 1.587 1.028 2.675 0 3.83-2.339 4.673-4.566 4.92.359.307.678.915.678 1.846 0 1.332-.012 2.407-.012 2.734 0 .267.18.577.688.48 3.97-1.32 6.833-5.054 6.833-9.458C22 6.463 17.522 2 12 2Z" - ] - ] - ] - raw "Documentation" - ] - ] - elSelect [ - _name "status" - _value "active" - _children [ - button [ - _type "button" - _children [ - elSelectedContent [ _children "Active" ] - ] - ] - elOptions [ - _popover - _children [ - elOption [ _value "active"; _children "Active" ] - elOption [ _value "inactive"; _children "Inactive" ] - elOption [ _value "archived"; _children "Archived" ] - ] - ] - ] - ] - ] - ] - ] - ] - ] - ] - |> Element.render - // language=HTML - let expected = """ - - - - Test - - - - -
-

Hello

-

World

-
-
-
- - - """ - Expect.equal (String.clean actual) (String.clean expected) "Rendered HTML should match expected" - } - ] diff --git a/lib/.config/dotnet-tools.json b/lib/.config/dotnet-tools.json new file mode 100644 index 0000000..4321530 --- /dev/null +++ b/lib/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "paket": { + "version": "10.3.1", + "commands": [ + "paket" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/fsharp-view-engine/.gitignore b/lib/.gitignore similarity index 100% rename from fsharp-view-engine/.gitignore rename to lib/.gitignore diff --git a/fsharp-view-engine/LICENSE b/lib/LICENSE similarity index 100% rename from fsharp-view-engine/LICENSE rename to lib/LICENSE diff --git a/lib/fake.cmd b/lib/fake.cmd new file mode 100644 index 0000000..df4b954 --- /dev/null +++ b/lib/fake.cmd @@ -0,0 +1 @@ +dotnet run --project ./src/Build/Build.fsproj -- --target %1 diff --git a/lib/fake.sh b/lib/fake.sh new file mode 100644 index 0000000..d25bbc3 --- /dev/null +++ b/lib/fake.sh @@ -0,0 +1 @@ +dotnet run --project ./src/Build/Build.fsproj -- --target $1 diff --git a/fsharp-view-engine/global.json b/lib/global.json similarity index 100% rename from fsharp-view-engine/global.json rename to lib/global.json diff --git a/lib/paket.dependencies b/lib/paket.dependencies new file mode 100644 index 0000000..7fe6d97 --- /dev/null +++ b/lib/paket.dependencies @@ -0,0 +1,13 @@ +source https://api.nuget.org/v3/index.json +storage: none + +nuget Fake.Core.Target +nuget Giraffe +nuget JetBrains.Annotations +nuget Markdig +nuget Expecto +nuget BenchmarkDotNet 0.14.0 +nuget FSharp.Core +nuget Giraffe.ViewEngine +nuget Feliz.ViewEngine +nuget Oxpecker.ViewEngine diff --git a/lib/paket.lock b/lib/paket.lock new file mode 100644 index 0000000..d8bbd0e --- /dev/null +++ b/lib/paket.lock @@ -0,0 +1,209 @@ +STORAGE: NONE +NUGET + remote: https://api.nuget.org/v3/index.json + BenchmarkDotNet (0.14) + BenchmarkDotNet.Annotations (>= 0.14) - restriction: >= netstandard2.0 + CommandLineParser (>= 2.9.1) - restriction: >= netstandard2.0 + Gee.External.Capstone (>= 2.3) - restriction: >= netstandard2.0 + Iced (>= 1.17) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.CSharp (>= 4.1) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Runtime (>= 2.2.332302) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Tracing.TraceEvent (>= 3.1.8) - restriction: >= netstandard2.0 + Microsoft.DotNet.PlatformAbstractions (>= 3.1.6) - restriction: >= netstandard2.0 + Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net6.0) (>= netstandard2.0) + Perfolizer (0.3.17) - restriction: >= netstandard2.0 + System.Management (>= 5.0) - restriction: >= netstandard2.0 + System.Numerics.Vectors (>= 4.5) - restriction: && (< net6.0) (>= netstandard2.0) + System.Reflection.Emit (>= 4.7) - restriction: && (< net6.0) (>= netstandard2.0) + System.Reflection.Emit.Lightweight (>= 4.7) - restriction: && (< net6.0) (>= netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: && (< net6.0) (>= netstandard2.0) + BenchmarkDotNet.Annotations (0.15.8) - restriction: >= netstandard2.0 + CommandLineParser (2.9.1) - restriction: >= netstandard2.0 + Expecto (10.2.3) + FSharp.Core (>= 7.0.200) - restriction: >= net6.0 + Mono.Cecil (>= 0.11.4 < 1.0) - restriction: >= net6.0 + Fake.Core.CommandLineParsing (6.1.4) - restriction: >= netstandard2.0 + FParsec (>= 1.1.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + Fake.Core.Context (6.1.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + Fake.Core.Environment (6.1.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + Fake.Core.FakeVar (6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Context (>= 6.1.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + Fake.Core.Process (6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Environment (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.FakeVar (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 6.1.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 8.0) - restriction: >= netstandard2.0 + Fake.Core.String (6.1.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + Fake.Core.Target (6.1.4) + Fake.Core.CommandLineParsing (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Context (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Environment (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.FakeVar (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Process (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 6.1.4) - restriction: >= netstandard2.0 + FSharp.Control.Reactive (>= 5.0.2) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + Fake.Core.Trace (6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Environment (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.FakeVar (>= 6.1.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (6.1.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 6.1.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 6.1.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 8.0.400) - restriction: >= netstandard2.0 + Feliz.ViewEngine (1.0.3) + FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 + FParsec (1.1.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.3.4) - restriction: || (>= net45) (>= netstandard2.0) + System.ValueTuple (>= 4.4) - restriction: >= net45 + FSharp.Control.Reactive (6.1.2) - restriction: >= netstandard2.0 + FSharp.Core (>= 6.0.7) - restriction: >= netstandard2.0 + System.Reactive (>= 6.0.1) - restriction: >= netstandard2.0 + FSharp.Core (10.0.102) + FSharp.SystemTextJson (1.4.36) - restriction: >= net6.0 + FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 + System.Text.Json (>= 6.0.10) - restriction: >= netstandard2.0 + Gee.External.Capstone (2.3) - restriction: >= netstandard2.0 + Giraffe (8.2) + FSharp.Core (>= 6.0) - restriction: >= net6.0 + FSharp.SystemTextJson (>= 1.3.13) - restriction: >= net6.0 + Giraffe.ViewEngine (>= 1.4) - restriction: >= net6.0 + Microsoft.IO.RecyclableMemoryStream (>= 3.0.1) - restriction: >= net6.0 + System.Text.Json (>= 8.0.6) - restriction: >= net6.0 + Giraffe.ViewEngine (1.4) + FSharp.Core (>= 5.0) - restriction: >= netstandard2.0 + Iced (1.21) - restriction: >= netstandard2.0 + JetBrains.Annotations (2025.2.4) + System.Runtime (>= 4.1) - restriction: && (< net20) (>= netstandard1.0) (< netstandard2.0) + Markdig (0.44) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Bcl.AsyncInterfaces (10.0.2) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net6.0) (< net8.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.CodeAnalysis.Analyzers (3.11) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Common (5.0) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Analyzers (>= 3.11) - restriction: >= netstandard2.0 + System.Buffers (>= 4.6) - restriction: && (< net8.0) (>= netstandard2.0) + System.Collections.Immutable (>= 9.0) - restriction: || (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6) - restriction: && (< net8.0) (>= netstandard2.0) + System.Numerics.Vectors (>= 4.6) - restriction: && (< net8.0) (>= netstandard2.0) + System.Reflection.Metadata (>= 9.0) - restriction: || (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.1) - restriction: && (< net8.0) (>= netstandard2.0) + System.Text.Encoding.CodePages (>= 8.0) - restriction: && (< net8.0) (>= netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.6) - restriction: && (< net8.0) (>= netstandard2.0) + Microsoft.CodeAnalysis.CSharp (5.0) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Analyzers (>= 3.11) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Common (5.0) - restriction: >= netstandard2.0 + System.Buffers (>= 4.6) - restriction: && (< net8.0) (>= netstandard2.0) + System.Collections.Immutable (>= 9.0) - restriction: || (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6) - restriction: && (< net8.0) (>= netstandard2.0) + System.Numerics.Vectors (>= 4.6) - restriction: && (< net8.0) (>= netstandard2.0) + System.Reflection.Metadata (>= 9.0) - restriction: || (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.1) - restriction: && (< net8.0) (>= netstandard2.0) + System.Text.Encoding.CodePages (>= 8.0) - restriction: && (< net8.0) (>= netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.6) - restriction: && (< net8.0) (>= netstandard2.0) + Microsoft.Diagnostics.NETCore.Client (0.2.661903) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (>= 9.0.8) - restriction: && (< net8.0) (>= netstandard2.0) + Microsoft.Extensions.Logging.Abstractions (>= 8.0.3) - restriction: >= netstandard2.0 + System.Buffers (>= 4.5.1) - restriction: && (< net8.0) (>= netstandard2.0) + Microsoft.Diagnostics.Runtime (3.1.512801) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (>= 0.2.410101) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 6.0) - restriction: && (< net6.0) (>= netstandard2.0) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: && (< net6.0) (>= netstandard2.0) + Microsoft.Diagnostics.Tracing.TraceEvent (3.1.29) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (>= 0.2.510501) - restriction: >= netstandard2.0 + Microsoft.Win32.Registry (>= 5.0) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 9.0.8) - restriction: >= netstandard2.0 + System.Reflection.Metadata (>= 9.0.8) - restriction: >= netstandard2.0 + System.Reflection.TypeExtensions (>= 4.7) - restriction: >= netstandard2.0 + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: >= netstandard2.0 + System.Text.Json (>= 9.0.8) - restriction: >= netstandard2.0 + Microsoft.DotNet.PlatformAbstractions (3.1.6) - restriction: >= netstandard2.0 + System.Runtime.InteropServices.RuntimeInformation (>= 4.0) - restriction: || (>= net45) (&& (>= netstandard1.3) (< netstandard2.0)) + Microsoft.Extensions.DependencyInjection.Abstractions (10.0.2) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (>= 10.0.2) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Extensions.Logging.Abstractions (10.0.2) - restriction: >= netstandard2.0 + Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Diagnostics.DiagnosticSource (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + Microsoft.Extensions.ObjectPool (10.0.2) - restriction: >= net10.0 + Microsoft.IO.RecyclableMemoryStream (3.0.1) - restriction: >= net6.0 + Microsoft.NETCore.Platforms (7.0.4) - restriction: || (&& (>= monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (>= monoandroid) (>= netcoreapp2.1) (< netstandard1.3)) (&& (< monoandroid) (< net20) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net20) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net20) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= monotouch) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (< monotouch) (< net20) (>= netstandard1.5) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netcoreapp2.0)) (&& (>= net461) (>= netcoreapp2.1)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinios)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinmac)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarintvos)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinwatchos)) (&& (>= netcoreapp2.0) (>= uap10.1)) (&& (< netcoreapp2.0) (>= netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) (&& (>= netcoreapp2.1) (>= uap10.1)) + Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (< net20) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net20) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net20) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net20) (>= netstandard1.5) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) + Microsoft.Win32.Registry (5.0) - restriction: >= netstandard2.0 + System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= uap10.1) + System.Security.AccessControl (>= 5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + Mono.Cecil (0.11.6) - restriction: >= net6.0 + Oxpecker.ViewEngine (2.0) + FSharp.Core (>= 10.0.100) - restriction: >= net10.0 + Microsoft.Extensions.ObjectPool (>= 10.0) - restriction: >= net10.0 + Perfolizer (0.3.17) - restriction: >= netstandard2.0 + System.Memory (>= 4.5.5) - restriction: && (>= netstandard2.0) (< netstandard2.1) + System.Buffers (4.6.1) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net462) (&& (>= net6.0) (< net8.0)) (&& (< net6.0) (>= netstandard2.0) (>= xamarintvos)) (&& (< net6.0) (>= netstandard2.0) (>= xamarinwatchos)) (&& (< net6.0) (>= xamarinios)) (&& (< net6.0) (>= xamarinmac)) (&& (< net8.0) (>= netstandard2.0)) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + System.CodeDom (10.0.2) - restriction: >= netstandard2.0 + System.Collections.Immutable (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net8.0) (< net9.0)) (>= netstandard2.0) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Diagnostics.DiagnosticSource (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.IO.Pipelines (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net462) (>= net6.0)) (&& (>= net6.0) (< net8.0)) (&& (>= net8.0) (< net9.0)) + System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Management (10.0.2) - restriction: >= netstandard2.0 + System.CodeDom (>= 10.0.2) - restriction: >= netstandard2.0 + System.Memory (4.6.3) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net462) (&& (>= net6.0) (< net8.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (< netstandard2.1)) (&& (>= netstandard2.0) (>= uap10.1)) + System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + System.Numerics.Vectors (>= 4.6.1) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + System.Numerics.Vectors (4.6.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + System.Reactive (6.1) - restriction: >= netstandard2.0 + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net472) (&& (< net6.0) (>= netstandard2.0)) (>= uap10.1) + System.Reflection.Emit (4.7) - restriction: && (< net6.0) (>= netstandard2.0) + System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= uap10.1) + System.Reflection.Emit.ILGeneration (4.7) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netstandard1.1) (>= netstandard2.0) (< win8)) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= uap10.1)) + System.Reflection.Emit.Lightweight (4.7) - restriction: && (< net6.0) (>= netstandard2.0) + System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (< netstandard2.0) (>= wpa81)) (&& (>= portable-net45+win8+wp8+wpa81) (< portable-net45+wp8) (< win8)) (&& (< portable-net45+wp8) (>= win8)) (>= uap10.1) + System.Reflection.Metadata (10.0.2) - restriction: || (&& (>= net8.0) (< net9.0)) (>= netstandard2.0) + System.Collections.Immutable (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Reflection.TypeExtensions (4.7) - restriction: >= netstandard2.0 + System.Runtime (4.3.1) - restriction: && (< net20) (>= netstandard1.0) (< netstandard2.0) + Microsoft.NETCore.Platforms (>= 1.1.1) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Targets (>= 1.1.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + System.Runtime.CompilerServices.Unsafe (6.1.2) - restriction: || (>= net462) (&& (>= net6.0) (< net8.0)) (>= netstandard2.0) + System.Runtime.InteropServices.RuntimeInformation (4.3) - restriction: && (>= net45) (>= netstandard2.0) + System.Security.AccessControl (6.0.1) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< net6.0) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.0)) (&& (< net6.0) (>= netcoreapp2.1)) (&& (< net6.0) (>= netstandard2.0) (>= xamarintvos)) (&& (< net6.0) (>= netstandard2.0) (>= xamarinwatchos)) (&& (< net6.0) (>= xamarinios)) (&& (< net6.0) (>= xamarinmac)) (&& (>= netstandard2.0) (>= uap10.1)) + System.Security.Principal.Windows (>= 5.0) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) + System.Security.Principal.Windows (5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< net6.0) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.0)) (&& (< net6.0) (>= netcoreapp2.1)) (&& (< net6.0) (>= netstandard2.0) (>= xamarintvos)) (&& (< net6.0) (>= netstandard2.0) (>= xamarinwatchos)) (&& (< net6.0) (>= xamarinios)) (&& (< net6.0) (>= xamarinmac)) (&& (>= netstandard2.0) (>= uap10.1)) + Microsoft.NETCore.Platforms (>= 5.0) - restriction: || (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) + System.Text.Encoding.CodePages (10.0.2) - restriction: && (< net8.0) (>= netstandard2.0) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.ValueTuple (>= 4.6.1) - restriction: >= net462 + System.Text.Encodings.Web (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net462) (>= net6.0)) (&& (>= net6.0) (< net8.0)) (&& (>= net8.0) (< net9.0)) + System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Text.Json (10.0.2) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (>= 10.0.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.IO.Pipelines (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Text.Encodings.Web (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Threading.Tasks.Extensions (4.6.3) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net6.0) (< net8.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (< netstandard2.1)) + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + System.ValueTuple (4.6.1) - restriction: && (>= net462) (>= netstandard2.0) diff --git a/lib/src/Benchmarks/Benchmarks.fs b/lib/src/Benchmarks/Benchmarks.fs new file mode 100644 index 0000000..09c8f03 --- /dev/null +++ b/lib/src/Benchmarks/Benchmarks.fs @@ -0,0 +1,472 @@ +module Benchmarks +open BenchmarkDotNet.Attributes +open BenchmarkDotNet.Configs +open BenchmarkDotNet.Jobs +open BenchmarkDotNet.Running +open BenchmarkDotNet.Toolchains.InProcess.NoEmit + +module ViewEngineApi = + open FSharp.ViewEngine + open type Html + + let buildDocument () = + html { + _lang "en" + head { + meta { _charset "utf-8" } + meta { _name "viewport"; _content "width=device-width, initial-scale=1" } + title "Benchmark" + link { _href "/css/site.css"; _rel "stylesheet" } + } + body { + _class "page" + header { + _class "site-header" + h1 { "Benchmark Page" } + nav { + ul { + li { a { _href "/"; "Home" } } + li { a { _href "/docs"; "Docs" } } + li { a { _href "/about"; "About" } } + } + } + } + main { + section { + _id "intro" + h2 { "Intro" } + p { "This is a simple benchmark document." } + p { "It includes common HTML elements." } + pre { + code { _class "language-html"; text "

Hello

" } + } + } + article { + h3 { "Highlights" } + ul { + li { "Lists" } + li { "Forms" } + li { "Tables" } + } + p { + text "Some inline " + raw "bold" + text " text." + } + } + form { + _id "signup" + _class "form" + label { _for "email"; "Email" } + input { _id "email"; _name "email"; _type "email"; _placeholder "name@example.com" } + label { _for "plan"; "Plan" } + select { + _id "plan" + _name "plan" + option { _value "free"; "Free" } + option { _value "pro"; "Pro" } + option { _value "team"; "Team" } + } + label { + _for "terms" + input { _id "terms"; _type "checkbox"; _checked true } + text " Accept terms" + } + button { _type "submit"; "Submit" } + } + table { + _class "data" + thead { + tr { + th { "Name" } + th { "Value" } + } + } + tbody { + tr { td { "Alpha" }; td { "1" } } + tr { td { "Beta" }; td { "2" } } + tr { td { "Gamma" }; td { "3" } } + } + } + } + footer { + _class "site-footer" + small { "© 2026 Example Co." } + a { _href "/privacy"; "Privacy" } + } + } + } + +module OxpeckerApi = + open Oxpecker.ViewEngine + + let buildDocument () = + html().attr("lang", "en") { + head() { + meta().attr("charset", "utf-8") + meta().attr("name", "viewport").attr("content", "width=device-width, initial-scale=1") + title() { "Benchmark" } + link().attr("href", "/css/site.css").attr("rel", "stylesheet") + } + body().attr("class", "page") { + header().attr("class", "site-header") { + h1() { "Benchmark Page" } + nav() { + ul() { + li() { a().attr("href", "/") { "Home" } } + li() { a().attr("href", "/docs") { "Docs" } } + li() { a().attr("href", "/about") { "About" } } + } + } + } + main() { + section().attr("id", "intro") { + h2() { "Intro" } + p() { "This is a simple benchmark document." } + p() { "It includes common HTML elements." } + pre() { + code().attr("class", "language-html") { "

Hello

" } + } + } + article() { + h3() { "Highlights" } + ul() { + li() { "Lists" } + li() { "Forms" } + li() { "Tables" } + } + p() { + "Some inline " + raw "bold" + " text." + } + } + form().attr("id", "signup").attr("class", "form") { + label().attr("for", "email") { "Email" } + input() + .attr("id", "email") + .attr("name", "email") + .attr("type", "email") + .attr("placeholder", "name@example.com") + label().attr("for", "plan") { "Plan" } + select().attr("id", "plan").attr("name", "plan") { + option().attr("value", "free") { "Free" } + option().attr("value", "pro") { "Pro" } + option().attr("value", "team") { "Team" } + } + label().attr("for", "terms") { + input().attr("id", "terms").attr("type", "checkbox").bool("checked", true) + " Accept terms" + } + button().attr("type", "submit") { "Submit" } + } + table().attr("class", "data") { + thead() { + tr() { + th() { "Name" } + th() { "Value" } + } + } + tbody() { + tr() { td() { "Alpha" }; td() { "1" } } + tr() { td() { "Beta" }; td() { "2" } } + tr() { td() { "Gamma" }; td() { "3" } } + } + } + } + footer().attr("class", "site-footer") { + small() { "© 2026 Example Co." } + a().attr("href", "/privacy") { "Privacy" } + } + } + } + +module GiraffeApi = + open Giraffe.ViewEngine + open Giraffe.ViewEngine.HtmlElements + open Giraffe.ViewEngine.Attributes + + let buildDocument () = + html [ _lang "en" ] [ + head [] [ + meta [ _charset "utf-8" ] + meta [ _name "viewport"; _content "width=device-width, initial-scale=1" ] + title [] [ str "Benchmark" ] + link [ _href "/css/site.css"; _rel "stylesheet" ] + ] + body [ _class "page" ] [ + header [ _class "site-header" ] [ + h1 [] [ str "Benchmark Page" ] + nav [] [ + ul [] [ + li [] [ a [ _href "/" ] [ str "Home" ] ] + li [] [ a [ _href "/docs" ] [ str "Docs" ] ] + li [] [ a [ _href "/about" ] [ str "About" ] ] + ] + ] + ] + main [] [ + section [ _id "intro" ] [ + h2 [] [ str "Intro" ] + p [] [ str "This is a simple benchmark document." ] + p [] [ str "It includes common HTML elements." ] + pre [] [ + code [ _class "language-html" ] [ str "

Hello

" ] + ] + ] + article [] [ + h3 [] [ str "Highlights" ] + ul [] [ + li [] [ str "Lists" ] + li [] [ str "Forms" ] + li [] [ str "Tables" ] + ] + p [] [ + str "Some inline " + rawText "bold" + str " text." + ] + ] + form [ _id "signup"; _class "form" ] [ + label [ _for "email" ] [ str "Email" ] + input [ _id "email"; _name "email"; _type "email"; _placeholder "name@example.com" ] + label [ _for "plan" ] [ str "Plan" ] + select [ _id "plan"; _name "plan" ] [ + option [ _value "free" ] [ str "Free" ] + option [ _value "pro" ] [ str "Pro" ] + option [ _value "team" ] [ str "Team" ] + ] + label [ _for "terms" ] [ + input [ _id "terms"; _type "checkbox"; _checked ] + str " Accept terms" + ] + button [ _type "submit" ] [ str "Submit" ] + ] + table [ _class "data" ] [ + thead [] [ + tr [] [ + th [] [ str "Name" ] + th [] [ str "Value" ] + ] + ] + tbody [] [ + tr [] [ td [] [ str "Alpha" ]; td [] [ str "1" ] ] + tr [] [ td [] [ str "Beta" ]; td [] [ str "2" ] ] + tr [] [ td [] [ str "Gamma" ]; td [] [ str "3" ] ] + ] + ] + ] + footer [ _class "site-footer" ] [ + small [] [ str "© 2026 Example Co." ] + a [ _href "/privacy" ] [ str "Privacy" ] + ] + ] + ] + +module FelizApi = + open Feliz.ViewEngine + + let buildDocument () = + Html.html [ + prop.lang "en" + prop.children [ + Html.head [ + prop.children [ + Html.meta [ prop.charset "utf-8" ] + Html.meta [ prop.name "viewport"; prop.content "width=device-width, initial-scale=1" ] + Html.title "Benchmark" + Html.link [ prop.href "/css/site.css"; prop.rel "stylesheet" ] + ] + ] + Html.body [ + prop.className "page" + prop.children [ + Html.header [ + prop.className "site-header" + prop.children [ + Html.h1 [ prop.children [ Html.text "Benchmark Page" ] ] + Html.nav [ + prop.children [ + Html.ul [ + prop.children [ + Html.li [ prop.children [ Html.a [ prop.href "/"; prop.children [ Html.text "Home" ] ] ] ] + Html.li [ prop.children [ Html.a [ prop.href "/docs"; prop.children [ Html.text "Docs" ] ] ] ] + Html.li [ prop.children [ Html.a [ prop.href "/about"; prop.children [ Html.text "About" ] ] ] ] + ] + ] + ] + ] + ] + ] + Html.main [ + prop.children [ + Html.section [ + prop.id "intro" + prop.children [ + Html.h2 [ prop.children [ Html.text "Intro" ] ] + Html.p [ prop.children [ Html.text "This is a simple benchmark document." ] ] + Html.p [ prop.children [ Html.text "It includes common HTML elements." ] ] + Html.pre [ + prop.children [ + Html.code [ prop.className "language-html"; prop.children [ Html.text "

Hello

" ] ] + ] + ] + ] + ] + Html.article [ + prop.children [ + Html.h3 [ prop.children [ Html.text "Highlights" ] ] + Html.ul [ + prop.children [ + Html.li [ prop.children [ Html.text "Lists" ] ] + Html.li [ prop.children [ Html.text "Forms" ] ] + Html.li [ prop.children [ Html.text "Tables" ] ] + ] + ] + Html.p [ + prop.children [ + Html.text "Some inline " + Html.rawText "bold" + Html.text " text." + ] + ] + ] + ] + Html.form [ + prop.id "signup" + prop.className "form" + prop.children [ + Html.label [ prop.htmlFor "email"; prop.children [ Html.text "Email" ] ] + Html.input [ + prop.id "email" + prop.name "email" + prop.type' "email" + prop.placeholder "name@example.com" + ] + Html.label [ prop.htmlFor "plan"; prop.children [ Html.text "Plan" ] ] + Html.select [ + prop.id "plan" + prop.name "plan" + prop.children [ + Html.option [ prop.value "free"; prop.children [ Html.text "Free" ] ] + Html.option [ prop.value "pro"; prop.children [ Html.text "Pro" ] ] + Html.option [ prop.value "team"; prop.children [ Html.text "Team" ] ] + ] + ] + Html.label [ + prop.htmlFor "terms" + prop.children [ + Html.input [ prop.id "terms"; prop.type' "checkbox"; prop.isChecked true ] + Html.text " Accept terms" + ] + ] + Html.button [ prop.type' "submit"; prop.children [ Html.text "Submit" ] ] + ] + ] + Html.table [ + prop.className "data" + prop.children [ + Html.thead [ + prop.children [ + Html.tr [ + prop.children [ + Html.th [ prop.children [ Html.text "Name" ] ] + Html.th [ prop.children [ Html.text "Value" ] ] + ] + ] + ] + ] + Html.tbody [ + prop.children [ + Html.tr [ prop.children [ Html.td [ prop.children [ Html.text "Alpha" ] ]; Html.td [ prop.children [ Html.text "1" ] ] ] ] + Html.tr [ prop.children [ Html.td [ prop.children [ Html.text "Beta" ] ]; Html.td [ prop.children [ Html.text "2" ] ] ] ] + Html.tr [ prop.children [ Html.td [ prop.children [ Html.text "Gamma" ] ]; Html.td [ prop.children [ Html.text "3" ] ] ] ] + ] + ] + ] + ] + ] + ] + Html.footer [ + prop.className "site-footer" + prop.children [ + Html.small [ prop.children [ Html.text "© 2026 Example Co." ] ] + Html.a [ prop.href "/privacy"; prop.children [ Html.text "Privacy" ] ] + ] + ] + ] + ] + ] + ] +[] +type BuildAndRender() = + + [] + member _.ViewEngineApi() = + ViewEngineApi.buildDocument() |> FSharp.ViewEngine.Render.toHtmlDocString + + [] + member _.OxpeckerApi() = + OxpeckerApi.buildDocument() |> Oxpecker.ViewEngine.Render.toHtmlDocString + + [] + member _.GiraffeApi() = + GiraffeApi.buildDocument() |> Giraffe.ViewEngine.RenderView.AsString.htmlDocument + + [] + member _.FelizApi() = + FelizApi.buildDocument() |> Feliz.ViewEngine.Render.htmlDocument + +[] +type RenderOnly() = + let viewDoc = ViewEngineApi.buildDocument() + let oxDoc = OxpeckerApi.buildDocument() + let giraffeDoc = GiraffeApi.buildDocument() + let felizDoc = FelizApi.buildDocument() + + [] + member _.ViewEngineApi() = + viewDoc |> FSharp.ViewEngine.Render.toHtmlDocString + + [] + member _.OxpeckerApi() = + oxDoc |> Oxpecker.ViewEngine.Render.toHtmlDocString + + [] + member _.GiraffeApi() = + giraffeDoc |> Giraffe.ViewEngine.RenderView.AsString.htmlDocument + + [] + member _.FelizApi() = + felizDoc |> Feliz.ViewEngine.Render.htmlDocument + +[] +type BuildOnly() = + + [] + member _.ViewEngineApi() = + ViewEngineApi.buildDocument() + + [] + member _.OxpeckerApi() = + OxpeckerApi.buildDocument() + + [] + member _.GiraffeApi() = + GiraffeApi.buildDocument() + + [] + member _.FelizApi() = + FelizApi.buildDocument() + +let runBenchmarks () = + let medJob = + Job.MediumRun + .WithToolchain(InProcessNoEmitToolchain.Instance) + + let config = + ManualConfig.Create(DefaultConfig.Instance) + .AddJob(medJob) + BenchmarkRunner.Run(config) |> ignore + BenchmarkRunner.Run(config) |> ignore + BenchmarkRunner.Run(config) |> ignore diff --git a/lib/src/Benchmarks/Benchmarks.fsproj b/lib/src/Benchmarks/Benchmarks.fsproj new file mode 100644 index 0000000..5cb7d76 --- /dev/null +++ b/lib/src/Benchmarks/Benchmarks.fsproj @@ -0,0 +1,18 @@ + + + + Exe + net10.0 + false + true + + + + + + + + + + + diff --git a/lib/src/Benchmarks/Profile.fs b/lib/src/Benchmarks/Profile.fs new file mode 100644 index 0000000..cd1c5f5 --- /dev/null +++ b/lib/src/Benchmarks/Profile.fs @@ -0,0 +1,110 @@ +module Profile + +open System + +type Mode = + | BuildAndRender + | BuildOnly + | RenderOnly + +type Api = + | ViewEngine + | Oxpecker + | Giraffe + | Feliz + +let private parseMode (args: string array) = + if args |> Array.contains "--build-only" then + BuildOnly + elif args |> Array.contains "--render-only" then + RenderOnly + else + BuildAndRender + +let private parseApi (args: string array) = + if args |> Array.contains "--oxpecker" then + Oxpecker + elif args |> Array.contains "--giraffe" then + Giraffe + elif args |> Array.contains "--feliz" then + Feliz + else + ViewEngine + +let private parseDurationMs (args: string array) = + args + |> Array.tryFind (fun arg -> arg.StartsWith("--duration-ms=", StringComparison.OrdinalIgnoreCase)) + |> Option.bind (fun arg -> + let value = arg.Substring("--duration-ms=".Length) + match Int32.TryParse(value) with + | true, ms when ms > 0 -> Some ms + | _ -> None) + |> Option.defaultValue 10_000 + +let run (mode: Mode) (api: Api) (durationMs: int) = + let buildAndRender () = + match api with + | ViewEngine -> + Benchmarks.ViewEngineApi.buildDocument() |> FSharp.ViewEngine.Render.toHtmlDocString |> ignore + | Oxpecker -> + Benchmarks.OxpeckerApi.buildDocument() |> Oxpecker.ViewEngine.Render.toHtmlDocString |> ignore + | Giraffe -> + Benchmarks.GiraffeApi.buildDocument() |> Giraffe.ViewEngine.RenderView.AsString.htmlDocument |> ignore + | Feliz -> + Benchmarks.FelizApi.buildDocument() |> Feliz.ViewEngine.Render.htmlDocument |> ignore + + let buildOnly () = + match api with + | ViewEngine -> Benchmarks.ViewEngineApi.buildDocument() |> ignore + | Oxpecker -> Benchmarks.OxpeckerApi.buildDocument() |> ignore + | Giraffe -> Benchmarks.GiraffeApi.buildDocument() |> ignore + | Feliz -> Benchmarks.FelizApi.buildDocument() |> ignore + + let renderOnly () = + match api with + | ViewEngine -> + let doc = Benchmarks.ViewEngineApi.buildDocument() + doc |> FSharp.ViewEngine.Render.toHtmlDocString |> ignore + | Oxpecker -> + let doc = Benchmarks.OxpeckerApi.buildDocument() + doc |> Oxpecker.ViewEngine.Render.toHtmlDocString |> ignore + | Giraffe -> + let doc = Benchmarks.GiraffeApi.buildDocument() + doc |> Giraffe.ViewEngine.RenderView.AsString.htmlDocument |> ignore + | Feliz -> + let doc = Benchmarks.FelizApi.buildDocument() + doc |> Feliz.ViewEngine.Render.htmlDocument |> ignore + + let invoke = + match mode with + | BuildAndRender -> buildAndRender + | BuildOnly -> buildOnly + | RenderOnly -> renderOnly + + // Warm up + for _ = 1 to 1000 do + invoke () + + // Signal ready + Console.Error.WriteLine("READY") + Console.Error.Flush() + + // Hot loop for profiling + let mutable count = 0 + let sw = Diagnostics.Stopwatch.StartNew() + while sw.ElapsedMilliseconds < int64 durationMs do + invoke () + count <- count + 1 + Console.Error.WriteLine($"Completed {count} iterations in {sw.ElapsedMilliseconds}ms") + +[] +let main args = + if args |> Array.contains "--profile" then + let mode = parseMode args + let api = parseApi args + let durationMs = parseDurationMs args + run mode api durationMs + 0 + else + Benchmarks.runBenchmarks () + 0 diff --git a/lib/src/Benchmarks/paket.references b/lib/src/Benchmarks/paket.references new file mode 100644 index 0000000..e8590a7 --- /dev/null +++ b/lib/src/Benchmarks/paket.references @@ -0,0 +1,5 @@ +BenchmarkDotNet +FSharp.Core +Giraffe.ViewEngine +Feliz.ViewEngine +Oxpecker.ViewEngine diff --git a/lib/src/Build/Build.fsproj b/lib/src/Build/Build.fsproj new file mode 100644 index 0000000..8f18310 --- /dev/null +++ b/lib/src/Build/Build.fsproj @@ -0,0 +1,13 @@ + + + Exe + net10.0 + false + $(NoWarn);NU1510 + + + + + + + \ No newline at end of file diff --git a/fsharp-view-engine/src/Build/Program.fs b/lib/src/Build/Program.fs similarity index 69% rename from fsharp-view-engine/src/Build/Program.fs rename to lib/src/Build/Program.fs index b8ff837..5e807ef 100644 --- a/fsharp-view-engine/src/Build/Program.fs +++ b/lib/src/Build/Program.fs @@ -16,10 +16,8 @@ let inline (==>!) x y = x ==> y |> ignore let srcDir = Path.getDirectory __SOURCE_DIRECTORY__ let rootDir = Path.getDirectory srcDir -let sln = rootDir "FSharp.ViewEngine.sln" let nugetsDir = rootDir "nugets" let testsDir = srcDir "Tests" -let appDir = srcDir "App" let exec workDir cmd args = CreateProcess.fromRawCommand cmd args @@ -39,7 +37,6 @@ let execEnv env workDir cmd args = |> Async.Ignore let dotnet workdir args = exec workdir "dotnet" args -let tailwindcss args = exec appDir "tailwindcss" args let getVersion () = let tag = Environment.environVarOrFail "GITHUB_REF_NAME" @@ -52,30 +49,11 @@ Target.create "Test" <| fun _ -> dotnet testsDir ["test"] |> Async.RunSynchronously -Target.create "WatchApp" (fun _ -> - let watchApp = dotnet appDir ["watch"; "run"; "--no-restore"] - let watchCss = tailwindcss ["--input"; "input.css"; "--output"; "wwwroot/css/output.css"; "--watch"] - Async.Parallel [| watchApp; watchCss |] - |> Async.RunSynchronously - |> ignore -) - -Target.create "BuildAppCss" <| fun _ -> - tailwindcss [ "--input"; "input.css"; "--output"; "wwwroot/css/output.css"; "--minify" ] - |> Async.RunSynchronously - -Target.create "PublishApp" <| fun _ -> - dotnet appDir [ - "publish" - "--output"; "./out" - "--self-contained"; "false" - ] - |> Async.RunSynchronously - Target.create "Pack" (fun _ -> - Trace.trace $"Packing {sln}" + let project = srcDir "FSharp.ViewEngine" "FSharp.ViewEngine.fsproj" + Trace.trace $"Packing {project}" let version = getVersion() - dotnet rootDir ["pack"; sln; "--configuration"; "Release"; "--output"; nugetsDir; $"/p:PackageVersion={version}"] + dotnet rootDir ["pack"; project; "--configuration"; "Release"; "--output"; nugetsDir; $"/p:PackageVersion={version}"] |> Async.RunSynchronously ) @@ -92,6 +70,5 @@ Target.create "Default" (fun _ -> Target.listAvailable()) "Test" ==>! "Pack" "CleanNugets" ==>! "Pack" "Pack" ==>! "PushNugets" -"BuildAppCss" ==>! "PublishApp" Target.runOrDefaultWithArguments "Default" diff --git a/lib/src/Build/paket.references b/lib/src/Build/paket.references new file mode 100644 index 0000000..9bc568a --- /dev/null +++ b/lib/src/Build/paket.references @@ -0,0 +1 @@ +Fake.Core.Target diff --git a/lib/src/FSharp.ViewEngine/Alpine.fs b/lib/src/FSharp.ViewEngine/Alpine.fs new file mode 100644 index 0000000..7948334 --- /dev/null +++ b/lib/src/FSharp.ViewEngine/Alpine.fs @@ -0,0 +1,41 @@ +namespace FSharp.ViewEngine + +type Alpine = + static member inline _by (value: string) = { Name = "by"; Value = ValueSome value } + static member inline _x (key: string, ?value: string) = + match value with + | Some v -> { Name = $"x-{key}"; Value = ValueSome v } + | None -> { Name = $"x-{key}"; Value = ValueNone } + static member inline _xOn (event: string, v: string) = { Name = $"x-on:{event}"; Value = ValueSome v } + static member inline _xOn (event: string) = { Name = $"x-on:{event}"; Value = ValueNone } + static member inline _xInit (value: string) = { Name = "x-init"; Value = ValueSome value } + static member inline _xData (value: string) = { Name = "x-data"; Value = ValueSome value } + static member inline _xRef (value: string) = { Name = "x-ref"; Value = ValueSome value } + static member inline _xText (value: string) = { Name = "x-text"; Value = ValueSome value } + static member inline _xBind (attr: string, value: string) = { Name = $"x-bind:{attr}"; Value = ValueSome value } + static member inline _xShow (value: string) = { Name = "x-show"; Value = ValueSome value } + static member inline _xIf (value: string) = { Name = "x-if"; Value = ValueSome value } + static member inline _xFor (value: string) = { Name = "x-for"; Value = ValueSome value } + static member inline _xModel (value: string, ?modifier: string) = + match modifier with + | Some m -> { Name = $"x-model{m}"; Value = ValueSome value } + | None -> { Name = "x-model"; Value = ValueSome value } + static member inline _xModelable (value: string) = { Name = "x-modelable"; Value = ValueSome value } + static member inline _xId (value: string) = { Name = "x-id"; Value = ValueSome value } + static member inline _xEffect (value: string) = { Name = "x-effect"; Value = ValueSome value } + static member inline _xTransition (?value: string, ?modifier: string) = + match value, modifier with + | Some v, Some m -> { Name = $"x-transition{m}"; Value = ValueSome v } + | Some v, None -> { Name = "x-transition"; Value = ValueSome v } + | None, Some m -> { Name = $"x-transition{m}"; Value = ValueNone } + | None, None -> { Name = "x-transition"; Value = ValueNone } + static member inline _xTrap (value: string, ?modifier: string) = + match modifier with + | Some m -> { Name = $"x-trap{m}"; Value = ValueSome value } + | None -> { Name = "x-trap"; Value = ValueSome value } + static member inline _xCloak = { Name = "x-cloak"; Value = ValueNone } + static member inline _xAnchor (value: string, ?modifier: string) = + match modifier with + | Some m -> { Name = $"x-anchor{m}"; Value = ValueSome value } + | None -> { Name = "x-anchor"; Value = ValueSome value } + static member inline _xTeleport (value: string) = { Name = "x-teleport"; Value = ValueSome value } diff --git a/lib/src/FSharp.ViewEngine/Core.fs b/lib/src/FSharp.ViewEngine/Core.fs new file mode 100644 index 0000000..fc0fd85 --- /dev/null +++ b/lib/src/FSharp.ViewEngine/Core.fs @@ -0,0 +1,322 @@ +namespace FSharp.ViewEngine + +open System +open System.Buffers +open System.Runtime.CompilerServices +open System.Text + +[] +type HtmlAttribute = { Name: string; Value: string voption } + +[] +type HtmlElement() = + abstract Render: StringBuilder -> unit + +module private HtmlEncoding = + [] + let private UnicodeReplacementChar = '\uFFFD' + + let private htmlAsciiNonEncodingChars = + SearchValues.Create( + "\0\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n\v\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !#$%()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f" + ) + + let rec private findEncodingCharLoop i (input: ReadOnlySpan) = + if i < input.Length then + let ch = input[i] + if ch <= '>' then + if ch = '<' || ch = '>' || ch = '"' || ch = '\'' || ch = '&' then + i + else + findEncodingCharLoop (i + 1) input + elif Char.IsBetween(ch, '\u00A0', '\u00FF') || Char.IsSurrogate(ch) then + i + else + findEncodingCharLoop (i + 1) input + else + -1 + + let private indexOfHtmlEncodingChar (input: ReadOnlySpan) = + match input.IndexOfAnyExcept(htmlAsciiNonEncodingChars) with + | -1 -> -1 + | index -> findEncodingCharLoop index input + + let private htmlEncodeInner (input: ReadOnlySpan) (sb: StringBuilder) : unit = + let mutable i = 0 + while i < input.Length do + let ch = input[i] + i <- i + 1 + if ch <= '>' then + if '<' = ch then sb.Append "<" + elif '>' = ch then sb.Append ">" + elif '"' = ch then sb.Append """ + elif '\'' = ch then sb.Append "'" + elif '&' = ch then sb.Append "&" + else sb.Append ch + else if Char.IsBetween(ch, '\u00A0', '\u00FF') then + sb.Append("&#").Append(int ch).Append(';') + elif Char.IsSurrogate(ch) then + if i < input.Length then + match Rune.TryCreate(ch, input[i]) with + | true, rune -> + i <- i + 1 + sb.Append("&#").Append(rune.Value).Append(';') + | _ -> + sb.Append(UnicodeReplacementChar) + else + sb.Append(UnicodeReplacementChar) + else + sb.Append(ch) + |> ignore + + let htmlEncode (value: string) (sb: StringBuilder) = + if isNull value then + () + else + let value = value.AsSpan() + match indexOfHtmlEncodingChar value with + | -1 -> sb.Append(value) |> ignore + | index -> + sb.Append(value.Slice(0, index)) |> ignore + htmlEncodeInner (value.Slice index) sb + +type TextElement(text: string) = + inherit HtmlElement() + override _.Render(sb) = HtmlEncoding.htmlEncode text sb + +type RawElement(text: string) = + inherit HtmlElement() + override _.Render(sb) = sb.Append(text) |> ignore + +type NoopElement() = + inherit HtmlElement() + override _.Render(_) = () + +module private RenderHelpers = + let inline renderAttr (sb: StringBuilder) (a: HtmlAttribute) = + match a.Value with + | ValueSome v -> sb.Append(' ').Append(a.Name).Append("=\"").Append(v).Append('\"') |> ignore + | ValueNone -> sb.Append(' ').Append(a.Name) |> ignore + +type VoidElement(tag: string) = + inherit HtmlElement() + let mutable attrCount = 0 + let mutable attr0 = Unchecked.defaultof + let mutable attr1 = Unchecked.defaultof + let mutable attrRest: ResizeArray = null + [] + member this.AddAttr(a: HtmlAttribute) = + match attrCount with + | 0 -> + attr0 <- a + attrCount <- 1 + | 1 -> + attr1 <- a + attrCount <- 2 + | _ -> + if isNull attrRest then + attrRest <- ResizeArray() + attrRest.Add(a) + attrCount <- attrCount + 1 + override _.Render(sb) = + sb.Append('<').Append(tag) |> ignore + match attrCount with + | 0 -> () + | 1 -> RenderHelpers.renderAttr sb attr0 + | 2 -> + RenderHelpers.renderAttr sb attr0 + RenderHelpers.renderAttr sb attr1 + | _ -> + RenderHelpers.renderAttr sb attr0 + RenderHelpers.renderAttr sb attr1 + let rest = attrRest + if not (isNull rest) then + for i = 0 to rest.Count - 1 do + RenderHelpers.renderAttr sb rest[i] + sb.Append('>') |> ignore + +type RegularElement(tag: string) = + inherit HtmlElement() + let mutable attrCount = 0 + let mutable attr0 = Unchecked.defaultof + let mutable attr1 = Unchecked.defaultof + let mutable attrRest: ResizeArray = null + let mutable childCount = 0 + let mutable child0 = Unchecked.defaultof + let mutable child1 = Unchecked.defaultof + let mutable childRest: ResizeArray = null + [] + member this.AddAttr(a: HtmlAttribute) = + match attrCount with + | 0 -> + attr0 <- a + attrCount <- 1 + | 1 -> + attr1 <- a + attrCount <- 2 + | _ -> + if isNull attrRest then + attrRest <- ResizeArray() + attrRest.Add(a) + attrCount <- attrCount + 1 + [] + member this.AddChild(c: HtmlElement) = + match childCount with + | 0 -> + child0 <- c + childCount <- 1 + | 1 -> + child1 <- c + childCount <- 2 + | _ -> + if isNull childRest then + childRest <- ResizeArray() + childRest.Add(c) + childCount <- childCount + 1 + override _.Render(sb) = + sb.Append('<').Append(tag) |> ignore + match attrCount with + | 0 -> () + | 1 -> RenderHelpers.renderAttr sb attr0 + | 2 -> + RenderHelpers.renderAttr sb attr0 + RenderHelpers.renderAttr sb attr1 + | _ -> + RenderHelpers.renderAttr sb attr0 + RenderHelpers.renderAttr sb attr1 + let rest = attrRest + if not (isNull rest) then + for i = 0 to rest.Count - 1 do + RenderHelpers.renderAttr sb rest[i] + sb.Append('>') |> ignore + match childCount with + | 0 -> () + | 1 -> child0.Render(sb) + | 2 -> + child0.Render(sb) + child1.Render(sb) + | _ -> + child0.Render(sb) + child1.Render(sb) + let rest = childRest + if not (isNull rest) then + for i = 0 to rest.Count - 1 do + rest[i].Render(sb) + sb.Append("') |> ignore + +type private StringBuilderPool = + [] + static val mutable private pool: ResizeArray + + static member inline Rent() = + let pool = StringBuilderPool.pool + if isNull pool || pool.Count = 0 then + StringBuilder() + else + let idx = pool.Count - 1 + let sb = pool[idx] + pool.RemoveAt(idx) + sb + + static member inline Return(sb: StringBuilder) = + sb.Clear() |> ignore + let pool = StringBuilderPool.pool + if isNull pool then + let p = ResizeArray() + p.Add(sb) + StringBuilderPool.pool <- p + else + pool.Add(sb) + +type TagBuilderCode = RegularElement -> unit +type VoidBuilderCode = VoidElement -> unit + +type TagBuilder(tag: string) = + [] + member inline _.Yield(el: HtmlElement) : TagBuilderCode = + fun st -> st.AddChild(el) + + [] + member inline _.Yield(text: string) : TagBuilderCode = + fun st -> st.AddChild(TextElement(text) :> HtmlElement) + + [] + member inline _.Yield(attr: HtmlAttribute) : TagBuilderCode = + fun st -> + if not (isNull attr.Name) then + st.AddAttr(attr) + + [] + member inline _.Zero() : TagBuilderCode = + fun _ -> () + + [] + member inline _.Combine([] f1: TagBuilderCode, [] f2: TagBuilderCode) : TagBuilderCode = + fun st -> f1 st; f2 st + + [] + member inline _.Delay([] f: unit -> TagBuilderCode) : TagBuilderCode = + fun st -> (f ()) st + + [] + member inline _.For(xs: 'a seq, [] f: 'a -> TagBuilderCode) : TagBuilderCode = + fun st -> + for x in xs do + (f x) st + + [] + member _.Run(f: TagBuilderCode) : HtmlElement = + let el = RegularElement(tag) + f el + el :> HtmlElement + + +type VoidBuilder(tag: string) = + [] + member inline _.Yield(attr: HtmlAttribute) : VoidBuilderCode = + fun st -> + if not (isNull attr.Name) then + st.AddAttr(attr) + + [] + member inline _.Zero() : VoidBuilderCode = + fun _ -> () + + [] + member inline _.Combine([] f1: VoidBuilderCode, [] f2: VoidBuilderCode) : VoidBuilderCode = + fun st -> f1 st; f2 st + + [] + member inline _.Delay([] f: unit -> VoidBuilderCode) : VoidBuilderCode = + fun st -> (f ()) st + + [] + member inline _.For(xs: 'a seq, [] f: 'a -> VoidBuilderCode) : VoidBuilderCode = + fun st -> + for x in xs do + (f x) st + + [] + member _.Run(f: VoidBuilderCode) : HtmlElement = + let el = VoidElement(tag) + f el + el :> HtmlElement + +[] +module Render = + let toString (element: HtmlElement) = + let sb = StringBuilderPool.Rent() + try + element.Render(sb) + sb.ToString() + finally + StringBuilderPool.Return(sb) + + let toHtmlDocString (view: #HtmlElement) = + let sb = StringBuilderPool.Rent() + sb.AppendLine("") |> ignore + try + view.Render(sb) + sb.ToString() + finally + StringBuilderPool.Return(sb) diff --git a/lib/src/FSharp.ViewEngine/Datastar.fs b/lib/src/FSharp.ViewEngine/Datastar.fs new file mode 100644 index 0000000..258a260 --- /dev/null +++ b/lib/src/FSharp.ViewEngine/Datastar.fs @@ -0,0 +1,45 @@ +namespace FSharp.ViewEngine + +type Datastar = + // Generic data-* attribute + static member inline _ds (key: string, value: string) = { Name = $"data-{key}"; Value = ValueSome value } + static member inline _ds (key: string) = { Name = $"data-{key}"; Value = ValueNone } + + // Core attributes + static member inline _dsAttr (name: string, v: string) = { Name = $"data-attr:{name}"; Value = ValueSome v } + static member inline _dsBind (name: string) = { Name = $"data-bind:{name}"; Value = ValueNone } + static member inline _dsBind (name: string, v: string) = { Name = $"data-bind:{name}"; Value = ValueSome v } + static member inline _dsClass (name: string, v: string) = { Name = $"data-class:{name}"; Value = ValueSome v } + static member inline _dsComputed (name: string, v: string) = { Name = $"data-computed:{name}"; Value = ValueSome v } + static member inline _dsEffect (v: string) = { Name = "data-effect"; Value = ValueSome v } + static member inline _dsIgnore = { Name = "data-ignore"; Value = ValueNone } + static member inline _dsIgnoreMorph = { Name = "data-ignore-morph"; Value = ValueNone } + static member inline _dsIndicator (name: string) = { Name = $"data-indicator:{name}"; Value = ValueNone } + static member inline _dsIndicator (name: string, v: string) = { Name = $"data-indicator:{name}"; Value = ValueSome v } + static member inline _dsInit (v: string) = { Name = "data-init"; Value = ValueSome v } + static member inline _dsJsonSignals (?v: string) = match v with Some v -> { Name = "data-json-signals"; Value = ValueSome v } | None -> { Name = "data-json-signals"; Value = ValueNone } + static member inline _dsOn (event: string, v: string) = { Name = $"data-on:{event}"; Value = ValueSome v } + static member inline _dsOnIntersect (v: string) = { Name = "data-on-intersect"; Value = ValueSome v } + static member inline _dsOnInterval (v: string) = { Name = "data-on-interval"; Value = ValueSome v } + static member inline _dsOnSignalPatch (v: string) = { Name = "data-on-signal-patch"; Value = ValueSome v } + static member inline _dsOnSignalPatchFilter (v: string) = { Name = "data-on-signal-patch-filter"; Value = ValueSome v } + static member inline _dsPreserveAttr (v: string) = { Name = "data-preserve-attr"; Value = ValueSome v } + static member inline _dsRef (name: string) = { Name = $"data-ref:{name}"; Value = ValueNone } + static member inline _dsRef (name: string, v: string) = { Name = $"data-ref:{name}"; Value = ValueSome v } + static member inline _dsShow (v: string) = { Name = "data-show"; Value = ValueSome v } + static member inline _dsSignals (name: string, v: string) = { Name = $"data-signals:{name}"; Value = ValueSome v } + static member inline _dsStyle (prop: string, v: string) = { Name = $"data-style:{prop}"; Value = ValueSome v } + static member inline _dsText (v: string) = { Name = "data-text"; Value = ValueSome v } + + // Pro attributes + static member inline _dsAnimate (v: string) = { Name = "data-animate"; Value = ValueSome v } + static member inline _dsCustomValidity (v: string) = { Name = "data-custom-validity"; Value = ValueSome v } + static member inline _dsOnRaf (v: string) = { Name = "data-on-raf"; Value = ValueSome v } + static member inline _dsOnResize (v: string) = { Name = "data-on-resize"; Value = ValueSome v } + static member inline _dsPersist (key: string) = { Name = $"data-persist:{key}"; Value = ValueNone } + static member inline _dsPersist (key: string, v: string) = { Name = $"data-persist:{key}"; Value = ValueSome v } + static member inline _dsQueryString (?v: string) = match v with Some v -> { Name = "data-query-string"; Value = ValueSome v } | None -> { Name = "data-query-string"; Value = ValueNone } + static member inline _dsReplaceUrl (v: string) = { Name = "data-replace-url"; Value = ValueSome v } + static member inline _dsRocket (v: string) = { Name = "data-rocket"; Value = ValueSome v } + static member inline _dsScrollIntoView = { Name = "data-scroll-into-view"; Value = ValueNone } + static member inline _dsViewTransition (v: string) = { Name = "data-view-transition"; Value = ValueSome v } diff --git a/fsharp-view-engine/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj b/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj similarity index 91% rename from fsharp-view-engine/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj rename to lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj index a557833..ee59546 100644 --- a/fsharp-view-engine/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj +++ b/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj @@ -1,4 +1,4 @@ - + net10.0 @@ -16,9 +16,10 @@ + - \ No newline at end of file + diff --git a/lib/src/FSharp.ViewEngine/Html.fs b/lib/src/FSharp.ViewEngine/Html.fs new file mode 100644 index 0000000..b8294a1 --- /dev/null +++ b/lib/src/FSharp.ViewEngine/Html.fs @@ -0,0 +1,226 @@ +namespace FSharp.ViewEngine + +open JetBrains.Annotations + +type Html = + static member val EmptyAttr = { Name = null; Value = ValueNone } with get + static member val empty = NoopElement() :> HtmlElement with get + static member raw ([]v: string) = RawElement(v) :> HtmlElement + static member js ([]v: string) = RawElement(v) :> HtmlElement + static member text (v: string) = TextElement(v) :> HtmlElement + static member val html = TagBuilder("html") with get + static member val head = TagBuilder("head") with get + static member title (value: string) = + let el = RegularElement("title") + el.AddChild(TextElement(value) :> HtmlElement) + el :> HtmlElement + static member val script = TagBuilder("script") with get + static member val body = TagBuilder("body") with get + static member val main = TagBuilder("main") with get + static member val header = TagBuilder("header") with get + static member val footer = TagBuilder("footer") with get + static member val nav = TagBuilder("nav") with get + static member val h1 = TagBuilder("h1") with get + static member val h2 = TagBuilder("h2") with get + static member val h3 = TagBuilder("h3") with get + static member val h4 = TagBuilder("h4") with get + static member val h5 = TagBuilder("h5") with get + static member val h6 = TagBuilder("h6") with get + static member val div = TagBuilder("div") with get + static member val p = TagBuilder("p") with get + static member val span = TagBuilder("span") with get + static member val a = TagBuilder("a") with get + static member val button = TagBuilder("button") with get + static member val code = TagBuilder("code") with get + static member val pre = TagBuilder("pre") with get + static member val ul = TagBuilder("ul") with get + static member val ol = TagBuilder("ol") with get + static member val li = TagBuilder("li") with get + static member val blockquote = TagBuilder("blockquote") with get + static member val article = TagBuilder("article") with get + static member val dialog = TagBuilder("dialog") with get + static member val time = TagBuilder("time") with get + static member val form = TagBuilder("form") with get + static member val label = TagBuilder("label") with get + static member val textarea = TagBuilder("textarea") with get + static member val select = TagBuilder("select") with get + static member val option = TagBuilder("option") with get + static member val table = TagBuilder("table") with get + static member val thead = TagBuilder("thead") with get + static member val tr = TagBuilder("tr") with get + static member val th = TagBuilder("th") with get + static member val tbody = TagBuilder("tbody") with get + static member val td = TagBuilder("td") with get + static member val dl = TagBuilder("dl") with get + static member val dt = TagBuilder("dt") with get + static member val dd = TagBuilder("dd") with get + static member val template = TagBuilder("template") with get + static member val iframe = TagBuilder("iframe") with get + static member val section = TagBuilder("section") with get + static member val aside = TagBuilder("aside") with get + static member val figure = TagBuilder("figure") with get + static member val figcaption = TagBuilder("figcaption") with get + static member val details = TagBuilder("details") with get + static member val summary = TagBuilder("summary") with get + static member val strong = TagBuilder("strong") with get + static member val em = TagBuilder("em") with get + static member val b = TagBuilder("b") with get + static member val i = TagBuilder("i") with get + static member val u = TagBuilder("u") with get + static member val s = TagBuilder("s") with get + static member val small = TagBuilder("small") with get + static member val mark = TagBuilder("mark") with get + static member val sub = TagBuilder("sub") with get + static member val sup = TagBuilder("sup") with get + static member val abbr = TagBuilder("abbr") with get + static member val cite = TagBuilder("cite") with get + static member val q = TagBuilder("q") with get + static member val dfn = TagBuilder("dfn") with get + static member val var = TagBuilder("var") with get + static member val samp = TagBuilder("samp") with get + static member val kbd = TagBuilder("kbd") with get + static member val ins = TagBuilder("ins") with get + static member val del = TagBuilder("del") with get + static member val address = TagBuilder("address") with get + static member val hgroup = TagBuilder("hgroup") with get + static member val search = TagBuilder("search") with get + static member val noscript = TagBuilder("noscript") with get + static member val slot = TagBuilder("slot") with get + static member val data = TagBuilder("data") with get + static member val video = TagBuilder("video") with get + static member val audio = TagBuilder("audio") with get + static member val picture = TagBuilder("picture") with get + static member val canvas = TagBuilder("canvas") with get + static member val object = TagBuilder("object") with get + static member val fieldset = TagBuilder("fieldset") with get + static member val legend = TagBuilder("legend") with get + static member val datalist = TagBuilder("datalist") with get + static member val output = TagBuilder("output") with get + static member val progress = TagBuilder("progress") with get + static member val meter = TagBuilder("meter") with get + static member val caption = TagBuilder("caption") with get + static member val colgroup = TagBuilder("colgroup") with get + static member val tfoot = TagBuilder("tfoot") with get + static member val map = TagBuilder("map") with get + static member val br = VoidElement("br") :> HtmlElement with get + static member val hr = VoidElement("hr") :> HtmlElement with get + static member val wbr = VoidElement("wbr") :> HtmlElement with get + static member val meta = VoidBuilder("meta") with get + static member val link = VoidBuilder("link") with get + static member val img = VoidBuilder("img") with get + static member val input = VoidBuilder("input") with get + static member val source = VoidBuilder("source") with get + static member val track = VoidBuilder("track") with get + static member val col = VoidBuilder("col") with get + static member val area = VoidBuilder("area") with get + static member val embed = VoidBuilder("embed") with get + + static member inline _id (v: string) = { Name = "id"; Value = ValueSome v } + static member inline _class (v: string) = { Name = "class"; Value = ValueSome v } + static member inline _class (v: string seq) = { Name = "class"; Value = ValueSome(v |> String.concat " ") } + static member inline _style (v: string) = { Name = "style"; Value = ValueSome v } + static member inline _lang (v: string) = { Name = "lang"; Value = ValueSome v } + static member inline _charset (v: string) = { Name = "charset"; Value = ValueSome v } + static member inline _name (v: string) = { Name = "name"; Value = ValueSome v } + static member inline _content (v: string) = { Name = "content"; Value = ValueSome v } + static member inline _href (v: string) = { Name = "href"; Value = ValueSome v } + static member inline _rel (v: string) = { Name = "rel"; Value = ValueSome v } + static member inline _src (v: string) = { Name = "src"; Value = ValueSome v } + static member inline _async (v: bool) = if v then { Name = "async"; Value = ValueNone } else Html.EmptyAttr + static member inline _defer (v: bool) = if v then { Name = "defer"; Value = ValueNone } else Html.EmptyAttr + static member inline _action (v: string) = { Name = "action"; Value = ValueSome v } + static member inline _method (v: string) = { Name = "method"; Value = ValueSome v } + static member inline _formmethod (v: string) = { Name = "formmethod"; Value = ValueSome v } + static member inline _type (v: string) = { Name = "type"; Value = ValueSome v } + static member inline _for (v: string) = { Name = "for"; Value = ValueSome v } + static member inline _rows (v: int) = { Name = "rows"; Value = ValueSome(string v) } + static member inline _cols (v: int) = { Name = "cols"; Value = ValueSome(string v) } + static member inline _data (attr: string, ?v: string) = + let key = $"data-{attr}" + match v with + | Some v -> { Name = key; Value = ValueSome v } + | None -> { Name = key; Value = ValueNone } + static member inline _datetime (v: string) = { Name = "datetime"; Value = ValueSome v } + static member inline _width (v: string) = { Name = "width"; Value = ValueSome v } + static member inline _height (v: string) = { Name = "height"; Value = ValueSome v } + static member inline _value (v: string) = { Name = "value"; Value = ValueSome v } + static member inline _hidden (v: bool) = if v then { Name = "hidden"; Value = ValueNone } else Html.EmptyAttr + static member inline _required (v: bool) = if v then { Name = "required"; Value = ValueNone } else Html.EmptyAttr + static member inline _disabled (v: bool) = if v then { Name = "disabled"; Value = ValueNone } else Html.EmptyAttr + static member inline _readonly (v: bool) = if v then { Name = "readonly"; Value = ValueNone } else Html.EmptyAttr + static member inline _multiple (v: bool) = if v then { Name = "multiple"; Value = ValueNone } else Html.EmptyAttr + static member inline _selected (v: bool) = if v then { Name = "selected"; Value = ValueNone } else Html.EmptyAttr + static member inline _min (v: string) = { Name = "min"; Value = ValueSome v } + static member inline _min (v: float) = { Name = "min"; Value = ValueSome(string v) } + static member inline _minlength (v: string) = { Name = "minlength"; Value = ValueSome v } + static member inline _minlength (v: int) = { Name = "minlength"; Value = ValueSome(string v) } + static member inline _max (v: string) = { Name = "max"; Value = ValueSome v } + static member inline _max (v: float) = { Name = "max"; Value = ValueSome(string v) } + static member inline _maxlength (v: string) = { Name = "maxlength"; Value = ValueSome v } + static member inline _maxlength (v: int) = { Name = "maxlength"; Value = ValueSome(string v) } + static member inline _step (v: string) = { Name = "step"; Value = ValueSome v } + static member inline _step (v: float) = { Name = "step"; Value = ValueSome(string v) } + static member inline _checked (v: bool) = if v then { Name = "checked"; Value = ValueNone } else Html.EmptyAttr + static member inline _role (v: string) = { Name = "role"; Value = ValueSome v } + static member inline _ariaLabelledby (v: string) = { Name = "aria-labelledby"; Value = ValueSome v } + static member inline _ariaDescribedby (v: string) = { Name = "aria-describedby"; Value = ValueSome v } + static member inline _ariaModal (v: string) = { Name = "aria-modal"; Value = ValueSome v } + static member inline _placeholder (v: string) = { Name = "placeholder"; Value = ValueSome v } + static member inline _autocomplete (v: string) = { Name = "autocomplete"; Value = ValueSome v } + static member inline _pattern (v: string) = { Name = "pattern"; Value = ValueSome v } + static member inline _accept (v: string) = { Name = "accept"; Value = ValueSome v } + static member inline _title (v: string) = { Name = "title"; Value = ValueSome v } + static member inline _wrap (v: string) = { Name = "wrap"; Value = ValueSome v } + static member inline _size (v: int) = { Name = "size"; Value = ValueSome(string v) } + static member inline _colspan (v: int) = { Name = "colspan"; Value = ValueSome(string v) } + static member inline _onload (v: string) = { Name = "onload"; Value = ValueSome v } + static member inline _crossorigin = { Name = "crossorigin"; Value = ValueNone } + static member inline _alt (v: string) = { Name = "alt"; Value = ValueSome v } + static member inline _target (v: string) = { Name = "target"; Value = ValueSome v } + static member inline _tabindex (v: int) = { Name = "tabindex"; Value = ValueSome(string v) } + static member inline _autofocus (v: bool) = if v then { Name = "autofocus"; Value = ValueNone } else Html.EmptyAttr + static member inline _open (v: bool) = if v then { Name = "open"; Value = ValueNone } else Html.EmptyAttr + static member inline _loading (v: string) = { Name = "loading"; Value = ValueSome v } + static member inline _srcset (v: string) = { Name = "srcset"; Value = ValueSome v } + static member inline _sandbox (v: string) = { Name = "sandbox"; Value = ValueSome v } + static member inline _allow (v: string) = { Name = "allow"; Value = ValueSome v } + static member inline _enctype (v: string) = { Name = "enctype"; Value = ValueSome v } + static member inline _novalidate (v: bool) = if v then { Name = "novalidate"; Value = ValueNone } else Html.EmptyAttr + static member inline _spellcheck (v: bool) = { Name = "spellcheck"; Value = ValueSome(if v then "true" else "false") } + static member inline _draggable (v: bool) = { Name = "draggable"; Value = ValueSome(if v then "true" else "false") } + static member inline _contenteditable (v: bool) = { Name = "contenteditable"; Value = ValueSome(if v then "true" else "false") } + static member inline _accesskey (v: string) = { Name = "accesskey"; Value = ValueSome v } + static member inline _dir (v: string) = { Name = "dir"; Value = ValueSome v } + static member inline _translate (v: bool) = { Name = "translate"; Value = ValueSome(if v then "yes" else "no") } + static member inline _inputmode (v: string) = { Name = "inputmode"; Value = ValueSome v } + static member inline _enterkeyhint (v: string) = { Name = "enterkeyhint"; Value = ValueSome v } + static member inline _list (v: string) = { Name = "list"; Value = ValueSome v } + static member inline _form (v: string) = { Name = "form"; Value = ValueSome v } + static member inline _formaction (v: string) = { Name = "formaction"; Value = ValueSome v } + static member inline _formenctype (v: string) = { Name = "formenctype"; Value = ValueSome v } + static member inline _formnovalidate (v: bool) = if v then { Name = "formnovalidate"; Value = ValueNone } else Html.EmptyAttr + static member inline _formtarget (v: string) = { Name = "formtarget"; Value = ValueSome v } + static member inline _ariaLabel (v: string) = { Name = "aria-label"; Value = ValueSome v } + static member inline _ariaHidden (v: string) = { Name = "aria-hidden"; Value = ValueSome v } + static member inline _ariaExpanded (v: string) = { Name = "aria-expanded"; Value = ValueSome v } + static member inline _ariaControls (v: string) = { Name = "aria-controls"; Value = ValueSome v } + static member inline _ariaLive (v: string) = { Name = "aria-live"; Value = ValueSome v } + static member inline _ariaCurrent (v: string) = { Name = "aria-current"; Value = ValueSome v } + static member inline _rowspan (v: int) = { Name = "rowspan"; Value = ValueSome(string v) } + static member inline _scope (v: string) = { Name = "scope"; Value = ValueSome v } + static member inline _headers (v: string) = { Name = "headers"; Value = ValueSome v } + static member inline _download (v: string) = { Name = "download"; Value = ValueSome v } + static member inline _download () = { Name = "download"; Value = ValueNone } + static member inline _referrerpolicy (v: string) = { Name = "referrerpolicy"; Value = ValueSome v } + static member inline _media (v: string) = { Name = "media"; Value = ValueSome v } + static member inline _sizes (v: string) = { Name = "sizes"; Value = ValueSome v } + static member inline _poster (v: string) = { Name = "poster"; Value = ValueSome v } + static member inline _controls (v: bool) = if v then { Name = "controls"; Value = ValueNone } else Html.EmptyAttr + static member inline _autoplay (v: bool) = if v then { Name = "autoplay"; Value = ValueNone } else Html.EmptyAttr + static member inline _loop (v: bool) = if v then { Name = "loop"; Value = ValueNone } else Html.EmptyAttr + static member inline _muted (v: bool) = if v then { Name = "muted"; Value = ValueNone } else Html.EmptyAttr + static member inline _preload (v: string) = { Name = "preload"; Value = ValueSome v } + static member inline _start (v: int) = { Name = "start"; Value = ValueSome(string v) } + static member inline _reversed (v: bool) = if v then { Name = "reversed"; Value = ValueNone } else Html.EmptyAttr + static member inline _cite (v: string) = { Name = "cite"; Value = ValueSome v } + diff --git a/lib/src/FSharp.ViewEngine/Htmx.fs b/lib/src/FSharp.ViewEngine/Htmx.fs new file mode 100644 index 0000000..96cd894 --- /dev/null +++ b/lib/src/FSharp.ViewEngine/Htmx.fs @@ -0,0 +1,17 @@ +namespace FSharp.ViewEngine + +type Htmx = + static member inline _hx (key: string, value: string) = { Name = $"hx-{key}"; Value = ValueSome value } + static member inline _hxGet (v: string) = { Name = "hx-get"; Value = ValueSome v } + static member inline _hxPost (v: string) = { Name = "hx-post"; Value = ValueSome v } + static member inline _hxDelete (v: string) = { Name = "hx-delete"; Value = ValueSome v } + static member inline _hxTrigger (v: string) = { Name = "hx-trigger"; Value = ValueSome v } + static member inline _hxTarget (v: string) = { Name = "hx-target"; Value = ValueSome v } + static member inline _hxIndicator (v: string) = { Name = "hx-indicator"; Value = ValueSome v } + static member inline _hxInclude (v: string) = { Name = "hx-include"; Value = ValueSome v } + static member inline _hxSwap (v: string) = { Name = "hx-swap"; Value = ValueSome v } + static member inline _hxSwapOOB (v: string) = { Name = "hx-swap-oob"; Value = ValueSome v } + static member inline _hxEncoding (v: string) = { Name = "hx-encoding"; Value = ValueSome v } + static member inline _hxOn (event: string, value: string) = { Name = $"hx-on:{event}"; Value = ValueSome value } + static member inline _hxHistory (v: string) = { Name = "hx-history"; Value = ValueSome v } + static member inline _hxVals (v: string) = { Name = "hx-vals"; Value = ValueSome v } diff --git a/lib/src/FSharp.ViewEngine/README.md b/lib/src/FSharp.ViewEngine/README.md new file mode 100644 index 0000000..25fd83b --- /dev/null +++ b/lib/src/FSharp.ViewEngine/README.md @@ -0,0 +1,77 @@ +[![Release](https://github.com/meiermade/FSharp.ViewEngine/actions/workflows/release.yml/badge.svg)](https://github.com/meiermade/FSharp.ViewEngine/actions/workflows/release.yml) + +# FSharp.ViewEngine +View engine for F#. Inspired by [Giraffe.ViewEngine](https://github.com/giraffe-fsharp/Giraffe.ViewEngine) and +[Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine). +Documentation site built using FSharp.ViewEngine available at [https://fsharpviewengine.meiermade.com](https://fsharpviewengine.meiermade.com). +> See [App](./src/App) for the source code. + +## Installation +Add the core view engine package. +```shell +dotnet add package FSharp.ViewEngine +``` + +## Usage +```fsharp +open FSharp.ViewEngine +open type Html +open type Htmx +open type Alpine +open type Tailwind + +html { + _lang "en" + head { + title "Test" + meta { _charset "utf-8" } + link { _href "/css/compiled.css"; _rel "stylesheet" } + } + body { + _xData "{showContent: false}" + _class "bg-gray-50" + div { + _id "page" + _class [ "flex"; "flex-col" ] + h1 { _hxGet "/hello"; _hxTarget "#page"; "Hello" } + h1 { _hxGet "/world"; _hxTarget "#page"; "World" } + } + br + div { + _xShow "showContent" + h2 { "Content" } + p { "Some content" } + ul { + li { "One" } + li { "Two" } + } + } + } +} +|> Render.toHtmlDocString +``` +```html + + + + Test + + + + +
+

Hello

+

World

+
+
+
+

Content

+

Some content

+
    +
  • One
  • +
  • Two
  • +
+
+ + +``` diff --git a/lib/src/FSharp.ViewEngine/Svg.fs b/lib/src/FSharp.ViewEngine/Svg.fs new file mode 100644 index 0000000..c7b574a --- /dev/null +++ b/lib/src/FSharp.ViewEngine/Svg.fs @@ -0,0 +1,21 @@ +namespace FSharp.ViewEngine + +type Svg = + static member val svg = TagBuilder("svg") with get + static member val path = TagBuilder("path") with get + static member val circle = TagBuilder("circle") with get + static member inline _viewBox (v: string) = { Name = "viewBox"; Value = ValueSome v } + static member inline _width (v: int) = { Name = "width"; Value = ValueSome(string v) } + static member inline _height (v: int) = { Name = "height"; Value = ValueSome(string v) } + static member inline _fill (v: string) = { Name = "fill"; Value = ValueSome v } + static member inline _stroke (v: string) = { Name = "stroke"; Value = ValueSome v } + static member inline _strokeWidth (v: int) = { Name = "stroke-width"; Value = ValueSome(string v) } + static member inline _strokeLinecap (v: string) = { Name = "stroke-linecap"; Value = ValueSome v } + static member inline _strokeLinejoin (v: string) = { Name = "stroke-linejoin"; Value = ValueSome v } + static member inline _fillRule (v: string) = { Name = "fill-rule"; Value = ValueSome v } + static member inline _clipRule (v: string) = { Name = "clip-rule"; Value = ValueSome v } + static member inline _d (v: string) = { Name = "d"; Value = ValueSome v } + static member inline _cx (v: int) = { Name = "cx"; Value = ValueSome(string v) } + static member inline _cy (v: int) = { Name = "cy"; Value = ValueSome(string v) } + static member inline _r (v: int) = { Name = "r"; Value = ValueSome(string v) } + diff --git a/lib/src/FSharp.ViewEngine/Tailwind.fs b/lib/src/FSharp.ViewEngine/Tailwind.fs new file mode 100644 index 0000000..2a85895 --- /dev/null +++ b/lib/src/FSharp.ViewEngine/Tailwind.fs @@ -0,0 +1,25 @@ +namespace FSharp.ViewEngine + +type Tailwind = + static member val elAutocomplete = TagBuilder("el-autocomplete") with get + static member val elOptions = TagBuilder("el-options") with get + static member val elOption = TagBuilder("el-option") with get + static member val elSelect = TagBuilder("el-select") with get + static member val elSelectedContent = TagBuilder("el-selectedcontent") with get + static member val elDropdown = TagBuilder("el-dropdown") with get + static member val elMenu = TagBuilder("el-menu") with get + static member val elDialog = TagBuilder("el-dialog") with get + static member val elDialogBackdrop = TagBuilder("el-dialog-backdrop") with get + static member val elDialogPanel = TagBuilder("el-dialog-panel") with get + static member val elCommandPalette = TagBuilder("el-command-palette") with get + static member val elCommandList = TagBuilder("el-command-list") with get + static member val elCommandGroup = TagBuilder("el-command-group") with get + static member val elCommandPreview = TagBuilder("el-command-preview") with get + static member val elDefaults = TagBuilder("el-defaults") with get + static member val elNoResults = TagBuilder("el-no-results") with get + static member val elTabGroup = TagBuilder("el-tab-group") with get + static member val elTabList = TagBuilder("el-tab-list") with get + static member val elTabPanels = TagBuilder("el-tab-panels") with get + static member inline _popover = { Name = "popover"; Value = ValueNone } + static member inline _anchor (position: string) = { Name = "anchor"; Value = ValueSome position } + diff --git a/fsharp-view-engine/src/FSharp.ViewEngine/paket.references b/lib/src/FSharp.ViewEngine/paket.references similarity index 100% rename from fsharp-view-engine/src/FSharp.ViewEngine/paket.references rename to lib/src/FSharp.ViewEngine/paket.references diff --git a/fsharp-view-engine/src/Tests/Program.fs b/lib/src/Tests/Program.fs similarity index 100% rename from fsharp-view-engine/src/Tests/Program.fs rename to lib/src/Tests/Program.fs diff --git a/lib/src/Tests/Tests.fs b/lib/src/Tests/Tests.fs new file mode 100644 index 0000000..097b0d2 --- /dev/null +++ b/lib/src/Tests/Tests.fs @@ -0,0 +1,173 @@ +module Tests + +open FSharp.ViewEngine +open System.Text +open System.Web +open System.Text.Json +open System.Text.RegularExpressions +open Expecto +open type Html +open type Htmx +open type Alpine +open type Svg +open type Tailwind + +module String = + let replace (oldValue:string) (newValue:string) (s:string) = s.Replace(oldValue, newValue) + let clean (s:string) = Regex.Replace(s, @"\s{2,}|\r|\n|\r\n", "") + +module ViewEngineApi = + open type Html + open type Htmx + open type Alpine + open type Svg + open type Tailwind + + let buildDocument () = + html { + _lang "en" + head { + title "Test" + meta { _charset "utf-8" } + link { _href "/css/compiled.css"; _rel "stylesheet" } + } + body { + _class "bg-gray-50" + div { + _id "page" + _class [ "flex"; "flex-col" ] + h1 { _hxGet "/hello"; _hxTarget "#page"; "Hello" } + h1 { _hxGet "/world"; _hxTarget "#page"; "World" } + } + br + div { + _xShow "showContent" + h2 { "Content" } + p { "Some content" } + raw "

Some more content

" + pre { + _class "language-html" + code { + _class "language-html" + text "

Even more content

" + } + } + ul { + li { "One" } + li { "Two" } + } + a { + _href "https://github.com/meiermade/FSharp.ViewEngine" + _class "rounded-lg text-gray-800 font-semibold flex items-center gap-3 p-1" + svg { + _viewBox "0 0 24 24" + _class "h-6 w-6 fill-current" + path { + _fillRule "evenodd" + _clipRule "evenodd" + _d "M12 2C6.477 2 2 6.463 2 11.97c0 4.404 2.865 8.14 6.839 9.458.5.092.682-.216.682-.48 0-.236-.008-.864-.013-1.695-2.782.602-3.369-1.337-3.369-1.337-.454-1.151-1.11-1.458-1.11-1.458-.908-.618.069-.606.069-.606 1.003.07 1.531 1.027 1.531 1.027.892 1.524 2.341 1.084 2.91.828.092-.643.35-1.083.636-1.332-2.22-.251-4.555-1.107-4.555-4.927 0-1.088.39-1.979 1.029-2.675-.103-.252-.446-1.266.098-2.638 0 0 .84-.268 2.75 1.022A9.607 9.607 0 0 1 12 6.82c.85.004 1.705.114 2.504.336 1.909-1.29 2.747-1.022 2.747-1.022.546 1.372.202 2.386.1 2.638.64.696 1.028 1.587 1.028 2.675 0 3.83-2.339 4.673-4.566 4.92.359.307.678.915.678 1.846 0 1.332-.012 2.407-.012 2.734 0 .267.18.577.688.48 3.97-1.32 6.833-5.054 6.833-9.458C22 6.463 17.522 2 12 2Z" + } + } + raw "Documentation" + } + elSelect { + _name "status" + _value "active" + button { + _type "button" + elSelectedContent { "Active" } + } + elOptions { + _popover + elOption { _value "active"; "Active" } + elOption { _value "inactive"; "Inactive" } + elOption { _value "archived"; "Archived" } + } + } + } + } + } + +// language=HTML +let expectedHtml = """ + + + + Test + + + + +
+

Hello

+

World

+
+
+
+

Content

+

Some content

+

Some more content

+
+                
+                    <p>Even more content</p>
+                
+            
+
    +
  • One
  • +
  • Two
  • +
+ + + + + Documentation + + + + + Active + Inactive + Archived + + +
+ + +""" + +[] +let tests = + testList "ViewEngine Tests" [ + test "ViewEngine should render html document" { + let actual = ViewEngineApi.buildDocument() |> Render.toHtmlDocString + Expect.equal (String.clean actual) (String.clean expectedHtml) "Rendered HTML should match expected" + } + + test "HtmlEncode should match HttpUtility.HtmlEncode" { + let inputs = + [ + "" + "plain" + "" + "Tom & Jerry" + "\"quote\" and 'apostrophe'" + "accent \u00E9" + "emoji \U0001F600" + "mix <&> \u00E9 \U0001F600" + ] + + for input in inputs do + let expected = HttpUtility.HtmlEncode(input) + + let actual = + let sb = StringBuilder() + let el = TextElement(input) + el.Render(sb) + sb.ToString() + + Expect.equal actual expected $"HtmlEncode should match HttpUtility for input: {input}" + } + + ] diff --git a/fsharp-view-engine/src/Tests/Tests.fsproj b/lib/src/Tests/Tests.fsproj similarity index 98% rename from fsharp-view-engine/src/Tests/Tests.fsproj rename to lib/src/Tests/Tests.fsproj index 031f17a..b4f7de8 100644 --- a/fsharp-view-engine/src/Tests/Tests.fsproj +++ b/lib/src/Tests/Tests.fsproj @@ -14,4 +14,4 @@ - \ No newline at end of file + diff --git a/fsharp-view-engine/src/Tests/paket.references b/lib/src/Tests/paket.references similarity index 100% rename from fsharp-view-engine/src/Tests/paket.references rename to lib/src/Tests/paket.references diff --git a/pulumi/src/docker/image.ts b/pulumi/src/docker/image.ts index 319343e..5d0d510 100644 --- a/pulumi/src/docker/image.ts +++ b/pulumi/src/docker/image.ts @@ -9,7 +9,7 @@ export const image = new docker.Image(config.identifier, { tags: [pulumi.interpolate `${repo.repositoryUrl}:latest`], push: true, context: { - location: path.join(config.rootDir, 'fsharp-view-engine'), + location: path.join(config.rootDir, 'docs'), }, platforms: ['linux/arm64'], registries: [{ From 3d5b311cec754e0a8147b0e0e60cecd279a25a6c Mon Sep 17 00:00:00 2001 From: Andrew Meier Date: Fri, 6 Feb 2026 07:28:53 -0500 Subject: [PATCH 2/5] Fix fake.sh executable permissions --- docs/fake.sh | 0 lib/fake.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 docs/fake.sh mode change 100644 => 100755 lib/fake.sh diff --git a/docs/fake.sh b/docs/fake.sh old mode 100644 new mode 100755 diff --git a/lib/fake.sh b/lib/fake.sh old mode 100644 new mode 100755 From 3e12a76c1f3b43859feccbbb7c2e78080f6eb302 Mon Sep 17 00:00:00 2001 From: Andrew Meier Date: Fri, 6 Feb 2026 07:46:56 -0500 Subject: [PATCH 3/5] Multi-target library and tests for net8.0, net9.0, net10.0 --- .github/workflows/pull_request.yml | 5 ++++- .github/workflows/release.yml | 5 ++++- lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj | 2 +- lib/src/Tests/Tests.fsproj | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index fc650f9..a355cb3 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -12,7 +12,10 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v5 with: - dotnet-version: 10.0.x + dotnet-version: | + 8.0.x + 9.0.x + 10.0.x - name: Install Tools run: dotnet tool restore working-directory: ./lib diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 094652d..1d0478e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,10 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v5 with: - dotnet-version: 10.0.x + dotnet-version: | + 8.0.x + 9.0.x + 10.0.x - name: Restore Tools run: dotnet tool restore working-directory: ./lib diff --git a/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj b/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj index ee59546..87e23ef 100644 --- a/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj +++ b/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj @@ -1,7 +1,7 @@ - net10.0 + net8.0;net9.0;net10.0 FSharp.ViewEngine LICENSE README.md diff --git a/lib/src/Tests/Tests.fsproj b/lib/src/Tests/Tests.fsproj index b4f7de8..fa5df33 100644 --- a/lib/src/Tests/Tests.fsproj +++ b/lib/src/Tests/Tests.fsproj @@ -1,7 +1,7 @@ Exe - net10.0 + net8.0;net9.0;net10.0 false false From 3a87203b83b0c0c9b4443eb4c4c9af1e76236dd4 Mon Sep 17 00:00:00 2001 From: Andrew Meier Date: Fri, 6 Feb 2026 07:48:00 -0500 Subject: [PATCH 4/5] Add Oxpecker.ViewEngine to inspiration credits --- README.md | 5 +++-- docs/src/Docs/docs/home.md | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b200af7..312700e 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,9 @@

# FSharp.ViewEngine -View engine for F#. Inspired by [Giraffe.ViewEngine](https://github.com/giraffe-fsharp/Giraffe.ViewEngine) and -[Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine). +View engine for F#. Inspired by [Giraffe.ViewEngine](https://github.com/giraffe-fsharp/Giraffe.ViewEngine), +[Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine), and +[Oxpecker.ViewEngine](https://github.com/Lanayx/Oxpecker). Documentation site built using FSharp.ViewEngine available at [https://fsharpviewengine.meiermade.com](https://fsharpviewengine.meiermade.com). > See [docs/src/Docs](./docs/src/Docs) for the source code. diff --git a/docs/src/Docs/docs/home.md b/docs/src/Docs/docs/home.md index 017abe2..f119e58 100644 --- a/docs/src/Docs/docs/home.md +++ b/docs/src/Docs/docs/home.md @@ -1,6 +1,6 @@ # FSharp.ViewEngine Documentation -A powerful F# view engine for building HTML with type safety and composability. Inspired by Giraffe.ViewEngine and Feliz.ViewEngine. +A powerful F# view engine for building HTML with type safety and composability. Inspired by Giraffe.ViewEngine, Feliz.ViewEngine, and Oxpecker.ViewEngine. ## Key Features From 6b7c509085ead2bc2f4a1134b6b1c8652113903b Mon Sep 17 00:00:00 2001 From: Andrew Meier Date: Fri, 6 Feb 2026 07:56:15 -0500 Subject: [PATCH 5/5] Move LICENSE to repo root, fix package file refs, run tests per TFM --- lib/LICENSE => LICENSE | 0 lib/src/Build/Program.fs | 7 +- .../FSharp.ViewEngine.fsproj | 4 +- lib/src/FSharp.ViewEngine/README.md | 77 ------------------- 4 files changed, 7 insertions(+), 81 deletions(-) rename lib/LICENSE => LICENSE (100%) delete mode 100644 lib/src/FSharp.ViewEngine/README.md diff --git a/lib/LICENSE b/LICENSE similarity index 100% rename from lib/LICENSE rename to LICENSE diff --git a/lib/src/Build/Program.fs b/lib/src/Build/Program.fs index 5e807ef..4bbfe70 100644 --- a/lib/src/Build/Program.fs +++ b/lib/src/Build/Program.fs @@ -46,8 +46,11 @@ let getVersion () = Target.create "CleanNugets" <| fun _ -> Shell.cleanDir nugetsDir Target.create "Test" <| fun _ -> - dotnet testsDir ["test"] - |> Async.RunSynchronously + ["net8.0"; "net9.0"; "net10.0"] + |> List.iter (fun tfm -> + dotnet testsDir ["run"; "--framework"; tfm] + |> Async.RunSynchronously + ) Target.create "Pack" (fun _ -> let project = srcDir "FSharp.ViewEngine" "FSharp.ViewEngine.fsproj" diff --git a/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj b/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj index 87e23ef..86fb3b7 100644 --- a/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj +++ b/lib/src/FSharp.ViewEngine/FSharp.ViewEngine.fsproj @@ -17,8 +17,8 @@ - - + + diff --git a/lib/src/FSharp.ViewEngine/README.md b/lib/src/FSharp.ViewEngine/README.md deleted file mode 100644 index 25fd83b..0000000 --- a/lib/src/FSharp.ViewEngine/README.md +++ /dev/null @@ -1,77 +0,0 @@ -[![Release](https://github.com/meiermade/FSharp.ViewEngine/actions/workflows/release.yml/badge.svg)](https://github.com/meiermade/FSharp.ViewEngine/actions/workflows/release.yml) - -# FSharp.ViewEngine -View engine for F#. Inspired by [Giraffe.ViewEngine](https://github.com/giraffe-fsharp/Giraffe.ViewEngine) and -[Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine). -Documentation site built using FSharp.ViewEngine available at [https://fsharpviewengine.meiermade.com](https://fsharpviewengine.meiermade.com). -> See [App](./src/App) for the source code. - -## Installation -Add the core view engine package. -```shell -dotnet add package FSharp.ViewEngine -``` - -## Usage -```fsharp -open FSharp.ViewEngine -open type Html -open type Htmx -open type Alpine -open type Tailwind - -html { - _lang "en" - head { - title "Test" - meta { _charset "utf-8" } - link { _href "/css/compiled.css"; _rel "stylesheet" } - } - body { - _xData "{showContent: false}" - _class "bg-gray-50" - div { - _id "page" - _class [ "flex"; "flex-col" ] - h1 { _hxGet "/hello"; _hxTarget "#page"; "Hello" } - h1 { _hxGet "/world"; _hxTarget "#page"; "World" } - } - br - div { - _xShow "showContent" - h2 { "Content" } - p { "Some content" } - ul { - li { "One" } - li { "Two" } - } - } - } -} -|> Render.toHtmlDocString -``` -```html - - - - Test - - - - -
-

Hello

-

World

-
-
-
-

Content

-

Some content

-
    -
  • One
  • -
  • Two
  • -
-
- - -```