From 22ae65c92ffa2a6ec182b41a4b1ee2154ab2f06d Mon Sep 17 00:00:00 2001 From: Justin Blake Date: Tue, 26 May 2026 16:03:24 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 +++++++ devbox.json | 5 +++ gren.json | 20 +++++++++++ src/Desktop.gren | 8 +++++ src/Mobile.gren | 8 +++++ src/Skog.gren | 33 +++++++++++++++++ src/UI.gren | 82 +++++++++++++++++++++++++++++++++++++++++++ src/UI/Attribute.gren | 19 ++++++++++ 8 files changed, 188 insertions(+) create mode 100644 README.md create mode 100644 devbox.json create mode 100644 gren.json create mode 100644 src/Desktop.gren create mode 100644 src/Mobile.gren create mode 100644 src/Skog.gren create mode 100644 src/UI.gren create mode 100644 src/UI/Attribute.gren diff --git a/README.md b/README.md new file mode 100644 index 0000000..49f396b --- /dev/null +++ b/README.md @@ -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" :) diff --git a/devbox.json b/devbox.json new file mode 100644 index 0000000..24edac5 --- /dev/null +++ b/devbox.json @@ -0,0 +1,5 @@ +{ + "packages": [ + "gren@0.6.5" + ] +} diff --git a/gren.json b/gren.json new file mode 100644 index 0000000..d2f2c92 --- /dev/null +++ b/gren.json @@ -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" + } +} diff --git a/src/Desktop.gren b/src/Desktop.gren new file mode 100644 index 0000000..56bc01b --- /dev/null +++ b/src/Desktop.gren @@ -0,0 +1,8 @@ +module Desktop exposing (Desktop) + +{-| Phantom-type tag for desktop-specific UI elements and views. +-} + + +type Desktop + = Desktop diff --git a/src/Mobile.gren b/src/Mobile.gren new file mode 100644 index 0000000..551e02b --- /dev/null +++ b/src/Mobile.gren @@ -0,0 +1,8 @@ +module Mobile exposing (Mobile) + +{-| Phantom-type tag for mobile-specific UI elements and views. +-} + + +type Mobile + = Mobile diff --git a/src/Skog.gren b/src/Skog.gren new file mode 100644 index 0000000..c069929 --- /dev/null +++ b/src/Skog.gren @@ -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 + } diff --git a/src/UI.gren b/src/UI.gren new file mode 100644 index 0000000..1da8781 --- /dev/null +++ b/src/UI.gren @@ -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 } diff --git a/src/UI/Attribute.gren b/src/UI/Attribute.gren new file mode 100644 index 0000000..de74e95 --- /dev/null +++ b/src/UI/Attribute.gren @@ -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