Misc

Gems

  • https://awesome-ruby.com/

Alerts and notifications

Jbox

jbox notifications, modals, tooltips, images and confirm windows. You need to install plugins that you use

bower install jbox --save

// app/assets/adminlte/application_adminlte.js
//= require jbox/Source/jBox
//= require jbox/Source/plugins/Notice/jBox.Notice

// app/assets/adminlte/application_adminlte.scss
@import "jbox/Source/jBox";
@import "jbox/Source/plugins/Notice/jBox.Notice";


# app/controllers/application_controller.rb
after_action :check_flash_message
def check_flash_message
  return unless request.xhr? && request.format.js? && new_layout?
  response.body += "flash_alert('#{view_context.j flash.now[:alert]}')" if flash.now[:alert].present?
  response.body += "flash_notice('#{view_context.j flash.now[:notice]}')" if flash.now[:notice].present?
end

# app/assets/javascripts/flash_messages.coffee
# https://stephanwagner.me/jBox/get_started
window.flash_alert = (message) ->
  # https://stephanwagner.me/jBox/documentation says that we need to wait for
  # ready for page load, so we use setTimeout
  setTimeout(
    ->
      new jBox 'Alert',
        autoClose: 10000
        attributes:
          x: 'right'
          y:'bottom'
        stack: false
        animation:
          open:'bounce'
          close:'fadeOut'
        content: message
        color: 'red'
    10 # tried with 0, 1, but it was triggered before page load and not working
  )
window.flash_notice = (message) ->
  setTimeout(
    ->
      new jBox 'Notice',
        autoClose: 10000
        attributes:
          x: 'right'
          y:'bottom'
        stack: false
        animation:
          open:'bounce'
          close:'fadeOut'
        content: message
        color: 'blue'
    10 # tried with 0, 1, but it was triggered before page load and not working
  )

Input mask

Select something

http://digitalbush.com/projects/masked-input-plugin/

  • selectize and selectize-rails
  • multiselect nice way to select multiple items from opened select box. If you show in popup with different data, then call select.multiSelect('refresh'); after you initialize multiSelect.
    • if you want to keep order keepOrder option shows nice order, but submitting the form do not preserve order. You can use this solution issue
    select.multiSelect({
      keepOrder: true,
      afterSelect: function(value){
        $('#templates-select option[value="'+value+'"]').remove();
        $('#templates-select').append($("<option></option>").attr("value",value).attr('selected', 'selected'));
      },
    });
    
    • keepOrder does not work for preselected items, solution could be to manually select (not already select: selected):
    $.each(selectedTemplateIds, function(index, template_id) {
      select.multiSelect('select', [String(template_id)]);
    });
    
  • multiple select it creates ul lists, if inside overflow: hidden you can use container and dropWidth: '100px' options

Select2

This nice select2 examples works.

  • problem is when you have animations (like in modal, or collapsed-box) select can calculate full width. solution is to set inline style="width:100%" or to call with

      $('#customer-name-select').select2({ placeholder: 'Search by Customer Name or Username', width: '100%'});
    
  • to make it inline you can wraps inside inline-block element and set some size with style='width:100px' on select element (select2 will use that to calculate size).

    # app/assets/select2.sass
    .select2-inline
      display: inline-block
      // by default .select2-container is block, which move it slightly to the top
      // and then it is not inline with other inline text or buttons
      .select2-container
        display: inline-block
    
  • options like dropdownParent could help

You can use data-(any option) so for example you can use data-placeholder="Please select" to set select2 placeholder, or data-tags="true" to enable tagging (also need multiple: true for select to accept multiple options)

I use this initializer data-select2-initialize (do not use data-select2 since it is used already) and if you use turbolinks and have all select elements on main page

