Skip to content

Commit

Permalink
Set up website pinevm.org
Browse files Browse the repository at this point in the history
  • Loading branch information
Viir committed Apr 14, 2024
1 parent a436089 commit 14a38d0
Show file tree
Hide file tree
Showing 23 changed files with 2,099 additions and 0 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/build-and-publish-website-pinevm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Build and publish website PineVM

on:
workflow_dispatch:
push:
paths:
- "implement/website/pinevm/**"
- ".github/workflows/build-and-publish-website-pinevm.yml"

jobs:
build-and-deploy:

runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4

- name: download build tool
run: |
pwsh -nologo -noprofile -command "Invoke-WebRequest 'https://github.com/elm-time/elm-time/releases/download/v0.1.6/elm-time-bin-v0.1.6-linux-x64.zip' -OutFile elm-time-linux-x64.zip"
pwsh -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('elm-time-linux-x64.zip','./elm-time');}"
- name: install build tool
run: |
chmod +x ./elm-time/elm-time
sudo ./elm-time/elm-time install
- name: Build for Netlify
working-directory: ./implement/website/pinevm
run: |
elm-time make src/Netlify.elm --output=netlify.zip
pwsh -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('netlify.zip','./out/netlify/docs');}"
- name: Deploy to Netlify
working-directory: ./implement/website/pinevm
run: |
npm install netlify-cli --save-dev
netlify deploy --dir ./out/netlify/docs --site pinevm-org --alias preview --auth ${{ secrets.WEBSITE_NETLIFY_AUTH_TOKEN }}
1 change: 1 addition & 0 deletions implement/website/pinevm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/elm-stuff/
5 changes: 5 additions & 0 deletions implement/website/pinevm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This directory contains the program to build the website at [pinevm.org](https://pinevm.org)

The `blobMain` function in the [`Netlify` module](./src/Netlify.elm) builds the static website for deploying on Netlify.

The `Backend.Main` module contains an additional entry point to support local testing.
9 changes: 9 additions & 0 deletions implement/website/pinevm/elm-analyse.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"checks": {
"SingleFieldRecord": false,
"MultiLineRecordFormatting": false,
"UseConsOverConcat": false,
"MapNothingToNothing": false,
"ExposeAll": false
}
}
47 changes: 47 additions & 0 deletions implement/website/pinevm/elm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"type": "application",
"source-directories": [
"src"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"agu-z/elm-zip": "3.0.1",
"avh4/elm-color": "1.0.0",
"danfishgold/base64-bytes": "1.1.0",
"elm/browser": "1.0.2",
"elm/bytes": "1.0.8",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/json": "1.1.3",
"elm/parser": "1.1.0",
"elm/regex": "1.0.0",
"elm/svg": "1.0.1",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm-community/list-extra": "8.7.0",
"elm-community/result-extra": "2.4.0",
"ianmackenzie/elm-geometry": "4.0.0",
"ianmackenzie/elm-units": "2.10.0",
"lattyware/elm-fontawesome": "7.0.0",
"mdgriffith/elm-ui": "1.1.8",
"rtfeldman/elm-hex": "1.0.0"
},
"indirect": {
"elm/random": "1.0.0",
"elm/virtual-dom": "1.0.3",
"folkertdev/elm-flate": "2.0.5",
"ianmackenzie/elm-1d-parameter": "1.0.1",
"ianmackenzie/elm-float-extra": "1.1.0",
"ianmackenzie/elm-interval": "3.1.0",
"ianmackenzie/elm-triangular-mesh": "1.1.0",
"ianmackenzie/elm-units-interval": "3.2.0",
"justinmimbs/date": "4.1.0",
"justinmimbs/time-extra": "1.2.0"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}
3 changes: 3 additions & 0 deletions implement/website/pinevm/netlify-publish/_redirects
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://docs.netlify.com/routing/redirects/rewrites-proxies/#history-pushstate-and-single-page-apps

