Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <link rel="stylesheet" href="https://unpkg.com/manuel@0.62.0/dist/style.css">
  <title>JS Bin</title>
</head>
<body>
  <script src="https://unpkg.com/manuel@0.63.0/dist/manuel.js"></script>
  <script src="https://unpkg.com/mithril@1.1.3/mithril.min.js"></script>
  <script src="https://unpkg.com/mithril-stream@1.1.0/stream.js"></script>
  <script src="https://unpkg.com/ramda@0.24.1/dist/ramda.min.js"></script>
<script>
const Maybe = {
  Just(x){
    return { of: Maybe.Just, x}
  }
  ,Nothing(){
    return { of: Maybe.Nothing }
  }
  ,map(f){
    return function(Ma){
      return Ma.of == Maybe.Just
        ? Maybe.Just( f(Ma.x) )
        : Maybe.Nothing()
    }
  }
}
  
function afterSilence(ms, s) {
    const r = m.stream()
    var timeoutId
    var last
    s.map(function(){
        last = s()
        clearTimeout(timeoutId);
        timeoutId = setTimeout(function() {
            r(last);
        }, ms);
    })
    return r
}
const indexBy = f => xs =>
    xs.reduce(function(p, n){
        p[f(n)] = n
        return p
    }, {})
const MithrilStreamAutocomplete = manuel({
    hyperscript: m
    ,get: o => o()
    ,set: (o, x) => o(x)
})
function GithubUserSearch(){
    
    const items = m.stream([])
    const loginIndex = items.map(indexBy( o => o.login))
    const model = {
        list: items.map(
        xs => xs.map(o => o.login)
        )
        ,input: m.stream('JAForb')
        ,chosen: m.stream()
        ,open: m.stream(true)
        ,highlighted: m.stream('')
    }
    const request = 
        afterSilence(1000, model.input).map(function(x){
            return x != model.chosen() 
                && x != null 
                && x.length > 2
            ? Maybe.Just({ 
            method: 'GET'
            , url: 'https://api.github.com/search/users?q=' + x
            })
            : Maybe.Nothing()
        })
    // side effects
    request
        .map( 
            Maybe.map(function(req){
                m.request(req)
                .then( res => res.items )
                .then( xs => items(xs) )
            })
        )
    
    m.stream.merge(
      Object.keys(model)
        .map( k => model[k] )
        .concat([ loginIndex ])
    )
      .map( () => m.redraw() )
    const view = () =>
        m('label', 'Search Github Users'
            ,MithrilStreamAutocomplete( model, {
                filter: () => true
                ,sort(a, b){
                    var A = loginIndex()[a]
                    var B = loginIndex()[b]
                    return a.score - b.score
                }
                ,renderItem(x, { mark, clickItem }){
                    var o = loginIndex()[x]
                    return m('li'
                        ,{ className: 
                            o.login == model.highlighted()
                            ? 'highlight'
                            : ''
                          , onmousedown: () => {
                            clickItem(x)
                          }
                        }
                        , m('span'
                            ,{ style: { display: 'block', height: '32px' }}
                            ,m('img'
                                ,{ src: o.avatar_url
                                , width: '32px'
                                , height: '32px'
                                , style: { position: 'absolute' }
                                }
                            )
                            ,m('span'
                                ,{ style: 
                                    { position: 'absolute'
                                    , display: 'block'
                                    , height: '32px'
                                    , transform: [
                                        ['32px', '25%']
                                        ,['8px', '0px']
                                    ]
                                        .map(
                                            (xy) => 'translate('+xy+')'
                                        )
                                        .join(' ')
                                    }
                                }
                                , mark(x)
                            ) 
                        )
                    )
                }
            })
        )
    return { view }
}
const App = {
    view(){
        return m(GithubUserSearch)
    }
}
m.mount(document.body, App)
</script>
</body>
</html>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
JAForbespro
0viewers