dedalus 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.gitignore +7 -0
  4. data/.rspec +1 -0
  5. data/.yardopts +1 -0
  6. data/ChangeLog.md +4 -0
  7. data/Gemfile +11 -0
  8. data/LICENSE.txt +20 -0
  9. data/README.md +135 -0
  10. data/Rakefile +42 -0
  11. data/bin/dedalus +20 -0
  12. data/dedalus.gemspec +60 -0
  13. data/features/.gitkeep +0 -0
  14. data/features/dedalus.feature +1 -0
  15. data/features/step_definitions/.gitkeep +0 -0
  16. data/features/step_definitions/dedalus_steps.rb +1 -0
  17. data/gemspec.yml +20 -0
  18. data/lib/dedalus/app_view_composer.rb +60 -0
  19. data/lib/dedalus/application_view.rb +48 -0
  20. data/lib/dedalus/elements/heading.rb +13 -0
  21. data/lib/dedalus/elements/icon.rb +21 -0
  22. data/lib/dedalus/elements/image.rb +53 -0
  23. data/lib/dedalus/elements/paragraph.rb +13 -0
  24. data/lib/dedalus/elements/text.rb +44 -0
  25. data/lib/dedalus/elements.rb +78 -0
  26. data/lib/dedalus/palette.rb +89 -0
  27. data/lib/dedalus/pattern_library/application.rb +140 -0
  28. data/lib/dedalus/pattern_library/application_view.rb +28 -0
  29. data/lib/dedalus/pattern_library/library_view.rb +7 -0
  30. data/lib/dedalus/pattern_library/models/library.rb +10 -0
  31. data/lib/dedalus/pattern_library/models/library_item.rb +11 -0
  32. data/lib/dedalus/pattern_library/models/library_section.rb +26 -0
  33. data/lib/dedalus/pattern_library/molecules/library_item_example.rb +50 -0
  34. data/lib/dedalus/pattern_library/molecules/library_section_tab.rb +62 -0
  35. data/lib/dedalus/pattern_library/molecules/periodic_table.rb +32 -0
  36. data/lib/dedalus/pattern_library/molecules/periodic_table_entry.rb +70 -0
  37. data/lib/dedalus/pattern_library/organisms/app_footer.rb +37 -0
  38. data/lib/dedalus/pattern_library/organisms/app_header.rb +36 -0
  39. data/lib/dedalus/pattern_library/organisms/app_sidebar.rb +29 -0
  40. data/lib/dedalus/pattern_library/organisms/library_entry.rb +64 -0
  41. data/lib/dedalus/pattern_library/screens/app_screen.rb +22 -0
  42. data/lib/dedalus/pattern_library/templates/app_template.rb +94 -0
  43. data/lib/dedalus/pattern_library.rb +1 -0
  44. data/lib/dedalus/version.rb +4 -0
  45. data/lib/dedalus/view_traversal.rb +129 -0
  46. data/lib/dedalus.rb +40 -0
  47. data/media/icons/arrow_cursor.png +0 -0
  48. data/media/icons/atom.png +0 -0
  49. data/media/icons/hive.png +0 -0
  50. data/media/icons/house.png +0 -0
  51. data/media/icons/molecule.png +0 -0
  52. data/media/icons/paramecium.png +0 -0
  53. data/spec/dedalus_spec.rb +28 -0
  54. data/spec/spec_helper.rb +4 -0
  55. metadata +226 -0