# app/assets/javascripts/turbolinks_load.coffee.rb
$(document).on 'turbolinks:load', ->
  console.log 'turbolinks:load'
  $('[data-select2-initialize]').each ->
    options = {}
    if $(this).attr 'placeholder'
      # select_tag :id, options, include_blank: true, placeholder: 'Choose one'
      options['placeholder'] = $(this).attr 'placeholder'
    else
      options['placeholder'] = '<%= I18n.translate 'please_select' %>'

    options['language'] = determine_language()
    $(this).select2 options

or without turbolinks or if you have select elements on some ajax responses, you can manually call <script>initializeSelect2()</script>)

# app/assets/javascripts/data_select2_initialize.coffee
@initializeSelect2 = ->
  $('[data-select2-initialize]').each ->
    if $(this).attr 'placeholder'
      placeholder = $(this).attr 'placeholder'
    else
      placeholder = "Please select"
    $(this).select2(
      placeholder: placeholder
    )
  <%= f.select :customer, options_from_collection_for_select(Customer.all, 'id', 'name_and_username'),  { include_blank: true }, 'data-select2-initialize': true, 'data-placeholder': 'Select customer' %>
  <script>
    initializeSelect2();
  </script>
# default options for all select
# https://select2.github.io/options.html#setting-default-options
# issue when select2 is used in modal or other elements that fades in
$.fn.select2.defaults.set("width", "100%")

Problem is when select2 is inside modal with tabindex="-1" example

To select item on select2 with ajax source, you need to initialize with data and keep ajax source

    $(selectTarget).select2({
      data: [{id: selectValue, text: selectText}],
      ajax: {
        url: $(selectTarget).data('select2AjaxInitialize'),
        dataType: 'json'
      }
    });

or for all

$(document).on 'turbolinks:load', ->
  $('[data-select2-ajax-initialize]').each ->
    url = $(this).data('select2AjaxInitialize')
    options = {
      ajax: {
        url: url
        dataType: 'json'
      }
    }
    $(this).select2 options
    # using label for select does not open select2 on focus, so on label click
    # we should trigger open
    # https://github.com/select2/select2/issues/2311#issuecomment-180666626
    $(this).focus ->
      $(this).select2('open')

Calendar date and time picker

Image file upload drag and drop crop

Rich text editors wyswyg

list:

Quil

quill examples You can edit by selecting content bubble

Usually you do not need any additional styles when you want to show html (bold, italic, h1, quote, code, list). Color and background colors are defined inline with style attribute so it works (unless you use rails sanitize which remove inline styles). Other styles requires quill classes (center, right, direction, align, indent, large, huge, fonts) so you need to inlude that css and to wrap output inside ql_editor class (or you can use inline style but it seems )

  <div class="ql-editor">
    <%= raw @location.about_html %>
  </div>
  <script>
    loadFile("//cdn.quilljs.com/1.2.2/quill.snow.css");
  </script>

You can load in head section

<!-- app/views/layouts/application.html.erb -->
<script src="//cdn.quilljs.com/1.2.2/quill.min.js" type="text/javascript"></script>
<link href="//cdn.quilljs.com/1.2.2/quill.snow.css" rel="stylesheet">

or you can load dynamically using this helper

# app/assets/javascripts/load_external_css_javascript.coffee
# all files will be loaded defered so you can use callbak
window.alreadyLoadedFiles = []
window.loadFile = (filename, callback) ->
  if callback and filename in alreadyLoadedFiles
    console.log "File #{filename} already loaded"
    callback()
    return
  if filename.slice(-2) == "js"
    fileref = document.createElement('script')
    fileref.setAttribute("type","text/javascript")
    fileref.setAttribute("src", filename)
    fileref.onload = callback if callback
  else if filename.slice(-3) == "css"
    fileref = document.createElement("link")
    fileref.setAttribute("rel", "stylesheet")
    fileref.setAttribute("type", "text/css")
    fileref.setAttribute("href", filename)
  if (typeof fileref!="undefined")
    document.getElementsByTagName("head")[0].appendChild(fileref)
    alreadyLoadedFiles.push filename
    console.log "Adding file #{filename}"

and use it with loadQuill('editor-content', 'editor-container');

