first commit
This commit is contained in:
commit
a9af55fb0b
9 changed files with 238 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
.make.*
|
||||
app.js
|
||||
elm-stuff/
|
||||
error.txt
|
2
.watchmakerc
Normal file
2
.watchmakerc
Normal file
|
@ -0,0 +1,2 @@
|
|||
extensions:
|
||||
- .elm
|
11
Makefile
Normal file
11
Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
DIRNAME=$(notdir $(CURDIR))
|
||||
|
||||
ELMS=$(wildcard src/*.elm)
|
||||
|
||||
app.js: src/App.elm $(ELMS)
|
||||
-elm make $< --output=$@ 2> error.txt
|
||||
@cat error.txt
|
||||
|
||||
upload: app.js index.html style.css
|
||||
rsync -avz . clpland:~/domains/somethingorotherwhatever.com/html/$(DIRNAME)
|
||||
@echo "Uploaded to https://somethingorotherwhatever.com/$(DIRNAME)"
|
25
elm.json
Normal file
25
elm.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"type": "application",
|
||||
"source-directories": [
|
||||
"src"
|
||||
],
|
||||
"elm-version": "0.19.1",
|
||||
"dependencies": {
|
||||
"direct": {
|
||||
"elm/browser": "1.0.2",
|
||||
"elm/core": "1.0.5",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/svg": "1.0.1",
|
||||
"elm/time": "1.0.0"
|
||||
},
|
||||
"indirect": {
|
||||
"elm/json": "1.1.3",
|
||||
"elm/url": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.3"
|
||||
}
|
||||
},
|
||||
"test-dependencies": {
|
||||
"direct": {},
|
||||
"indirect": {}
|
||||
}
|
||||
}
|
23
index.html
Normal file
23
index.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Elm app by clp</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1>Elm app by clp</h1>
|
||||
</header>
|
||||
<main>
|
||||
<p>This is an app which will either load succesfully, and you'll wonder whether you saw this text at all, or fail ignominiously, showing you only this text.</p>
|
||||
<p>On balance of probabilities: I'm sorry I couldn't be bothered to make this work for you.</p>
|
||||
</main>
|
||||
<footer>Made by <a href="https://somethingorotherwhatever.com">clp</a></footer>
|
||||
|
||||
<script src="app.js"></script>
|
||||
<script src="load-app.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
10
load-app.js
Normal file
10
load-app.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import show_error from './show-error.mjs';
|
||||
async function init_app() {
|
||||
const compilation_error = await show_error;
|
||||
if(compilation_error) {
|
||||
return;
|
||||
}
|
||||
const app = Elm.App.init({node: document.body, flags: {}});
|
||||
}
|
||||
|
||||
init_app();
|
21
show-error.mjs
Normal file
21
show-error.mjs
Normal file
|
@ -0,0 +1,21 @@
|
|||
export default fetch('/error.txt').then(r=>{
|
||||
if(r.ok) {
|
||||
return r.text();
|
||||
} else {
|
||||
throw('');
|
||||
}
|
||||
}).then(text => {
|
||||
if(!text) {
|
||||
return false;
|
||||
}
|
||||
document.body.innerHTML = '';
|
||||
const error_show = document.createElement('pre');
|
||||
error_show.setAttribute('id','build-error');
|
||||
error_show.style.background = 'black';
|
||||
error_show.style.color = 'white';
|
||||
error_show.style.padding = '1em';
|
||||
error_show.style['font-size'] = '16px';
|
||||
error_show.textContent = text;
|
||||
document.body.appendChild(error_show);
|
||||
return true;
|
||||
}).catch(e => false);
|
128
src/App.elm
Normal file
128
src/App.elm
Normal file
|
@ -0,0 +1,128 @@
|
|||
module App exposing (..)
|
||||
|
||||
import Browser
|
||||
import Html as H exposing (Html)
|
||||
import Html.Attributes as HA
|
||||
import Html.Events as HE
|
||||
import Svg
|
||||
import Svg.Attributes as SA
|
||||
import Time exposing (Posix)
|
||||
|
||||
main = Browser.document
|
||||
{ init = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, view = view
|
||||
}
|
||||
|
||||
type alias Model = { time: Posix }
|
||||
|
||||
init_model = { time = Time.millisToPosix 0 }
|
||||
|
||||
type Msg
|
||||
= Tick Posix
|
||||
|
||||
init : () -> (Model, Cmd msg)
|
||||
init _ = (init_model, Cmd.none)
|
||||
|
||||
update msg model = case msg of
|
||||
Tick time -> ({ model | time = time }, Cmd.none)
|
||||
|
||||
subscriptions model = Time.every 50 Tick
|
||||
|
||||
ff = String.fromFloat
|
||||
|
||||
view model =
|
||||
let
|
||||
time = model.time
|
||||
zone = Time.utc
|
||||
now = (toFloat <| Time.posixToMillis time) / 1000
|
||||
|
||||
num_arms = 10
|
||||
|
||||
r_for n = 1 - 0.9*n/num_arms
|
||||
period_for n = 10 ^ ((toFloat num_arms) - n)
|
||||
|
||||
arm n =
|
||||
let
|
||||
period = period_for n
|
||||
an = (now / period - 0.25) * 2 * pi
|
||||
r = r_for n
|
||||
in
|
||||
Svg.line
|
||||
[ SA.x1 "0"
|
||||
, SA.y1 "0"
|
||||
, SA.x2 <| ff <| (*) r <| cos an
|
||||
, SA.y2 <| ff <| (*) r <| sin an
|
||||
, SA.strokeWidth "0.01"
|
||||
, SA.stroke "black"
|
||||
-- , SA.strokeDasharray <| (ff dash) ++ " " ++ (ff dash)
|
||||
]
|
||||
[]
|
||||
arms = List.map (toFloat >> arm) (List.range 0 num_arms)
|
||||
|
||||
tick ii =
|
||||
let
|
||||
i = toFloat ii
|
||||
an = 2 * pi * (i / 10 - 0.25)
|
||||
r = 1
|
||||
in
|
||||
Svg.line
|
||||
[ SA.x1 "0"
|
||||
, SA.y1 "0"
|
||||
, SA.x2 <| ff <| (*) r <| cos an
|
||||
, SA.y2 <| ff <| (*) r <| sin an
|
||||
, SA.strokeWidth "0.01"
|
||||
, SA.stroke "#eee"
|
||||
]
|
||||
[]
|
||||
|
||||
inner_circle n =
|
||||
let
|
||||
fn = toFloat n
|
||||
period = period_for fn
|
||||
r = (r_for fn)
|
||||
num_ticks = (floor period)
|
||||
in
|
||||
Svg.g
|
||||
[]
|
||||
[ Svg.circle
|
||||
[ SA.r <| ff r
|
||||
, SA.strokeWidth "0.002"
|
||||
, SA.stroke "gray"
|
||||
, SA.fill "none"
|
||||
]
|
||||
[]
|
||||
, Svg.text_
|
||||
[ SA.x "0"
|
||||
, SA.y <| ff (-r)
|
||||
, SA.fontSize "0.03"
|
||||
, SA.textAnchor "middle"
|
||||
]
|
||||
[ Svg.text <| ff <| period]
|
||||
]
|
||||
|
||||
circles = List.map (inner_circle) (List.range 0 num_arms)
|
||||
in
|
||||
{
|
||||
title = "Unix epoch clock",
|
||||
body =
|
||||
[ Svg.svg
|
||||
[ HA.attribute "viewBox" "-1.2 -1.2 2.4 2.6"]
|
||||
[ Svg.g [] (List.map tick (List.range 0 9))
|
||||
, Svg.g [] circles
|
||||
, Svg.g [] arms
|
||||
, Svg.text_
|
||||
[ SA.x "0"
|
||||
, SA.y "1.1"
|
||||
, SA.textAnchor "middle"
|
||||
, SA.dominantBaseline "central"
|
||||
, SA.fontSize "0.1"
|
||||
, SA.stroke "white"
|
||||
, SA.strokeWidth "0.02"
|
||||
, SA.style "paint-order: stroke fill"
|
||||
]
|
||||
[ Svg.text <| String.fromInt <| floor <| (\n -> (toFloat n)/1000) <| Time.posixToMillis model.time ]
|
||||
]
|
||||
]
|
||||
}
|
14
style.css
Normal file
14
style.css
Normal file
|
@ -0,0 +1,14 @@
|
|||
body {
|
||||
margin: 0;
|
||||
width: 100svw;
|
||||
height: 100svh;
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
grid-template: 1fr / 1fr;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue