fron-ui 1.0.0rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +38 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +7 -0
  7. data/.yardopts +8 -0
  8. data/Gemfile +8 -0
  9. data/Gemfile.lock +105 -0
  10. data/Rakefile +37 -0
  11. data/Readme.md +4 -0
  12. data/db.json +192 -0
  13. data/fron-ui.gemspec +21 -0
  14. data/lib/fron-ui.rb +1 -0
  15. data/lib/fron_ui.rb +5 -0
  16. data/lib/fron_ui/version.rb +7 -0
  17. data/opal/fron-ui/base.rb +49 -0
  18. data/opal/fron-ui/behaviors/action.rb +40 -0
  19. data/opal/fron-ui/behaviors/actions.rb +40 -0
  20. data/opal/fron-ui/behaviors/confirmation.rb +23 -0
  21. data/opal/fron-ui/behaviors/dropdown.rb +27 -0
  22. data/opal/fron-ui/behaviors/file.rb +48 -0
  23. data/opal/fron-ui/behaviors/intendable_children.rb +76 -0
  24. data/opal/fron-ui/behaviors/keydown.rb +31 -0
  25. data/opal/fron-ui/behaviors/loop.rb +41 -0
  26. data/opal/fron-ui/behaviors/render.rb +30 -0
  27. data/opal/fron-ui/behaviors/rest.rb +121 -0
  28. data/opal/fron-ui/behaviors/selectable_children.rb +67 -0
  29. data/opal/fron-ui/behaviors/serialize.rb +32 -0
  30. data/opal/fron-ui/behaviors/shortcuts.rb +35 -0
  31. data/opal/fron-ui/behaviors/state.rb +56 -0
  32. data/opal/fron-ui/behaviors/transition.rb +63 -0
  33. data/opal/fron-ui/components/action.rb +18 -0
  34. data/opal/fron-ui/components/box.rb +17 -0
  35. data/opal/fron-ui/components/button.rb +61 -0
  36. data/opal/fron-ui/components/calendar.rb +129 -0
  37. data/opal/fron-ui/components/checkbox.rb +57 -0
  38. data/opal/fron-ui/components/chooser.rb +246 -0
  39. data/opal/fron-ui/components/color_panel.rb +235 -0
  40. data/opal/fron-ui/components/color_picker.rb +111 -0
  41. data/opal/fron-ui/components/container.rb +61 -0
  42. data/opal/fron-ui/components/date_picker.rb +141 -0
  43. data/opal/fron-ui/components/drag.rb +76 -0
  44. data/opal/fron-ui/components/dropdown.rb +72 -0
  45. data/opal/fron-ui/components/icon.rb +29 -0
  46. data/opal/fron-ui/components/image.rb +77 -0
  47. data/opal/fron-ui/components/input.rb +30 -0
  48. data/opal/fron-ui/components/label.rb +9 -0
  49. data/opal/fron-ui/components/list.rb +34 -0
  50. data/opal/fron-ui/components/loader.rb +63 -0
  51. data/opal/fron-ui/components/modal.rb +0 -0
  52. data/opal/fron-ui/components/notifications.rb +73 -0
  53. data/opal/fron-ui/components/number.rb +202 -0
  54. data/opal/fron-ui/components/progress.rb +52 -0
  55. data/opal/fron-ui/components/slider.rb +47 -0
  56. data/opal/fron-ui/components/tabs.rb +149 -0
  57. data/opal/fron-ui/components/textarea.rb +13 -0
  58. data/opal/fron-ui/components/time.rb +65 -0
  59. data/opal/fron-ui/components/title.rb +34 -0
  60. data/opal/fron-ui/examples/blog/index.rb +289 -0
  61. data/opal/fron-ui/examples/comments/components/comment.rb +75 -0
  62. data/opal/fron-ui/examples/comments/components/comments.rb +93 -0
  63. data/opal/fron-ui/examples/comments/components/footer.rb +36 -0
  64. data/opal/fron-ui/examples/comments/components/header.rb +35 -0
  65. data/opal/fron-ui/examples/comments/components/list.rb +12 -0
  66. data/opal/fron-ui/examples/comments/index.rb +6 -0
  67. data/opal/fron-ui/examples/contacts/components/contacts.rb +100 -0
  68. data/opal/fron-ui/examples/contacts/components/details.rb +92 -0
  69. data/opal/fron-ui/examples/contacts/components/item.rb +46 -0
  70. data/opal/fron-ui/examples/contacts/components/list.rb +10 -0
  71. data/opal/fron-ui/examples/contacts/components/sidebar.rb +30 -0
  72. data/opal/fron-ui/examples/contacts/index.rb +6 -0
  73. data/opal/fron-ui/examples/editor/index.rb +164 -0
  74. data/opal/fron-ui/examples/kitchensink/index.rb +193 -0
  75. data/opal/fron-ui/examples/todos/components/item.rb +84 -0
  76. data/opal/fron-ui/examples/todos/components/options.rb +26 -0
  77. data/opal/fron-ui/examples/todos/components/todos.rb +145 -0
  78. data/opal/fron-ui/examples/todos/index.rb +6 -0
  79. data/opal/fron-ui/examples/webshop/index.rb +0 -0
  80. data/opal/fron-ui/fonts/ionicons.rb +2954 -0
  81. data/opal/fron-ui/fonts/open_sans.rb +19 -0
  82. data/opal/fron-ui/lib/collection.rb +138 -0
  83. data/opal/fron-ui/lib/date.rb +23 -0
  84. data/opal/fron-ui/lib/debounce.rb +14 -0
  85. data/opal/fron-ui/lib/image_loader.rb +13 -0
  86. data/opal/fron-ui/lib/lorem.rb +93 -0
  87. data/opal/fron-ui/lib/nil.rb +29 -0
  88. data/opal/fron-ui/lib/record.rb +23 -0
  89. data/opal/fron-ui/lib/state_serializer.rb +129 -0
  90. data/opal/fron-ui/lib/storage.rb +57 -0
  91. data/opal/fron-ui/spec/setup.rb +40 -0
  92. data/opal/fron-ui/ui.rb +40 -0
  93. data/opal/fron-ui/utils/theme_roller.rb +63 -0
  94. data/opal/fron-ui/vendor/autoprefixer.js +21114 -0
  95. data/opal/fron-ui/vendor/marked.js +1291 -0
  96. data/opal/fron-ui/vendor/md5.js +274 -0
  97. data/opal/fron-ui/vendor/moment.js +3083 -0
  98. data/opal/fron-ui/vendor/uuid.js +92 -0
  99. data/opal/fron_ui.rb +13 -0
  100. data/spec/behaviors/action_spec.rb +34 -0
  101. data/spec/behaviors/actions_spec.rb +38 -0
  102. data/spec/behaviors/confirmation_spec.rb +23 -0
  103. data/spec/behaviors/dropdown_spec.rb +32 -0
  104. data/spec/behaviors/render_spec.rb +20 -0
  105. data/spec/behaviors/rest_spec.rb +70 -0
  106. data/spec/behaviors/selectable_children_spec.rb +40 -0
  107. data/spec/behaviors/serialize_spec.rb +34 -0
  108. data/spec/components/action_spec.rb +7 -0
  109. data/spec/components/base_spec.rb +19 -0
  110. data/spec/components/box_spec.rb +7 -0
  111. data/spec/components/button_spec.rb +9 -0
  112. data/spec/components/calendar_spec.rb +58 -0
  113. data/spec/components/checkbox_spec.rb +20 -0
  114. data/spec/components/chooser_spec.rb +75 -0
  115. data/spec/components/color_panel_spec.rb +49 -0
  116. data/spec/components/color_picker_spec.rb +41 -0
  117. data/spec/components/container_spec.rb +23 -0
  118. data/spec/components/date_picker_spec.rb +71 -0
  119. data/spec/components/drag_spec.rb +20 -0
  120. data/spec/components/dropdown_spec.rb +33 -0
  121. data/spec/components/image_spec.rb +33 -0
  122. data/spec/components/input_spec.rb +8 -0
  123. data/spec/components/list_spec.rb +10 -0
  124. data/spec/components/loader_spec.rb +9 -0
  125. data/spec/components/notifications_spec.rb +17 -0
  126. data/spec/components/number_spec.rb +64 -0
  127. data/spec/components/progress_spec.rb +23 -0
  128. data/spec/components/slider_spec.rb +25 -0
  129. data/spec/components/tabs_spec.rb +50 -0
  130. data/spec/components/textarea_spec.rb +7 -0
  131. data/spec/components/time_spec.rb +37 -0
  132. data/spec/components/title_spec.rb +11 -0
  133. data/spec/examples/comments_spec.rb +72 -0
  134. data/spec/examples/todos_spec.rb +39 -0
  135. data/spec/lib/collection_spec.rb +38 -0
  136. data/spec/lib/lorem_spec.rb +55 -0
  137. data/spec/lib/state_serializer_spec.rb +58 -0
  138. data/spec/lib/storage_spec.rb +39 -0
  139. data/spec/spec_helper.rb +1 -0
  140. metadata +223 -0