# app/assets/javascripts/quill.coffee
window.loadQuill = (editorContent, editorContainer) ->
  loadFile "//cdn.quilljs.com/1.2.2/quill.snow.css"
  loadFile "//cdn.quilljs.com/1.2.2/quill.min.js", ->
    console.log "Loading quill editorContent=#{editorContent} " +
      "editorContainer=#{editorContainer}"
    # stripped example from https://quilljs.com/docs/modules/toolbar/
    # so we do not need to load quill classes
    options =
      # debug: 'info'
      modules:
        toolbar: [
          [{ 'header': [1, 2, 3, 4, 5, 6, false] }]
          ['bold', 'italic', 'underline']
          ['blockquote', 'code-block']
          [{ 'list': 'ordered'}, { 'list': 'bullet' }]
          ['clean']
          ['link']
        ]
      theme: 'snow'

    $editorContainer = $("##{editorContainer}")
    quill = new Quill($editorContainer.get(0), options)
    toolbar = quill.getModule 'toolbar'
    toolbar.addHandler 'link', (value) ->
      if (value)
        href = prompt('Enter the URL')
        href = "http://#{href}" if href.substring(0,4) != "http"
        this.quill.format('link', href)
      else
        this.quill.format('link', false)
    quill.on 'text-change', ->
      newHtml = $($editorContainer).find('.ql-editor').html()
      $("##{editorContent}").val newHtml

You can also get html on form submit

# app/assets/javascript/quill.coffee
$(document).on 'ready page:load', ->
  options =
    debug: 'info'
    modules:
      toolbar: [
        ['bold', 'italic', 'underline']
        ['blockquote', 'code-block']
        [{ 'header': 1 }, { 'header': 2 }]
        [{ 'list': 'ordered'}, { 'list': 'bullet' }]
        [{ 'script': 'sub'}, { 'script': 'super' }]
        [{ 'indent': '-1'}, { 'indent': '+1' }]
        [{ 'direction': 'rtl' }]
        [{ 'size': ['small', false, 'large', 'huge'] }]
        [{ 'header': [1, 2, 3, 4, 5, 6, false] }]
        [{ 'color': [] }, { 'background': [] }]
        [{ 'font': [] }]
        [{ 'align': [] }]
        ['clean']
      ]
    theme: 'snow'
  syncHtml = ->

  $('[data-quill-editor]').each ->
    editoContainer = $(this).get(0)
    quill = new Quill(editoContainer, options)
    $targetInput = $(this.dataset.quillEditor)
    quill.on 'text-change', ->
      newHtml = $(editoContainer).find('.ql-editor').html()
      $targetInput.val newHtml
<%# app/views/admin/pages/show.html.erb %>
<div data-quill-editor="#editor-content">
  <%# you can test with raw content but sanitized is safer %>
  <%= sanitize @page.content %>
</div>
<%# app/views/admin/pages/_form.html.erb
    <div id="editor-container">
      <%= sanitize @location.about_html %>
    </div>
    <script>
      loadQuill('editor-content', 'editor-container');
    </script>

Fontawesome

FA icons are very usefull for quick icons. Look for examples

Images

  • free high resolution https://unsplash.com/
  • free online sample images https://unsplash.it/images
  • free stock photos https://burst.shopify.com
  • sample placeholder https://placeholder.com/
  • free vector images kajak pictogram https://pixabay.com/en/sport-pictogram-olympia-water-swim-1580667/

Slides

Graphs

Email services

User tracking services

mixpanel

  • create tracking plan that defines each event and its properties (name and type: string, number, boolean), In plan we should define: Event name, description, why this event and for each property: property name, property description, property type, why this property
  • call identify when user signup, or if there are existing users, when the logs in, or use the app
  • you can also send push notifications from mixpanel

User support services

User intro tour

