This commit is contained in:
Justin Blake 2026-05-26 16:03:24 -04:00
commit 22ae65c92f
No known key found for this signature in database
GPG key ID: E70CAC45C816AAEA
8 changed files with 188 additions and 0 deletions

13
README.md Normal file
View file

@ -0,0 +1,13 @@
# Skog
Multiplatform mobile and desktop app framework for [Gren](https://gren-lang.org/).
## Technical notes and references
* Original design plan at ~/projects/gren-multiplatform-experiment/gren-multiplatform.md
* Proof of concept for iOS at ~/projects/gren-mobile-experiment
* Driving initial implementation via ~/projects/idlegame-gren
## Other stuff
Skog is Norwegian for "forrest" :)

5
devbox.json Normal file
View file

@ -0,0 +1,5 @@
{
"packages": [
"gren@0.6.5"
]
}

20
gren.json Normal file
View file

@ -0,0 +1,20 @@
{
"type": "package",
"platform": "browser",
"name": "blaix/skog",
"summary": "Framework for Gren apps that run on mobile, desktop, and web.",
"license": "BSD-3-Clause",
"version": "0.1.0",
"exposed-modules": [
"Skog",
"UI",
"UI.Attribute",
"Mobile",
"Desktop"
],
"gren-version": "0.6.0 <= v < 0.7.0",
"dependencies": {
"gren-lang/core": "7.0.0 <= v < 8.0.0",
"gren-lang/browser": "6.0.0 <= v < 7.0.0"
}
}

8
src/Desktop.gren Normal file
View file

@ -0,0 +1,8 @@
module Desktop exposing (Desktop)
{-| Phantom-type tag for desktop-specific UI elements and views.
-}
type Desktop
= Desktop

8
src/Mobile.gren Normal file
View file

@ -0,0 +1,8 @@
module Mobile exposing (Mobile)
{-| Phantom-type tag for mobile-specific UI elements and views.
-}
type Mobile
= Mobile

33
src/Skog.gren Normal file
View file

@ -0,0 +1,33 @@
module Skog exposing (Program, program)
{-| Define a multi-platform Skog program.
The app provides shared `init`, `update`, and `subscriptions` along with
separate `mobileView` and `desktopView` functions. Bridges (SwiftUI,
Compose, DOM) consume the views; this stub just wires up a Platform.worker.
-}
import Desktop exposing (Desktop)
import Mobile exposing (Mobile)
import Platform
import UI
type alias Program model msg =
Platform.Program {} model msg
program :
{ init : { model : model, command : Cmd msg }
, update : msg -> model -> { model : model, command : Cmd msg }
, subscriptions : model -> Sub msg
, mobileView : model -> UI.Element Mobile msg
, desktopView : model -> UI.Element Desktop msg
}
-> Program model msg
program config =
Platform.worker
{ init = \_ -> config.init
, update = config.update
, subscriptions = config.subscriptions
}

82
src/UI.gren Normal file
View file

@ -0,0 +1,82 @@
module UI exposing
( Element
, text
, column
, row
, button
, image
)
{-| Cross-platform UI primitives.
The `platform` type parameter stays polymorphic for elements that work
everywhere. Platform-specific elements live in the `Mobile` and `Desktop`
modules and constrain the parameter.
-}
import UI.Attribute exposing (Attribute)
type Element platform msg
= Text
{ attributes : Array (Attribute platform msg)
, content : String
}
| Column
{ attributes : Array (Attribute platform msg)
, children : Array (Element platform msg)
}
| Row
{ attributes : Array (Attribute platform msg)
, children : Array (Element platform msg)
}
| Button
{ attributes : Array (Attribute platform msg)
, onPress : msg
, label : Element platform msg
}
| Image
{ attributes : Array (Attribute platform msg)
, source : String
}
text : Array (Attribute platform msg) -> String -> Element platform msg
text attributes content =
Text { attributes = attributes, content = content }
column :
Array (Attribute platform msg)
-> Array (Element platform msg)
-> Element platform msg
column attributes children =
Column { attributes = attributes, children = children }
row :
Array (Attribute platform msg)
-> Array (Element platform msg)
-> Element platform msg
row attributes children =
Row { attributes = attributes, children = children }
button :
Array (Attribute platform msg)
-> { onPress : msg, label : Element platform msg }
-> Element platform msg
button attributes config =
Button
{ attributes = attributes
, onPress = config.onPress
, label = config.label
}
image :
Array (Attribute platform msg)
-> String
-> Element platform msg
image attributes source =
Image { attributes = attributes, source = source }

19
src/UI/Attribute.gren Normal file
View file

@ -0,0 +1,19 @@
module UI.Attribute exposing (Attribute, padding, backgroundColor)
{-| Styling attributes for UI elements.
-}
type Attribute platform msg
= Padding Int
| BackgroundColor String
padding : Int -> Attribute platform msg
padding amount =
Padding amount
backgroundColor : String -> Attribute platform msg
backgroundColor color =
BackgroundColor color