@@ -0,0 +1,75 @@
1
+ module Examples
2
+ class Comments < UI::Container
3
+ # Comment
4
+ class Comment < UI::Container
5
+ # Includes
6
+ include UI::Behaviors::Confirmation
7
+ include UI::Behaviors::Actions
8
+ include UI::Behaviors::Rest
9
+ include ::Record
10
+
11
+ # REST
12
+ rest url: 'http://localhost:3000/comments'
13
+
14
+ # Tagname
15
+ tag 'ui-comment'
16
+
17
+ # Style
18
+ style 'ui-comment-body' => { borderBottom: -> { "#{(theme.border_size / 2).em} solid #{colors.background}" },
19
+ paddingBottom: -> { theme.spacing.em },
20
+ 'p' => { margin: 0,
21
+ '& + p' => { marginTop: -> { theme.spacing.em } } } },
22
+ '&:hover ui-comment-header ui-action' => { display: :block }
23
+
24
+ # Components
25
+ component :image, UI::Image, width: 4.em, height: 4.em
26
+ component :box, UI::Container, flex: 1 do
27
+ component :header, Header, direction: :row
28
+ component :body, 'ui-comment-body'
29
+ component :footer, Footer, direction: :row
30
+ end
31
+
32
+ # Confirmation for destroy
33
+ confirmation :destroy!, 'Are you sure?'
34
+
35
+ # Initializes the comment by setting
36
+ # the direction attribute
37
+ def initialize
38
+ super
39
+ self[:direction] = :row
40
+ end
41
+
42
+ # Votes up the comment
43
+ def vote_up
44
+ update_votes(1)
45
+ end
46
+
47
+ # Votes down the comment
48
+ def vote_down
49
+ update_votes(-1)
50
+ end
51
+
52
+ # Updates the vote count by the given number
53
+ #
54
+ # @param count [Integer] The count
55
+ def update_votes(count)
56
+ update votes: @data[:votes] + count do |data|
57
+ self.data = data
58
+ end
59
+ end
60
+
61
+ # Destroys the comment and trigger refresh
62
+ def destroy!
63
+ destroy { trigger :refresh }
64
+ end
65
+
66
+ # Renders the comment
67
+ def render
68
+ @image.src = @data[:user][:image]
69
+ @box.body.html = @data[:body]
70
+ @box.header.render @data
71
+ @box.footer.render @data
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,93 @@
1
+ require_relative 'header'
2
+ require_relative 'footer'
3
+ require_relative 'comment'
4
+ require_relative 'list'
5
+
6
+ module Examples
7
+ # Comments example
8
+ class Comments < UI::Container
9
+ # Includes
10
+ include UI::Behaviors::Actions
11
+ include UI::Behaviors::Rest
12
+
13
+ # Extends
14
+ extend Forwardable
15
+
16
+ tag 'ui-comments'
17
+
18
+ # REST
19
+ rest url: 'http://localhost:3000/comments'
20
+
21
+ # Style
22
+ style margin: '2em auto',
23
+ maxWidth: 42.em,
24
+ fontSize: 16.px,
25
+ '> ui-container' => { borderBottom: -> { "#{(theme.border_size / 1.5).em} dashed #{dampen colors.background, 0.05}" },
26
+ paddingBottom: -> { theme.spacing.em },
27
+ marginBottom: -> { theme.spacing.em },
28
+ 'ui-button' => { maxWidth: 10.em,
29
+ alignSelf: 'flex-end' },
30
+ textarea: { border: -> { "#{(theme.border_size / 1.5).em} solid #{dampen colors.background, 0.05}" },
31
+ boxSizing: 'border-box',
32
+ minHeight: 7.em,
33
+ flex: 1 } }
34
+
35
+ # Components
36
+ component :form, UI::Container do
37
+ component :title, UI::Title, text: 'Leave a comment', flex: '0 0 auto'
38
+ component :box, UI::Container, direction: :row do
39
+ component :image, UI::Image, src: Lorem.avatar, width: 4.em, height: 4.em
40
+ component :input, UI::Textarea, spellcheck: false
41
+ end
42
+ component :button, UI::Button, text: 'Comment', action: :add
43
+ end
44
+ component :list, List, base: Comment
45
+
46
+ # Delegations
47
+ def_delegators :form, :box
48
+ def_delegators :box, :image, :input
49
+
50
+ # Events
51
+ on :refresh, :load
52
+
53
+ # Adds a new comment
54
+ def add
55
+ return if input.value.empty?
56
+
57
+ data = {
58
+ id: SecureRandom.uuid,
59
+ date: Time.now,
60
+ votes: 0,
61
+ user: {
62
+ name: name,
63
+ image: image.src
64
+ },
65
+ body: input.value.split("\n").map { |paragraph| "<p>#{paragraph}</p>" }.join('')
66
+ }
67
+
68
+ create data do
69
+ input.value = ''
70
+ load
71
+ end
72
+ end
73
+
74
+ # Starts to reply by focusing the input field
75
+ def reply
76
+ input.focus
77
+ end
78
+
79
+ # Returns the current users name
80
+ #
81
+ # @return [String] The name
82
+ def name
83
+ @name ||= Lorem.name
84
+ end
85
+
86
+ # Loads comments from the server
87
+ def load
88
+ all do |items|
89
+ @list.items = items.reverse
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,36 @@
1
+ module Examples
2
+ class Comments < UI::Container
3
+ # Comment footer
4
+ class Footer < UI::Container
5
+ # Tagname
6
+ tag 'ui-comment-footer'
7
+
8
+ # Style
9
+ style color: -> { dampen colors.background, 0.3 },
10
+ span: { opacity: 0.8 },
11
+ fontSize: 0.8.em,
12
+ '&[direction=row]:not([compact]) > * + *' => { marginLeft: -> { (theme.spacing / 2).em } },
13
+ 'ui-label' => { marginRight: -> { (theme.spacing / 2).em } },
14
+ 'ui-action' => { display: :flex, fontWeight: 600 }
15
+
16
+ # Components
17
+ component :vote_up, UI::Action, direction: :row, action: :vote_up do
18
+ component :label, UI::Label, text: 0
19
+ component :icon, UI::Icon, glyph: 'chevron-up'
20
+ end
21
+ component :span, :span, text: '|'
22
+ component :vote_down, UI::Action, action: :vote_down do
23
+ component :icon, UI::Icon, glyph: 'chevron-down'
24
+ end
25
+ component :span, :span, text: '|'
26
+ component :reply, UI::Action, text: 'Reply', action: :reply
27
+
28
+ # Renders the component
29
+ #
30
+ # @param data [Hash] The data
31
+ def render(data)
32
+ @vote_up.label.text = data[:votes]
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ module Examples
2
+ class Comments < UI::Container
3
+ # Comment header
4
+ class Header < UI::Container
5
+ # Tagname
6
+ tag 'ui-comment-header'
7
+
8
+ # Style
9
+ style 'ui-time' => { fontSize: 0.85.em,
10
+ lineHeight: 1.5,
11
+ opacity: 0.4,
12
+ '&:before' => { content: '"-"',
13
+ marginRight: -> { (theme.spacing / 2).em } } },
14
+ '&[direction=row]:not([compact]) > * + *' => { marginLeft: -> { (theme.spacing / 2).em } },
15
+ 'ui-label' => { fontWeight: 600 },
16
+ 'ui-action' => { display: :none }
17
+
18
+ # Components
19
+ component :user, UI::Label
20
+ component :date, UI::Time, from_now: true
21
+ component :spacer, UI::Base, flex: 1
22
+ component :action, UI::Action, action: :confirm_destroy! do
23
+ component :icon, UI::Icon, glyph: 'android-close'
24
+ end
25
+
26
+ # Renders the component
27
+ #
28
+ # @param data [Hash] The data
29
+ def render(data)
30
+ @date.value = data[:date]
31
+ @user.text = data[:user][:name]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ module Examples
2
+ class Comments < UI::Container
3
+ # Comment List
4
+ class List < Collection
5
+ # Tagname
6
+ tag 'ui-comments-list'
7
+
8
+ # Styles
9
+ style '> * + *' => { marginTop: -> { (theme.spacing * 2).em } }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ require 'fron_ui'
2
+ require_tree './components'
3
+ comments = Examples::Comments.new
4
+ comments >> DOM::Document.body
5
+ comments.load
6
+ Fron::Sheet.render_style_tag
@@ -0,0 +1,100 @@
1
+ require_relative 'details'
2
+ require_relative 'sidebar'
3
+
4
+ module Examples
5
+ # Contacts example
6
+ class Contacts < UI::Container
7
+ include UI::Behaviors::Actions
8
+ include UI::Behaviors::Render
9
+ include UI::Behaviors::Rest
10
+ include UI::Behaviors::State
11
+
12
+ extend Forwardable
13
+
14
+ rest url: 'http://localhost:3000/contacts'
15
+
16
+ component :sidebar, Sidebar, flex: '0 0 20em'
17
+ component :details, Details, flex: 1
18
+
19
+ style fontSize: 14.px,
20
+ width: 67.5.em,
21
+ margin: '0 auto',
22
+ height: 57.5.em,
23
+ padding: -> { theme.spacing.em },
24
+ boxSizing: 'border-box'
25
+
26
+ render :render!
27
+
28
+ def_delegators :class, :storage
29
+
30
+ on :selected_change, :select
31
+ on :input, 'ui-sidebar input', :render
32
+ on :refresh, :refresh
33
+ on :destroyed, :destroyed
34
+
35
+ state_changed :state_changed
36
+
37
+ # Initializes the component
38
+ def initialize
39
+ super
40
+ @items = []
41
+ self[:direction] = :row
42
+ end
43
+
44
+ # Handles state change
45
+ def state_changed
46
+ load state
47
+ render!
48
+ end
49
+
50
+ # Adds a new contact
51
+ def add
52
+ data = {
53
+ id: SecureRandom.uuid
54
+ }
55
+
56
+ create data do |item|
57
+ refresh do
58
+ @sidebar.input.value = ''
59
+ render!
60
+ self.state = item[:id]
61
+ end
62
+ end
63
+ end
64
+
65
+ # Handles item selection from the list
66
+ def select
67
+ self.state = @sidebar.selected.data[:id]
68
+ end
69
+
70
+ # Loads the contact with the given id
71
+ #
72
+ # @param id [String] The ID
73
+ def load(id)
74
+ @details.load id
75
+ render!
76
+ end
77
+
78
+ # Handles the destroyed event
79
+ #
80
+ # @param event [DOM::Event] The event
81
+ def destroyed(event)
82
+ self.state = nil if event.target.data[:id] == state
83
+ refresh
84
+ end
85
+
86
+ # Refreshes the list
87
+ def refresh
88
+ all do |items|
89
+ @items = items
90
+ render { yield if block_given? }
91
+ end
92
+ end
93
+
94
+ # Renders the list
95
+ def render!
96
+ @sidebar.items = @items.select { |item| item[:name].to_s.match Regexp.new(@sidebar.input.value || '.*', 'i') }
97
+ @sidebar.select state
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,92 @@
1
+ module Examples
2
+ class Contacts < UI::Container
3
+ # Details
4
+ class Details < UI::Box
5
+ include UI::Behaviors::Confirmation
6
+ include UI::Behaviors::Serialize
7
+ include UI::Behaviors::Actions
8
+ include UI::Behaviors::Rest
9
+
10
+ tag 'ui-details'
11
+
12
+ rest url: 'http://localhost:3000/contacts'
13
+
14
+ style 'ui-image' => { margin: -> { theme.spacing.em },
15
+ height: 15.em,
16
+ width: 15.em },
17
+ 'ui-container' => { padding: -> { theme.spacing.em } },
18
+ 'ui-container ui-container' => { maxWidth: 30.em },
19
+ 'ui-label' => { fontWeight: 600 },
20
+ 'input' => { fontSize: 1.2.em },
21
+ 'ui-loader' => { fontSize: 2.em },
22
+ '&.empty' => {
23
+ '> ui-container, > ui-button' => {
24
+ display: :none
25
+ },
26
+ '&:after' => {
27
+ content: "'No contact selected!'",
28
+ padding: -> { (theme.spacing * 3).em },
29
+ textAlign: :center,
30
+ fontSize: 2.em,
31
+ opacity: 0.25
32
+ }
33
+ }
34
+
35
+ component :title, UI::Title, text: 'Contact Details'
36
+
37
+ component :box, UI::Container, flex: 1, direction: :row do
38
+ component :image, UI::Image
39
+ component :form, UI::Container, flex: 1 do
40
+ component :label, UI::Label, text: 'Full Name:'
41
+ component :input, UI::Input, placeholder: 'Tony Stark', name: :name
42
+ component :label, UI::Label, text: 'E-mail:'
43
+ component :input, UI::Input, placeholder: 'tony@stark-industries.com', name: :email
44
+ component :label, UI::Label, text: 'Address:'
45
+ component :input, UI::Input, placeholder: '10880 Malibu Point, Malibu, Calif', name: :address
46
+ component :label, UI::Label, text: 'Phone:'
47
+ component :input, UI::Input, placeholder: '+1-202-555-0160', name: :phone
48
+ end
49
+ end
50
+
51
+ component :button, UI::Button, type: 'danger', text: 'Remove Contact', action: :confirm_destroy!
52
+
53
+ confirmation :destroy!, 'Are you sure you want to remove this contact?'
54
+
55
+ on :change, :save
56
+
57
+ # Loads the contact with the given id
58
+ #
59
+ # @param id [String] The ID
60
+ def load(id)
61
+ return add_class :empty if id.empty?
62
+ request :get, id do |data|
63
+ break add_class :empty unless data
64
+ super data
65
+ remove_class :empty
66
+ render
67
+ end
68
+ end
69
+
70
+ # Saves the contact
71
+ def save
72
+ update data do
73
+ @data.merge! data
74
+ render
75
+ trigger :refresh
76
+ end
77
+ end
78
+
79
+ # Destroys the contact
80
+ def destroy!
81
+ destroy do
82
+ trigger :destroyed
83
+ end
84
+ end
85
+
86
+ # Renders the contact image
87
+ def render
88
+ @box.image.src = 'http://www.gravatar.com/avatar/' + `md5(#{data[:email] || ''})` + '?s=200&d=identicon'
89
+ end
90
+ end
91
+ end
92
+ end