User navigation to website with help tips should be only one, when user clicks something (so help is to interactivelly show tips, not on page load). Users will not remeber if you show them 8 steps for the page they just arrived.

  • introjs commercial lincence after 2.1
  • http://bootstraptour.com source
    • intersting value is backdrop: true so element is highlighted reflex: true so click on target element dismiss page tour
    • if you want to repeat tour you can use yield and content_for
      <%# somewhere in support dropdown menu %>
      <% if content_for? :page_tour_script %>
        <li>
          <%= yield :page_tour_script %>
          <a href="#" onclick="startTour()">
            Start Page Tour
          </a>
        </li>
      <% end %>
      
    <%# on a page where we need tour %>
    <% content_for :page_tour_script do %>
      <script>
        function startTour() {
          // http://bootstraptour.com/api/
          var tour = new Tour({
            storage: false,
            steps: [
            {
              element: "[data-target='#publish-location-package-modal']",
              title: "Publish Package",
              content: "You can publish package using this button",
              placement: 'right',
              backdrop: true,
              reflex: true,
            },
          ]});
    
          // Initialize the tour
          tour.init();
    
          // Start the tour
          tour.start();
        }
      </script>
    <% end %>
    

Visitor user analytics

To find new customers you can find sites that link to similar content. For example in google link:kulakajak.org -site:kulakajak.org will give all sites that links to kulakajak.org. You can scrape them to find admin contact email and suggest them to add your content that will be interesting to their audience

Do you feel it could be a good fit for your audience? Might be worth a mention :) Here is the Link: I’d love to know what you think! Sincerely,

Opensource heatmaps

  • example how to to track with firebase

https://github.com/seeyourvisitors/seeyourvisitors/blob/master/gg.dev.js and how to show results with https://github.com/pa7/heatmap.js example js is here https://github.com/seeyourvisitors/heatmap

Marketing

Optimisation

Error tracking

  • airbrake
  • sentry

Payment

  • https://www.braintreepayments.com/
  • https://www.paddle.co/
  • https://www.payola.io/

Ruby

  • yml_gtranslate automatic generate translated yml locale files for rails localisations using google translate for f in $(find config/locales/ -type d);do yml_gt en rs $f;done. Also usefull when want to grep only en.yml grep -i catar config/locales --include *.en.yml -R

Rails

https://github.com/eliotsykes/real-world-rails realworldrails more are using rspec than test: cd real-world-rails/apps and find . -name spec -maxdepth 2 | wc -l # 134 and find . -name test -maxdepth 2 | wc -l # 52

Those are nice to explore:

  • crowdsourcing catarse tilt is not actually opensource, since their api should be used
  • sharetribe opensource market peer-to-peer marketplace
  • diaspora
    • when you run localy, you can import new contacts and their posts, for example: hq@pod.diaspora.software
  • openstreetmap

Templates

Email templates

http://internations.github.io/antwort/ guides https://github.com/InterNations/antwort/wiki/HTML-Styleguide-for-Email

Animations

https://xtianmiller.github.io/emergence.js/

Scroll

Nice design and ui tools

https://css-tricks.com/examples/DifferentTransitionsOnOff/

Fonts and icons

Web framework

https://github.com/kemalyst/kemalyst based on https://crystal-lang.org/

Static analysis

  • shellckeck static analysis tool for shell scripts

Mockups and wireframes

  • https://balsamiq.com/products/ trial one month
  • https://moqups.com/ free up to 300 objects
  • https://wireframe.cc/ free for public one page

To create mockups you can use: Invision, Marvel, Baslamiq, Sketch

Continuous integration

see [ci cd post] /2018/04/10/continuous-delivery-integration-ci-cd-pronto/)

DDNS

  • duckdns install
  • https://www.nsupdate.info to run on ubuntu just sudo apt-get install ddclient and provide config params (or update /etc/ddclient.conf) and it will run every hour

Find alternatives

https://alternativeto.net

Dokku

Heroku-like self hosted platform as a service

https://pawelurbanek.com/rails-heroku-dokku-migration https://github.com/dokku/dokku https://github.com/githubsaturn/captainduckduck