Skip to content
This repository has been archived by the owner on Nov 4, 2020. It is now read-only.

colbyn/subscript-old

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Subscript

Productively create maintainable web-apps, utilizing the best of Rust’s unique features.

  • Built for backend-developers implementing products and services that require sophisticated frontends.

  • Built for backend-developers wishing to standardize their infrastructure on Rust.

  • Built for backend-developers accustomed to implementing services akin to a client-server model, and by extension, to implement the frontend as yet another client without special treatment or ceremony.

  • Build for backend-developers that wanna write inline CSS properties, media-queries, keyframes and pseudo classes/elements.

    Yes this includes inline media-queries, keyframes and pseudo classes/elements:

    • I call it "selector-less functionalized CSS", since it doesn't use global selectors and so therefore CSS styling can be abstracted by any rust function and therein operable with the native rust module system; unlike CSS modules, and unlike CSS itself there will never be specificity errors from global sectors (not including framework malfunction). Internally this translates to, and is using the browsers CSSOM APIs.
    • Also this doesn't bloat the debug DOM tree with inline css-properties (if it’s not already obvious).
  • Not built for those seeking xml syntax.

Feature Highlights

  • Client side URL routing/parsing VIA pattern-matching-like syntax:
parse_url!{
      [] => {
          Page::Homepage
      }
      ["content"] => {
          Page::Content
      }
      // Notice this (a dynamic binder):
      ["content", name: String] => {
          Page::SomeItem {name: name}
      }
      ["content", guid: u64] => {
          Page::SomeOtherItem {id: guid}
      }
      ["account"] => {
          Page::Account
      }
      // Also dynamic binder's work for any type that implements `FromStr`:
      ["account", user_id: Uuid] => {
          Page::AccountUser {id: user_id}
      }
      _ => {
          Page::NotFound
      }
};

From the above, for things like user_id: Uuid it uses the FromStr instance on the type for parsing; if it fails it simply checks the next entry (so erroneously formatted uuid's in this case return Page::NotFound - not a runtime error). Also parse_url!(..) includes compile-time totality checks.

  • subscriptions and component-to-component heterogeneous messaging (also supports broadcasting)
// ... from your init function ...
subs!{
      msg update_session(value: NewSession) -> Msg {
          Msg::NewSession(msg.session)
      }
      msg update_page(value: UrlChanged) -> Msg {
          Msg::UrlChanged(parse_url(value))
      }
      msg maybe_update_page(value: UrlRequest) -> Msg {
          Msg::UrlRequest(value.page)
      }
};
// ... from some update function ...
// lets broadcast some random messages (values) of different types
sh.broadcast(SomeType(...));
sh.broadcast(SomeOtherType(...));
sh.broadcast(UrlRequest(Page::Something));
// ...
// This is perhaps impossible without types hehe
sh.message::<SomeComponentType>(message_value);
///         ^^^^^^^^^^^^^^^^^^^ sent a message to any component of the given type.
  • The perhaps unique view syntax

    Thought it best to just throw in everything and the kitchen sink.

    // `v1!{...}` is for versioned view syntaxes, just like versioned http-apis.
    v1!{
        // notice: no needless distinction between mixins/fragments and views:
        display: "flex";
        flex_direction: "column";
        width: "80%";
        margin: "0 auto";
        // supports inline-like css media queries, keyframes and pseudo classes/elements. e.g.
        css.media[min_width: "1100px"] => s1!{
            width: "60%";
        };
        attr = "value";
        // (personally, i generally put css styling, html attributes/events first and children last)
        h1 !{
            display: "flex";
            justify_content: "center";
            font_family: "monospace";
            font_size: "5em";
            padding: "0";
            margin: "0";
            color: "#444";
            css.hover => s1!{
                // ...
                // perhaps some annoying css-transition here :)
                // ...
            };
            // This is a non-static value, a signal (in this case of type Signal<String>):
            &model.counter_value.map(|x| {
              format!("{}", x)
            });
        };
        button !{
            button_styling();
            event.click[] => move || {
                Msg::Increment
            };
            "Increment";
        };
        button !{
            button_styling();
            event.click[] => move || {
                Msg::Decrement
            };
            "Decrement";
        };
    }

About

Subscript is simply put, a data-driven UI library.

Regarding it's current implementation, Subscript is perhaps closer to the so called “incremental DOM” school-of-thought then to any react/virtual-dom manifestation; especially since there is no intermediate “diff” phase. As a consequence Subscript may one day lay claim to some interesting performance characteristics.

Currently, much work has been spent on the external API. Especially concerning how the view is constructed. I hope you enjoy my work!

Technical

Stable

Subscript doesn’t require the nightly compiler.

TODOs - Interested in Extending Subscript/Collaboration?

Here are some suggestions thats on my immediate roadmap:

  • D3 style scale abstraction and related utils.
  • If possible, better error messages (view/style macros).
  • Typed/Value-level API for CSS properties and values. e.g.
    v1!{
      div !{
          // With the current implementation, this is treaded or rather parsed specially by the view macro and so not conducive to auto-complete:
          background_color: "gray";
          
          // For a reference `css.hover` is likewise parsed specially by the view macro:
          css.hover => s1!{
            // Also using the literal property syntax:
            color: "hsl(0, 0, 0)";
          };
          
          // For the backwards-compatibility conscientious folks, the below API examples won’t replace the above *literal syntax* notation that we’re currently using.
          
          // Future CSS API examples:
          
          // These are regular auto-completable rust expressions (that implement the current (for lack of a better name) `ViewExt` trait).
          background_color(gray())
          padding(0);
          padding(px(1));
          padding((0, 0));
          // Likewise for overloaded labels:
          display(flex());
          display(grid());
          
          // Also...
          css::hover(s1!{
            color(hsl(0, 0, 0));
          });
          
          h1 !{
            // For a reference this string -value or expression also implements the mixable trait:
            "Hello World";
          }
      }
    }
    I’ve already tried this before and got the above API to work quit nicely. But the CSS API is MASSIVE and I’m currently overloaded on more essential features.

Copyright 2019 Colbyn Wadman

About

[Old Project] Subscript - A Web-App Toolkit (WIP)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages