hyperstack-org / hyperstack

Hyperstack ALPHA https://hyperstack.org
https://docs.hyperstack.org
MIT License
539 stars 41 forks source link

Elegant usage of Material design Components and Icons. #273

Open sebyx07 opened 4 years ago

sebyx07 commented 4 years ago

Might be useful for others. The results are really impressive

yarn add @material-ui/core --save

// append in client_and_server.js
Mui = require('@material-ui/core');
Mui.default = Mui;
# example hyperstack/components/hyper_component.rb

class HyperComponent
  include Hyperstack::Component
  include Hyperstack::State::Observable
  param_accessor_style :accessors

  def __material_component(component_name, **options, &block)
    Mui.send(component_name, options, &block)
  end

  def __material_icon(icon_name, **options)
    __material_component("Icon", options) { icon_name.underscore }
  end

  def method_missing(method_name, *_args, **options, &block)
    classified_name = method_name.classify
    name_without_icon = method_name.sub("Icon", "")

    if classified_name == method_name && `Mui[#{method_name}]`
      __material_component(method_name, **options, &block)
    elsif name_without_icon != method_name && classified_name == method_name
      __material_icon(name_without_icon, **options, &block)
    else
      super
    end
  end
end
# for icons inside application.html.erb
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
# example navbar, translation from react to hyperstack
# render it inside app.rb with     Page::Navbar()

module Page
  class Navbar < HyperComponent
    # <AppBar position="static">
    # <Toolbar>
    # <IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
    # <MenuIcon />
    #       </IconButton>
    # <Typography variant="h6" className={classes.title}>
    #   News
    # </Typography>
    #       <Button color="inherit">Login</Button>
    # </Toolbar>
    #   </AppBar>

    render do
      AppBar position: :static do
        Toolbar do
          IconButton edge: :start, color: :inherit, "aria-label": "menu" do
            MenuIcon()
          end

          Typography(variant: :h6) { "News" }

          Typography do
            Button(color: :inherit) { "Login" }
          end
        end
      end
    end
  end
end

I'll keep you guys posted if I have a example running DirectUpload from ActiveStorage.

sebyx07 commented 4 years ago

@catmando if you could help me with error, after the example. Would be great, then I can add the progress bar

# a direct upload implementation

class DirectUploader < HyperComponent
  param :upload_url # access it as @UploadUrl
  param :upload_name# access it as @UploadName

  render(DIV) do
    input = INPUT(
      id: @UploadName,
      type: :file, accept: "image/*", multiple: true
    ).on(:change) { |event| upload_files(event) }

    LABEL(htmlFor: "contained-button-file") do
      Button(variant: :contained, component: :span) do
        "Upload"
      end.on(:click) { jQ[input].click } # select the input with jQ, then trigger a click on it, check initializer to have jquery enabled
    end
  end

  def upload_files(event)
    event.target.files.to_a.each do |file|
      upload_file(file)
    end
  end

  def upload_file(file)
    Uploader.new(file, @UploadUrl, @UploadName).call!
  end

  class Uploader
    def initialize(file, upload_url, upload_name)
      @upload_url = upload_url
      @upload_name = upload_name
      @upload = Native(`new ActiveStorage.DirectUpload(#{file.to_n}, "/rails/active_storage/direct_uploads")`) # with Native you can native js, like ActiveStorage.DirectUpload or w/e
    end

    def call!
      @upload.create do |err, blob| # handle callback
        err = Native(err) # convert again to ruby/opal objects
        blob = Native(blob) # convert again to ruby/opal objects
        next p err if err

        data = { @upload_name => blob.signed_id }
        Hyperstack::HTTP.post(@upload_url, payload: data) do
          p "DONE"
        end
      end
    end

    def directUploadWillStoreFileWithXHR(request) # TODO
      p Native(request)
    end

    def directUploadDidProgress(event) # Todo
      p Native(event)
    end
  end
end

The error happens on @upload.create do |err, blob|

//error

broadcast.rb:158 Uncaught TypeError: Cannot read property 'prototype' of undefined
    at singleton_class_alloc.$$eval_native_react_component [as $eval_native_react_component] (react_wrapper.rb:34)
    at singleton_class_alloc.TMP_ReactWrapper_native_react_component$q_4 [as $native_react_component?] (react_wrapper.rb:46)
    at singleton_class_alloc.$$create_component_wrapper [as $create_component_wrapper] (native_library.rb:73)
    at singleton_class_alloc.$$import_const_from_native [as $import_const_from_native] (native_library.rb:40)
    at singleton_class_alloc.$$const_missing [as $const_missing] (auto-import.rb:17)
    at const_missing (runtime.self-a59b72816f596f5bb11f5da568edd0b684eec56ddaff0ae5da9834528996763d.js?body=1:211)
    at Object.Opal.const_get_relative (runtime.self-a59b72816f596f5bb11f5da568edd0b684eec56ddaff0ae5da9834528996763d.js?body=1:284)
    at singleton_class_alloc.$$const_get [as $const_get] (module.rb:296)
    at TMP_26 (module.rb:305)
    at Object.Opal.yieldX (runtime.self-a59b72816f596f5bb11f5da568edd0b684eec56ddaff0ae5da9834528996763d.js?body=1:1411)
sebyx07 commented 4 years ago

hey @excid3 if you could some tutorial for Hyperstack + Material Design. I think this way hotter than rails5-6 features. It's the missing feature....

It's like wysiwyg. Even action-text can be integrated with ease. DirectUpload took me ~10mins

barriehadfield commented 4 years ago

@sebyx07 brilliant work!