diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | TJLaskuri.Core/TJLaskuri.Core.fsproj | 5 | ||||
| -rw-r--r-- | TJLaskuri.Core/Views.fs | 88 | ||||
| -rw-r--r-- | TJLaskuri.Frontend/App.fs | 34 | ||||
| -rw-r--r-- | TJLaskuri.Frontend/index.html | 3 | ||||
| -rw-r--r-- | TJLaskuri.Frontend/vite.config.ts | 12 | ||||
| -rw-r--r-- | TJLaskuri.Web/Modules/Index.fs | 31 | ||||
| -rw-r--r-- | TJLaskuri.Web/Program.fs | 38 | ||||
| -rw-r--r-- | TJLaskuri.Web/TJLaskuri.Web.fsproj | 39 | ||||
| -rw-r--r-- | TJLaskuri.Web/wwwroot/styles.css | 72 |
10 files changed, 278 insertions, 47 deletions
@@ -1,5 +1,6 @@ bin/ obj/ +core # Fable *.fs.js @@ -7,3 +8,5 @@ fable_modules/ node_modules/ dist/ *.fable-temp.csproj + +TJLaskuri.Web/wwwroot/js/app.js diff --git a/TJLaskuri.Core/TJLaskuri.Core.fsproj b/TJLaskuri.Core/TJLaskuri.Core.fsproj index c3b606a..bc6029f 100644 --- a/TJLaskuri.Core/TJLaskuri.Core.fsproj +++ b/TJLaskuri.Core/TJLaskuri.Core.fsproj @@ -7,7 +7,12 @@ <ItemGroup> <Compile Include="Types.fs" /> + <Compile Include="Views.fs" /> <Compile Include="Library.fs" /> </ItemGroup> + <ItemGroup> + <PackageReference Include="Falco.Markup" Version="1.2.0" /> + </ItemGroup> + </Project> diff --git a/TJLaskuri.Core/Views.fs b/TJLaskuri.Core/Views.fs new file mode 100644 index 0000000..939acec --- /dev/null +++ b/TJLaskuri.Core/Views.fs @@ -0,0 +1,88 @@ +namespace TJLaskuri.Core.Views + +open System +open Falco.Markup +open Elem +open Attr +open Text + +module Document = + let view documentBody = + html [ lang "fi" ] [ + head [] [ + meta [ charset "utf-8" ] + meta [ name "viewport"; content "width=device-width" ] + Elem.title [] [ raw "TJ-laskuri" ] + script [ type' "module"; src "/js/app.js" ] [] + link [ rel "stylesheet"; href "/styles.css" ] + ] + body [] [ + documentBody + ] + ] + +module Main = + type Model = { + TimeLeft : TimeSpan + TimeCompleted : TimeSpan + } + + let view model = + main [] [ + div [ class' "counter" ] [ + Elem.span [ class' "counter_title" ] [ + raw "Tänään jäljellä" + ] + Elem.span [ class' "counter_value" ] [ + enc (string <| Math.Ceiling model.TimeLeft.TotalDays) + ] + Elem.span [ class' "counter_mornings" ] [ + raw " aamua" + ] + ] + + div [ class' "progress-bar" ] [ + let p = 100.0 * (1.0 - model.TimeLeft / (model.TimeLeft + model.TimeCompleted)) + let cssWidth = sprintf "%s%%" (p.ToString("F2")) + + div [ + class' "progress-bar_value" + style <| + sprintf "background-color: green; width: %s" + cssWidth + ] [ + span <| sprintf "%s %%" (p.ToString("F2")) + ] + ] + + Elem.p [ + style "text-align: center; font-size: 1.5rem;" + ] [ + enc "2/25 347" + ] + + // div [] [ + // Elem.label [ for' "kontingent-select" ] [ raw "Saapumiserä:" ] + // select [ id "kontingent-select" ] [ + // option [ value "1/25" ] [ enc "1/25" ] + // option [ value "2/25" ] [ enc "2/25" ] + // option [ value "1/26" ] [ enc "1/26" ] + // option [ value "2/26" ] [ enc "2/26" ] + // ] + // ] + + // div [] [ + // Elem.p [] [ + // span "Tunteina" + // enc (string model.TimeLeft.TotalHours) + // ] + // Elem.p [] [ + // span "Sekunteina" + // enc (string model.TimeLeft.TotalSeconds) + // ] + // Elem.p [] [ + // span "Aamuja ohi " + // enc (string <| Math.Floor model.TimeCompleted.TotalDays) + // ] + // ] + ] diff --git a/TJLaskuri.Frontend/App.fs b/TJLaskuri.Frontend/App.fs index d19c455..c83ed6a 100644 --- a/TJLaskuri.Frontend/App.fs +++ b/TJLaskuri.Frontend/App.fs @@ -9,25 +9,25 @@ let k = kontingent 2 2025 let st = ThreeFourSeven let currentTime = - DateTime(2025, 7, 5) + // DateTime(2025, 7, 5) // DateTime(2026, 6, 18) // DateTime(2026, 6, 17) - // DateTime.Today + DateTime.Today // DateTime.Now // Domain.getStartDate k |> Option.get -currentTime -|> Domain.getTimeLeft k st -|> function - | Some left -> - let el = document.createElement "p" - el.innerHTML <- sprintf "Tänään jäljellä:<br>%O" left.TotalDays - document.body.appendChild(el) |> ignore - | None -> - printfn "Error: unknown kontingent" - -let startDate = Domain.getStartDate k |> Option.get -let el = document.createElement "p" -el.innerHTML <- sprintf "Aloituspäivä: %O<br>Aamuja ohi %d" - startDate (Domain.getTimeCompleted k currentTime |> Option.get).Days -document.body.appendChild(el) |> ignore +// currentTime +// |> Domain.getTimeLeft k st +// |> function +// | Some left -> +// let el = document.createElement "p" +// el.innerHTML <- sprintf "Tänään jäljellä:<br>%O<br>aamua" left.TotalDays +// document.body.appendChild(el) |> ignore +// | None -> +// printfn "Error: unknown kontingent" +// +// let startDate = Domain.getStartDate k |> Option.get +// let el = document.createElement "p" +// el.innerHTML <- sprintf "Aloituspäivä: %O<br>Aamuja ohi %d" +// startDate (Domain.getTimeCompleted k currentTime |> Option.get).Days +// document.body.appendChild(el) |> ignore diff --git a/TJLaskuri.Frontend/index.html b/TJLaskuri.Frontend/index.html index 9fadce0..79b1c82 100644 --- a/TJLaskuri.Frontend/index.html +++ b/TJLaskuri.Frontend/index.html @@ -3,10 +3,9 @@ <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width" /> - <title>TJ-laskuri</title> + <title>TJ-laskuri</title> </head> <body> <script type="module" src="/App.fs.js"></script> </body> </html> - diff --git a/TJLaskuri.Frontend/vite.config.ts b/TJLaskuri.Frontend/vite.config.ts index 37b081b..2dd7341 100644 --- a/TJLaskuri.Frontend/vite.config.ts +++ b/TJLaskuri.Frontend/vite.config.ts @@ -8,6 +8,18 @@ export default defineConfig({ ignored: [ "**/*.fs" // Don't watch F# files ] + }, + }, + build: { + rollupOptions: { + output: { + // Remove hash from output so we can copy the file + // to the content root of the web app + entryFileNames: `[name].js`, + + // chunkFileNames: `[name].js`, + // assetFileNames: `[name].[ext]` + } } } }) diff --git a/TJLaskuri.Web/Modules/Index.fs b/TJLaskuri.Web/Modules/Index.fs new file mode 100644 index 0000000..7623779 --- /dev/null +++ b/TJLaskuri.Web/Modules/Index.fs @@ -0,0 +1,31 @@ +module TJLaskuri.Web.Modules.Index + +open System +open Falco +open TJLaskuri.Core + +[<AutoOpen>] +module Views = + open TJLaskuri.Core.Views + + type Model = { + Counter : Main.Model + } + + let view model = + Main.view model.Counter + |> Document.view + +let get : HttpHandler = + fun ctx -> + let time = DateTime.Now + let kontingent = kontingent 2 2025 + let timeLeft = Domain.getTimeLeft kontingent ThreeFourSeven time |> Option.get + let completed = Domain.getTimeCompleted kontingent time |> Option.get + + view { + Counter = { + TimeLeft = timeLeft + TimeCompleted = completed + } + } |> Response.ofHtml <| ctx diff --git a/TJLaskuri.Web/Program.fs b/TJLaskuri.Web/Program.fs index fb776e0..831d8a8 100644 --- a/TJLaskuri.Web/Program.fs +++ b/TJLaskuri.Web/Program.fs @@ -1,15 +1,23 @@ -open System
-open Microsoft.AspNetCore.Builder
-open Microsoft.Extensions.Hosting
-
-[<EntryPoint>]
-let main args =
- let builder = WebApplication.CreateBuilder(args)
- let app = builder.Build()
-
- app.MapGet("/", Func<string>(fun () -> "Hello World!")) |> ignore
-
- app.Run()
-
- 0 // Exit code
-
+open Microsoft.AspNetCore.Builder +open Microsoft.Extensions.Hosting +open Falco +open Falco.Routing +open TJLaskuri.Web.Modules + +let endpoints = [ + get "/" Index.get + ] + +[<EntryPoint>] +let main args = + let builder = WebApplication.CreateBuilder(args) + let app = builder.Build() + + app.MapStaticAssets() |> ignore + + app + .UseRouting() + .UseFalco(endpoints) + .Run() + + 0 // Exit code diff --git a/TJLaskuri.Web/TJLaskuri.Web.fsproj b/TJLaskuri.Web/TJLaskuri.Web.fsproj index 6ddf66a..6cd0654 100644 --- a/TJLaskuri.Web/TJLaskuri.Web.fsproj +++ b/TJLaskuri.Web/TJLaskuri.Web.fsproj @@ -1,15 +1,28 @@ -<Project Sdk="Microsoft.NET.Sdk.Web">
-
- <PropertyGroup>
- <TargetFramework>net9.0</TargetFramework>
- </PropertyGroup>
-
- <ItemGroup>
- <Compile Include="Program.fs" />
- </ItemGroup>
-
+<Project Sdk="Microsoft.NET.Sdk.Web"> + + <PropertyGroup> + <TargetFramework>net9.0</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <Compile Include="Modules/Index.fs" /> + <Compile Include="Program.fs" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include="..\TJLaskuri.Core\TJLaskuri.Core.fsproj" /> - </ItemGroup>
-
-</Project>
+ </ItemGroup> + + <ItemGroup> + <PackageReference Include="Falco" Version="5.0.2" /> + </ItemGroup> + + <Target Name="CopyStaticAssets" BeforeTargets="Build"> + <Message Text="Copying static assets" /> + <Copy + SourceFiles="../TJLaskuri.Frontend/dist/index.js" + DestinationFiles="wwwroot/js/app.js" + /> + </Target> + +</Project> diff --git a/TJLaskuri.Web/wwwroot/styles.css b/TJLaskuri.Web/wwwroot/styles.css new file mode 100644 index 0000000..66a6ef5 --- /dev/null +++ b/TJLaskuri.Web/wwwroot/styles.css @@ -0,0 +1,72 @@ +* { + box-sizing: border-box; + max-width: none; +} + +html { + font-size: 100%; +} + +@font-face { + font-family: 'Cooper Black'; + font-weight: normal; + font-style: normal; + font-display: swap; + src: + local('Cooper Black'), + url('https://cdn.jsdelivr.net/npm/fonts-archive-cooper-black/CooperBlack-Regular.woff2') format('woff2'), + url('https://cdn.jsdelivr.net/npm/fonts-archive-cooper-black/CooperBlack-Regular.woff') format('woff'), + url('https://cdn.jsdelivr.net/npm/fonts-archive-cooper-black/CooperBlack-Regular.otf') format('opentype'), + url('https://cdn.jsdelivr.net/npm/fonts-archive-cooper-black/CooperBlack-Regular.ttf') format('truetype'); +} + +body { + font-family: "Cooper Black", serif; + font-weight: bold; + max-width: 50rem; + margin: 0 auto; + padding: 1rem; +} + +.counter { + padding: 2rem; + text-align: center; + font-size: 2.5rem; + font-weight: 900; +} + +.counter_title { + display: block; + font-size: 1.2em; +} + +.counter_value { + display: block; + margin: 0; + font-weight: 900; + font-size: 2.5em; +} + +.counter_mornings { + display: block; +} + +.progress-bar { + height: 25px; + border-radius: 5px; + border: 1px solid black; + background-color: lightgrey; +} + +.progress-bar_value { + color: white; + height: 100%; + display: flex; + padding: 0 10px; + justify-content: flex-end; + align-items: center; + white-space: nowrap; + text-align: center; + border-radius: 5px; + min-width: 0; +} |