@@ -0,0 +1,89 @@
1
+ module Dedalus
2
+ class Color
3
+ attr_accessor :red, :green, :blue, :alpha
4
+
5
+ def initialize(red,green,blue,alpha=255)
6
+ @red = red
7
+ @green = green
8
+ @blue = blue
9
+ @alpha = alpha
10
+ end
11
+
12
+ # def mix(other_color)
13
+ # Color.new(
14
+ # (red+other_color.red/2),
15
+ # (green+other_color.green/2),
16
+ # (blue+other_color.blue/2)
17
+ # )
18
+ # end
19
+
20
+ def darken(ratio=0.90)
21
+ Color.new(red*ratio,green*ratio,blue*ratio)
22
+ end
23
+
24
+ def lighten(ratio=1.10)
25
+ Color.new(red*ratio,green*ratio,blue*ratio)
26
+ end
27
+
28
+ def to_gosu
29
+ Gosu::Color.rgba(red, green, blue, alpha)
30
+ end
31
+ end
32
+
33
+ class ColorPalette
34
+ attr_accessor :red, :green, :blue, :yellow, :purple, :gray, :white
35
+ def initialize(red:, green:, blue:, yellow:, purple:, gray:, white: Color.new(240,240,240))
36
+ @red = red
37
+ @green = green
38
+ @blue = blue
39
+ @yellow = yellow
40
+ @purple = purple
41
+ @gray = gray
42
+ @white = white
43
+ end
44
+
45
+ def decode_color(color)
46
+ return color if color.is_a?(Dedalus::Color)
47
+
48
+ case color
49
+ when 'red' then red
50
+ when 'lightred' then red.lighten
51
+ when 'darkred' then red.darken
52
+
53
+ when 'green' then green
54
+ when 'lightgreen' then green.lighten
55
+ when 'darkgreen' then green.darken
56
+
57
+ when 'blue' then blue
58
+ when 'lightblue' then blue.lighten
59
+ when 'darkblue' then blue.darken
60
+
61
+ when 'yellow' then yellow
62
+ when 'lightyellow' then yellow.lighten
63
+ when 'darkyellow' then yellow.darken
64
+
65
+ when 'gray' then gray
66
+ when 'lightgray' then gray.lighten
67
+ when 'darkgray' then gray.darken
68
+
69
+ when 'purple' then purple
70
+ when 'lightpurple' then purple.lighten
71
+ when 'darkpurple' then purple.darken
72
+
73
+ else
74
+ raise "Unknown color string given to #{self.class.name}#decode_color: #{color}"
75
+ end
76
+ end
77
+ end
78
+
79
+ DesaturatedPalette = ColorPalette.new(
80
+ red: Color.new(140, 100, 100),
81
+ green: Color.new(100, 140, 100),
82
+ blue: Color.new(100, 100, 140),
83
+ yellow: Color.new(150, 140, 100),
84
+ purple: Color.new(140, 100, 140),
85
+ gray: Color.new(80, 80, 80)
86
+ )
87
+
88
+ Palette = DesaturatedPalette
89
+ end
@@ -0,0 +1,140 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class Application < Joyce::Application
4
+ viewed_with ApplicationView
5
+ include Models
6
+
7
+ def click
8
+ p [ :app_click ]
9
+ view.click
10
+ end
11
+
12
+ def setup(module_to_search:)
13
+ create_library(module_to_search)
14
+ end
15
+
16
+ def find_descendants_of(klass, module_to_search)
17
+ ObjectSpace.each_object(Class).select { |k| k < klass && find_descendants_of(k, module_to_search).count.zero? && k.name.deconstantize == module_to_search.name }
18
+ end
19
+
20
+ def create_library(module_to_search)
21
+ library = Library.create(name: "Dedalus Pattern Library")
22
+
23
+ atom_section = library.create_library_section(
24
+ name: "Atoms",
25
+ icon: :atom,
26
+ color: 'darkred',
27
+ about: "Components that can't be split further"
28
+ )
29
+
30
+ atom_classes = find_descendants_of(Dedalus::Atom, module_to_search)
31
+ atom_section.build_items_from_classes(atom_classes, kind: 'atom')
32
+
33
+ molecules_section = library.create_library_section(
34
+ name: "Molecules",
35
+ icon: :molecule,
36
+ color: 'yellow',
37
+ about: "Simple compounds of a few atoms"
38
+ )
39
+
40
+ molecule_classes = find_descendants_of(Dedalus::Molecule, module_to_search)
41
+ molecules_section.build_items_from_classes(molecule_classes, kind: 'molecule')
42
+
43
+ organism_section = library.create_library_section({
44
+ name: "Organisms",
45
+ icon: :paramecium,
46
+ color: 'green',
47
+ about: "Highly-complex assemblages of molecules"
48
+ })
49
+
50
+ organism_classes = find_descendants_of(Dedalus::Organism, module_to_search)
51
+ organism_section.build_items_from_classes(organism_classes, kind: 'organism')
52
+
53
+ template_section = library.create_library_section({
54
+ name: "Templates",
55
+ icon: :hive,
56
+ color: 'blue',
57
+ about: "Assembled screens with placeholders"})
58
+
59
+ template_section.create_library_item({
60
+ name: "Library Template",
61
+ item_class_name: 'Dedalus::PatternLibrary::ApplicationTemplate',
62
+ description: "ui library app template",
63
+ example_data: ApplicationTemplate.example_data
64
+ })
65
+
66
+ # just manually create a view from models for now...
67
+ library_data = serialize_library(library)
68
+ library_view = LibraryView.create(library_data)
69
+ view.library_view = library_view
70
+ end
71
+
72
+ def serialize_library(library)
73
+ {
74
+ library_name: library.name,
75
+
76
+ library_sections: [welcome_section] + library.library_sections.map do |section|
77
+ {
78
+ title: section.name,
79
+ subtitle: section.about,
80
+ color: section.color,
81
+ items: section.library_items.map do |item|
82
+ {
83
+ name: item.name,
84
+ kind: item.kind,
85
+ color: section.color,
86
+ description: item.description,
87
+ item_class_name: item.item_class_name,
88
+ item_data: item.example_data
89
+ }
90
+ end
91
+ }
92
+ end,
93
+
94
+ library_section_tabs: [welcome_tab] + library.library_sections.map do |section|
95
+ {
96
+ name: section.name,
97
+ icon: section.icon,
98
+ description: section.about,
99
+ section_color: section.color
100
+ }
101
+ end,
102
+
103
+ library_items: all_library_items
104
+ }
105
+ end
106
+
107
+ def welcome_tab
108
+ {
109
+ name: "Welcome",
110
+ icon: :house,
111
+ description: "About the Library",
112
+ section_color: "darkgray"
113
+ }
114
+ end
115
+
116
+ def welcome_section
117
+ {
118
+ title: "Welcome",
119
+ subtitle: "About the Dedalus library",
120
+ color: 'darkgray',
121
+ show_table: true,
122
+ items: all_library_items
123
+ }
124
+ end
125
+
126
+ def all_library_items
127
+ LibraryItem.all.map do |item|
128
+ {
129
+ name: item.name,
130
+ kind: item.kind,
131
+ color: item.color,
132
+ description: item.description,
133
+ item_class_name: item.item_class_name,
134
+ item_data: item.example_data
135
+ }
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,28 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class ApplicationView < Dedalus::ApplicationView
4
+ attr_accessor :library_view
5
+
6
+ def app_screen
7
+ ApplicationScreen.new(app_template).hydrate(
8
+ library_section_tabs: library_view.library_section_tabs,
9
+ current_entry_name: current_entry_name,
10
+ library_sections: library_view.library_sections,
11
+ library_items: library_view.library_items
12
+ )
13
+ end
14
+
15
+ def app_template
16
+ ApplicationTemplate.new
17
+ end
18
+
19
+ def current_entry_name
20
+ @current_entry_name ||= "Welcome"
21
+ end
22
+
23
+ def route_to(section_name)
24
+ @current_entry_name = section_name
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class LibraryView < Metacosm::View
4
+ attr_accessor :library_name, :library_section_tabs, :library_sections, :library_items
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ module Models
4
+ class Library < Metacosm::Model
5
+ attr_accessor :name
6
+ has_many :library_sections
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ module Models
4
+ class LibraryItem < Metacosm::Model
5
+ attr_accessor :name, :color, :kind, :description
6
+ attr_accessor :item_class_name, :example_data
7
+ belongs_to :library_section
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ module Models
4
+ class LibrarySection < Metacosm::Model
5
+ attr_accessor :name, :about, :description, :icon, :color
6
+ belongs_to :library
7
+ has_many :library_items
8
+
9
+ def build_items_from_classes(klasses, kind:)
10
+ klasses.each do |klass|
11
+ item_name = klass.name.to_s
12
+
13
+ create_library_item(
14
+ name: item_name.demodulize.titleize,
15
+ color: self.color,
16
+ kind: kind,
17
+ item_class_name: item_name,
18
+ description: klass.description,
19
+ example_data: klass.example_data
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class LibraryItemExample < Dedalus::Molecule
4
+ attr_accessor :name
5
+ attr_accessor :item_class_name
6
+ attr_accessor :item_data
7
+ attr_accessor :kind
8
+ attr_accessor :color
9
+
10
+ def show
11
+ [
12
+ Elements::Paragraph.new(text: "EXAMPLE", scale: 0.5, height_percent: 0.05, background_color: background_color.darken),
13
+ item,
14
+ Elements::Paragraph.new(text: item_data, scale: 0.7, background_color: Palette.decode_color('darkgray'), padding: 10)
15
+ ]
16
+ end
17
+
18
+ def item
19
+ item_class_name.constantize.new(item_data)
20
+ end
21
+
22
+ def width_percent
23
+ 0.6
24
+ end
25
+
26
+ def background_color
27
+ if color
28
+ Palette.decode_color(color).darken
29
+ else
30
+ Palette.gray
31
+ end
32
+ end
33
+
34
+ def self.description
35
+ "an example of a pattern"
36
+ end
37
+
38
+ def self.example_data
39
+ {
40
+ name: "Paragraph",
41
+ description: "fake library item molecule",
42
+ item_class_name: 'Dedalus::Elements::Paragraph',
43
+ item_data: { text: "Hi there!" },
44
+ color: 'red', #Palette.red,
45
+ kind: 'Atom'
46
+ }
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,62 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class LibrarySectionTab < Dedalus::Molecule
4
+ attr_accessor :icon, :name, :description, :scale, :highlight, :section_color
5
+
6
+ def show
7
+ [[
8
+ icon_element, [ title_element,
9
+ description_element ]
10
+ ]]
11
+ end
12
+
13
+ def hover
14
+ p [ :hovering_on, section: name ]
15
+ @scale = 0.2
16
+ end
17
+
18
+ def background_color
19
+ bg = Palette.decode_color(section_color)
20
+ self.highlight ? bg.lighten : bg
21
+ end
22
+
23
+ def click
24
+ view.route_to(name)
25
+ end
26
+
27
+ def scale
28
+ @scale ||= 0.0
29
+ end
30
+
31
+ def height
32
+ @height ||= 80
33
+ end
34
+
35
+ def icon_element
36
+ Elements::Icon.for(icon, padding: 16)
37
+ end
38
+
39
+ def title_element
40
+ Elements::Heading.new(text: name, scale: 1.8 + scale)
41
+ end
42
+
43
+ def description_element
44
+ Elements::Paragraph.new(text: description)
45
+ end
46
+
47
+ def self.description
48
+ "navigational tab"
49
+ end
50
+
51
+ def self.example_data
52
+ {
53
+ icon: :house,
54
+ name: "Welcome",
55
+ description: "Hello world (links to Welcome)",
56
+ highlight: false,
57
+ section_color: 'gray'
58
+ }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,32 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class PeriodicTable < Dedalus::Molecule
4
+ attr_accessor :elements
5
+
6
+ def show
7
+ self.element_groups.map do |_, grouped_elements|
8
+ grouped_elements.map do |name:, color:, kind:, **|
9
+ PeriodicTableEntry.new(
10
+ element_name: name,
11
+ color: color,
12
+ kind: kind,
13
+ scale: 0.5
14
+ )
15
+ end
16
+ end
17
+ end
18
+
19
+ def element_groups
20
+ elements.group_by { |elem| elem[:kind] }
21
+ end
22
+
23
+ def self.description
24
+ "A collection of elements"
25
+ end
26
+
27
+ def self.example_data
28
+ { elements: Array.new(4) { LibraryItemExample.example_data } }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,70 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class PeriodicTableEntry < Dedalus::Molecule
4
+ attr_accessor :element_name
5
+ attr_accessor :kind
6
+ attr_accessor :color
7
+ attr_accessor :scale
8
+
9
+ def show
10
+ [
11
+ Elements::Heading.new(text: abbreviation, scale: 6.0 * scale),
12
+ Elements::Paragraph.new(text: element_name, scale: scale),
13
+ Elements::Paragraph.new(text: kind, scale: 0.6 * scale)
14
+ ]
15
+ end
16
+
17
+ def scale
18
+ @scale ||= 1.0
19
+ end
20
+
21
+ def abbreviation
22
+ if element_name.match(/ /) #split(" ").count > 0
23
+ element_name.split(" ").map(&:first).join.capitalize
24
+ else
25
+ element_name.slice(0,2).capitalize
26
+ end
27
+ end
28
+
29
+ def click
30
+ view.route_to(element_name)
31
+ end
32
+
33
+ def margin
34
+ 15 * scale
35
+ end
36
+
37
+ def padding
38
+ 20 * scale
39
+ end
40
+
41
+ def width
42
+ 230 * scale
43
+ end
44
+
45
+ def height
46
+ 250 * scale
47
+ end
48
+
49
+ def background_color
50
+ if color
51
+ c = Palette.decode_color(color) if color.is_a?(String)
52
+ c.darken
53
+ else
54
+ Palette.gray
55
+ end
56
+ end
57
+
58
+ def self.description
59
+ "a high-level view of an element"
60
+ end
61
+
62
+ def self.example_data
63
+ {
64
+ element_abbreviation: "Pa",
65
+ element_name: "Paragraph"
66
+ }
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,37 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class ApplicationFooter < Dedalus::Organism
4
+ attr_accessor :joyce_version, :dedalus_version, :company, :copyright
5
+
6
+ def show
7
+ [ footer_message ]
8
+ end
9
+
10
+ def padding
11
+ 20
12
+ end
13
+
14
+ def self.description
15
+ "An application footer"
16
+ end
17
+
18
+ def self.example_data
19
+ {
20
+ joyce_version: "x.y.z",
21
+ dedalus_version: "a.b.c",
22
+ company: "Hello LLC",
23
+ copyright: "All rights reserved"
24
+ }
25
+ end
26
+
27
+ private
28
+ def footer_message
29
+ @footer_message ||= Elements::Paragraph.new(text: assemble_text, scale: 0.5)
30
+ end
31
+
32
+ def assemble_text
33
+ "Powered by Dedalus v#{dedalus_version} and Joyce v#{joyce_version}. Copyright #{company} #{copyright}. All rights reserved."
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class ApplicationHeader < Dedalus::Organism
4
+ attr_accessor :title, :subtitle
5
+
6
+ def show
7
+ [
8
+ heading,
9
+ subheading
10
+ ]
11
+ end
12
+
13
+ def padding
14
+ 20
15
+ end
16
+
17
+ def self.description
18
+ "An application header"
19
+ end
20
+
21
+ def self.example_data
22
+ { title: "Fake app", description: "Hello world" }
23
+ end
24
+
25
+ private
26
+ def heading
27
+ @heading ||= Elements::Heading.new(text: title)
28
+ end
29
+
30
+ def subheading
31
+ @subheading ||= Elements::Heading.new(text: subtitle, scale: 0.75)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,29 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class ApplicationSidebar < Dedalus::Organism
4
+ attr_accessor :library_section_tab_molecules
5
+
6
+ def show
7
+ self.library_section_tab_molecules
8
+ end
9
+
10
+ def padding
11
+ 0
12
+ end
13
+
14
+ def self.description
15
+ "A sidebar for an application"
16
+ end
17
+
18
+ def self.example_data
19
+ {
20
+ library_section_tab_molecules: [
21
+ LibrarySectionTab.new(LibrarySectionTab.example_data),
22
+ LibrarySectionTab.new(LibrarySectionTab.example_data),
23
+ LibrarySectionTab.new(LibrarySectionTab.example_data)
24
+ ]
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,64 @@
1
+ module Dedalus
2
+ module PatternLibrary
3
+ class LibraryEntry < Dedalus::Organism
4
+ attr_accessor :title, :subtitle, :description, :color, :items, :item, :show_table
5
+
6
+ def self.from_item(item)
7
+ new(title: item[:name], subtitle: item[:description], item: item)
8
+ end
9
+
10
+ def show
11
+ [
12
+ Elements::Heading.new(text: title),
13
+ Elements::Heading.new(text: subtitle, scale: 0.9),
14
+ Elements::Paragraph.new(text: description)
15
+ ] + [ library_items ]
16
+ end
17
+
18
+ def library_items
19
+ if items
20
+ if show_table
21
+ PeriodicTable.new(elements: items)
22
+ else # items
23
+ items.map do |name:, description:, item_class_name:, item_data:, kind:, color:|
24
+ PeriodicTableEntry.new(
25
+ element_name: name,
26
+ color: color,
27
+ kind: kind)
28
+ end
29
+ end
30
+ elsif item
31
+ LibraryItemExample.new(item)
32
+ else
33
+ []
34
+ end
35
+ end
36
+
37
+ def padding
38
+ @padding ||= 40
39
+ end
40
+
41
+ def background_color
42
+ if color
43
+ Palette.decode_color(color).lighten
44
+ elsif item && item[:color]
45
+ Palette.decode_color(item[:color])
46
+ end
47
+ end
48
+
49
+ def self.description
50
+ "An entry in a library"
51
+ end
52
+
53
+ def self.example_data
54
+ {
55
+ title: "Welcome",
56
+ subtitle: "world",
57
+ description: "Welcome to this section",
58
+ color: "darkblue",
59
+ items: [ LibraryItemExample.example_data ]
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end