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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +38 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/.yardopts +8 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +105 -0
- data/Rakefile +37 -0
- data/Readme.md +4 -0
- data/db.json +192 -0
- data/fron-ui.gemspec +21 -0
- data/lib/fron-ui.rb +1 -0
- data/lib/fron_ui.rb +5 -0
- data/lib/fron_ui/version.rb +7 -0
- data/opal/fron-ui/base.rb +49 -0
- data/opal/fron-ui/behaviors/action.rb +40 -0
- data/opal/fron-ui/behaviors/actions.rb +40 -0
- data/opal/fron-ui/behaviors/confirmation.rb +23 -0
- data/opal/fron-ui/behaviors/dropdown.rb +27 -0
- data/opal/fron-ui/behaviors/file.rb +48 -0
- data/opal/fron-ui/behaviors/intendable_children.rb +76 -0
- data/opal/fron-ui/behaviors/keydown.rb +31 -0
- data/opal/fron-ui/behaviors/loop.rb +41 -0
- data/opal/fron-ui/behaviors/render.rb +30 -0
- data/opal/fron-ui/behaviors/rest.rb +121 -0
- data/opal/fron-ui/behaviors/selectable_children.rb +67 -0
- data/opal/fron-ui/behaviors/serialize.rb +32 -0
- data/opal/fron-ui/behaviors/shortcuts.rb +35 -0
- data/opal/fron-ui/behaviors/state.rb +56 -0
- data/opal/fron-ui/behaviors/transition.rb +63 -0
- data/opal/fron-ui/components/action.rb +18 -0
- data/opal/fron-ui/components/box.rb +17 -0
- data/opal/fron-ui/components/button.rb +61 -0
- data/opal/fron-ui/components/calendar.rb +129 -0
- data/opal/fron-ui/components/checkbox.rb +57 -0
- data/opal/fron-ui/components/chooser.rb +246 -0
- data/opal/fron-ui/components/color_panel.rb +235 -0
- data/opal/fron-ui/components/color_picker.rb +111 -0
- data/opal/fron-ui/components/container.rb +61 -0
- data/opal/fron-ui/components/date_picker.rb +141 -0
- data/opal/fron-ui/components/drag.rb +76 -0
- data/opal/fron-ui/components/dropdown.rb +72 -0
- data/opal/fron-ui/components/icon.rb +29 -0
- data/opal/fron-ui/components/image.rb +77 -0
- data/opal/fron-ui/components/input.rb +30 -0
- data/opal/fron-ui/components/label.rb +9 -0
- data/opal/fron-ui/components/list.rb +34 -0
- data/opal/fron-ui/components/loader.rb +63 -0
- data/opal/fron-ui/components/modal.rb +0 -0
- data/opal/fron-ui/components/notifications.rb +73 -0
- data/opal/fron-ui/components/number.rb +202 -0
- data/opal/fron-ui/components/progress.rb +52 -0
- data/opal/fron-ui/components/slider.rb +47 -0
- data/opal/fron-ui/components/tabs.rb +149 -0
- data/opal/fron-ui/components/textarea.rb +13 -0
- data/opal/fron-ui/components/time.rb +65 -0
- data/opal/fron-ui/components/title.rb +34 -0
- data/opal/fron-ui/examples/blog/index.rb +289 -0
- data/opal/fron-ui/examples/comments/components/comment.rb +75 -0
- data/opal/fron-ui/examples/comments/components/comments.rb +93 -0
- data/opal/fron-ui/examples/comments/components/footer.rb +36 -0
- data/opal/fron-ui/examples/comments/components/header.rb +35 -0
- data/opal/fron-ui/examples/comments/components/list.rb +12 -0
- data/opal/fron-ui/examples/comments/index.rb +6 -0
- data/opal/fron-ui/examples/contacts/components/contacts.rb +100 -0
- data/opal/fron-ui/examples/contacts/components/details.rb +92 -0
- data/opal/fron-ui/examples/contacts/components/item.rb +46 -0
- data/opal/fron-ui/examples/contacts/components/list.rb +10 -0
- data/opal/fron-ui/examples/contacts/components/sidebar.rb +30 -0
- data/opal/fron-ui/examples/contacts/index.rb +6 -0
- data/opal/fron-ui/examples/editor/index.rb +164 -0
- data/opal/fron-ui/examples/kitchensink/index.rb +193 -0
- data/opal/fron-ui/examples/todos/components/item.rb +84 -0
- data/opal/fron-ui/examples/todos/components/options.rb +26 -0
- data/opal/fron-ui/examples/todos/components/todos.rb +145 -0
- data/opal/fron-ui/examples/todos/index.rb +6 -0
- data/opal/fron-ui/examples/webshop/index.rb +0 -0
- data/opal/fron-ui/fonts/ionicons.rb +2954 -0
- data/opal/fron-ui/fonts/open_sans.rb +19 -0
- data/opal/fron-ui/lib/collection.rb +138 -0
- data/opal/fron-ui/lib/date.rb +23 -0
- data/opal/fron-ui/lib/debounce.rb +14 -0
- data/opal/fron-ui/lib/image_loader.rb +13 -0
- data/opal/fron-ui/lib/lorem.rb +93 -0
- data/opal/fron-ui/lib/nil.rb +29 -0
- data/opal/fron-ui/lib/record.rb +23 -0
- data/opal/fron-ui/lib/state_serializer.rb +129 -0
- data/opal/fron-ui/lib/storage.rb +57 -0
- data/opal/fron-ui/spec/setup.rb +40 -0
- data/opal/fron-ui/ui.rb +40 -0
- data/opal/fron-ui/utils/theme_roller.rb +63 -0
- data/opal/fron-ui/vendor/autoprefixer.js +21114 -0
- data/opal/fron-ui/vendor/marked.js +1291 -0
- data/opal/fron-ui/vendor/md5.js +274 -0
- data/opal/fron-ui/vendor/moment.js +3083 -0
- data/opal/fron-ui/vendor/uuid.js +92 -0
- data/opal/fron_ui.rb +13 -0
- data/spec/behaviors/action_spec.rb +34 -0
- data/spec/behaviors/actions_spec.rb +38 -0
- data/spec/behaviors/confirmation_spec.rb +23 -0
- data/spec/behaviors/dropdown_spec.rb +32 -0
- data/spec/behaviors/render_spec.rb +20 -0
- data/spec/behaviors/rest_spec.rb +70 -0
- data/spec/behaviors/selectable_children_spec.rb +40 -0
- data/spec/behaviors/serialize_spec.rb +34 -0
- data/spec/components/action_spec.rb +7 -0
- data/spec/components/base_spec.rb +19 -0
- data/spec/components/box_spec.rb +7 -0
- data/spec/components/button_spec.rb +9 -0
- data/spec/components/calendar_spec.rb +58 -0
- data/spec/components/checkbox_spec.rb +20 -0
- data/spec/components/chooser_spec.rb +75 -0
- data/spec/components/color_panel_spec.rb +49 -0
- data/spec/components/color_picker_spec.rb +41 -0
- data/spec/components/container_spec.rb +23 -0
- data/spec/components/date_picker_spec.rb +71 -0
- data/spec/components/drag_spec.rb +20 -0
- data/spec/components/dropdown_spec.rb +33 -0
- data/spec/components/image_spec.rb +33 -0
- data/spec/components/input_spec.rb +8 -0
- data/spec/components/list_spec.rb +10 -0
- data/spec/components/loader_spec.rb +9 -0
- data/spec/components/notifications_spec.rb +17 -0
- data/spec/components/number_spec.rb +64 -0
- data/spec/components/progress_spec.rb +23 -0
- data/spec/components/slider_spec.rb +25 -0
- data/spec/components/tabs_spec.rb +50 -0
- data/spec/components/textarea_spec.rb +7 -0
- data/spec/components/time_spec.rb +37 -0
- data/spec/components/title_spec.rb +11 -0
- data/spec/examples/comments_spec.rb +72 -0
- data/spec/examples/todos_spec.rb +39 -0
- data/spec/lib/collection_spec.rb +38 -0
- data/spec/lib/lorem_spec.rb +55 -0
- data/spec/lib/state_serializer_spec.rb +58 -0
- data/spec/lib/storage_spec.rb +39 -0
- data/spec/spec_helper.rb +1 -0
- 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,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
|