/* /index.html 200
161 changes: 161 additions & 0 deletions implement/website/pinevm/src/Backend/Main.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
module Backend.Main exposing
( State
, webServiceMain
)

import Base64
import Build
import Bytes.Encode
import FileTree
import Platform.WebService
import Url


type alias State =
{}


webServiceMain : Platform.WebService.WebServiceConfig State
webServiceMain =
{ init = ( {}, [] )
, subscriptions = subscriptions
}


subscriptions : State -> Platform.WebService.Subscriptions State
subscriptions _ =
{ httpRequest = updateForHttpRequestEvent
, posixTimeIsPast = Nothing
}


updateForHttpRequestEvent :
Platform.WebService.HttpRequestEventStruct
-> State
-> ( State, Platform.WebService.Commands State )
updateForHttpRequestEvent httpRequestEvent stateBefore =
let
bodyFromString =
Bytes.Encode.string >> Bytes.Encode.encode >> Base64.fromBytes

staticContentHttpHeaders { contentType, contentEncoding } =
{ cacheMaxAgeMinutes = Just (60 * 24)
, contentType = contentType
, contentEncoding = contentEncoding
}

httpResponseOkWithStringContent stringContent httpResponseHeaders =
httpResponseOkWithBodyAsBase64 (bodyFromString stringContent) httpResponseHeaders

httpResponseOkWithBodyAsBase64 bodyAsBase64 contentConfig =
{ statusCode = 200
, bodyAsBase64 = bodyAsBase64
, headersToAdd =
[ ( "Cache-Control"
, contentConfig.cacheMaxAgeMinutes
|> Maybe.map (\maxAgeMinutes -> "public, max-age=" ++ String.fromInt (maxAgeMinutes * 60))
)
, ( "Content-Type", Just contentConfig.contentType )
, ( "Content-Encoding", contentConfig.contentEncoding )
]
|> List.concatMap
(\( name, maybeValue ) ->
maybeValue
|> Maybe.map (\value -> [ { name = name, values = [ value ] } ])
|> Maybe.withDefault []
)
}

frontendHtmlDocumentResponse frontendConfig =
httpResponseOkWithStringContent (Build.frontendHtmlDocument frontendConfig)
(staticContentHttpHeaders { contentType = "text/html", contentEncoding = Nothing })

httpHeaderContentTypeFromFilePath : List String -> Maybe String
httpHeaderContentTypeFromFilePath filePath =
case
filePath
|> List.reverse
|> List.head
|> Maybe.map (String.split ".")
|> Maybe.withDefault []
|> List.reverse
of
[] ->
Nothing

fileNameEnding :: fileNameOtherParts ->
if fileNameOtherParts == [] then
Nothing

else
case fileNameEnding of
"css" ->
Just "text/css"

"js" ->
Just "application/javascript"

"png" ->
Just "image/png"

"svg" ->
Just "image/svg+xml"

_ ->
Nothing

cachedResponse { filePath } bodyAsBase64 =
{ statusCode = 200
, bodyAsBase64 = bodyAsBase64
, headersToAdd =
[ [ { name = "Cache-Control", values = [ "public, max-age=3600" ] }
]
, httpHeaderContentTypeFromFilePath filePath
|> Maybe.map (\contentType -> [ { name = "Content-Type", values = [ contentType ] } ])
|> Maybe.withDefault []
]
|> List.concat
}

response =
if (httpRequestEvent.request.method |> String.toLower) /= "get" then
{ statusCode = 405
, bodyAsBase64 = Nothing
, headersToAdd = []
}

else
case Url.fromString httpRequestEvent.request.uri of
Nothing ->
{ statusCode = 500
, bodyAsBase64 =
"Failed to parse URL"
|> Bytes.Encode.string
|> Bytes.Encode.encode
|> Base64.fromBytes
, headersToAdd = []
}

Just url ->
case
Build.fileTree
|> FileTree.flatListOfBlobsFromFileTreeNode
|> List.filter (Tuple.first >> (==) (String.split "/" url.path |> List.filter (String.isEmpty >> not)))
|> List.head
of
Just ( filePath, matchingFile ) ->
matchingFile.base64
|> Just
|> cachedResponse { filePath = filePath }

Nothing ->
frontendHtmlDocumentResponse { debug = False }

httpResponse =
{ httpRequestId = httpRequestEvent.httpRequestId
, response = response
}
in
( stateBefore
, [ Platform.WebService.RespondToHttpRequest httpResponse ]
)
9 changes: 9 additions & 0 deletions implement/website/pinevm/src/Backend/MigrateState.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Backend.MigrateState exposing (migrate)

import Backend.Main
import Platform.WebService


migrate : Backend.Main.State -> ( Backend.Main.State, Platform.WebService.Commands Backend.Main.State )
migrate state =
( state, [] )
76 changes: 76 additions & 0 deletions implement/website/pinevm/src/Build.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
module Build exposing (..)

import Base64
import CompilationInterface.ElmMake
import CompilationInterface.SourceFiles
import FileTree


fileTree : FileTree.FileTreeNode { base64 : String }
fileTree =
CompilationInterface.SourceFiles.file_tree____static_content
|> mapFileTreeNodeFromSource
|> FileTree.setNodeAtPathInSortedFileTree
( [ elmMadeScriptFileNameDefault ]
, FileTree.BlobNode { base64 = CompilationInterface.ElmMake.elm_make____src_Frontend_Main_elm.javascript.base64 }
)
|> FileTree.setNodeAtPathInSortedFileTree
( [ "index.html" ]
, FileTree.BlobNode
{ base64 =
frontendHtmlDocument { debug = False }
|> Base64.fromString
|> Maybe.withDefault "Failed to encode as base64"
}
)


mapFileTreeNodeFromSource : CompilationInterface.SourceFiles.FileTreeNode a -> FileTree.FileTreeNode a
mapFileTreeNodeFromSource node =
case node of
CompilationInterface.SourceFiles.BlobNode blob ->
FileTree.BlobNode blob

CompilationInterface.SourceFiles.TreeNode tree ->
tree |> List.map (Tuple.mapSecond mapFileTreeNodeFromSource) |> FileTree.TreeNode


frontendHtmlDocument : { debug : Bool } -> String
frontendHtmlDocument { debug } =
let
elmMadeScriptFileName =
elmMadeScriptFileNameDefault
in
"""
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Pine, the Elm runtime environment</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<script type="text/javascript" src="""
++ elmMadeScriptFileName
++ """></script>
</head>
<body>
<div id="elm-app-container"></div>
</body>
<script type="text/javascript">
var app = Elm.Frontend.Main.init({
node: document.getElementById('elm-app-container')
});
</script>
</html>
"""


elmMadeScriptFileNameDefault : String
elmMadeScriptFileNameDefault =
"elm.js"
11 changes: 11 additions & 0 deletions implement/website/pinevm/src/CompilationInterface/ElmMake.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module CompilationInterface.ElmMake exposing (..)

{-| For documentation of the compilation interface, see <https://github.com/elm-time/elm-time/blob/main/guide/how-to-configure-and-deploy-an-elm-backend-app.md#compilationinterfaceelmmake-elm-module>
-}


elm_make____src_Frontend_Main_elm : { debug : { javascript : { base64 : String } }, javascript : { base64 : String } }
elm_make____src_Frontend_Main_elm =
{ javascript = { base64 = "The compiler replaces this declaration." }
, debug = { javascript = { base64 = "The compiler replaces this declaration." } }
}
19 changes: 19 additions & 0 deletions implement/website/pinevm/src/CompilationInterface/SourceFiles.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module CompilationInterface.SourceFiles exposing (..)

{-| For documentation of the compilation interface, see <https://github.com/elm-time/elm-time/blob/main/guide/how-to-configure-and-deploy-an-elm-backend-app.md#compilationinterfacesourcefiles-elm-module>
-}


type FileTreeNode blobStructure
= BlobNode blobStructure
| TreeNode (List ( String, FileTreeNode blobStructure ))


file_tree____static_content : FileTreeNode { base64 : String }
file_tree____static_content =
TreeNode []


file_tree____netlify_publish : FileTreeNode { base64 : String }
file_tree____netlify_publish =
TreeNode []
Loading

0 comments on commit 14a38d0

Please sign in to comment.