essence 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9be2e0f4b7e7288c5cf845c54d67988f472a967ebdd04b6d01ac790c1d1c7a4
4
- data.tar.gz: f1ebff9a5f1f108042f48f3241edc2cd5d8998d9605b20d6e52bed3b338219dc
3
+ metadata.gz: 8a05b5cc8ee41e915b4d8646bb7357451484b0d36f9893deb21f58c540838d86
4
+ data.tar.gz: 27b53f351c8b5fb5b6718cdf2c5b4b4834251042dc48657dd2a70ac42e4865be
5
5
  SHA512:
6
- metadata.gz: 067d0df4723dd420b5100d7c21c417f37e959e62e325154fcd3671a22b3b919d51720e6b6a911233a8791065d0a3a93a9b931c0111b5e4b90454aa6c8648b80c
7
- data.tar.gz: 06d8732651332803411614ae867fd3e78ae226853992fd3d0367bc441054925d6647d4c2151d0c3e0af4b24990b8a24891c8042f816789cd454cda9f5197e03d
6
+ metadata.gz: 1f3d8aad9655e9a3d86ca7db39d6bdc03f608bfe6bc79f6cea64591340449b19fa4c9ffbbfe0f8939472b870dcf57508f1a1b0d9d29504757b49e3636ef3c074
7
+ data.tar.gz: 846b1a2df22849a2c8cdb9b8d44a8e7dbc3204e4b90e68b93b8d355ae6aa86076da3206c00594a54d23b714b37562cf38a5e9070bcaf9e590d3120a372dceb16
data/README.md CHANGED
@@ -14,10 +14,10 @@ A simple, ergonomic and performant component library for Ruby applications.
14
14
 
15
15
  ### Features
16
16
 
17
- - Tailored components - Designed using flexibility in mind while streamlining the development process
18
- - Gorgeous simplicity - Essence empowers minimalistic user interface with purposeful accents
19
- - Geared for performance - Keep everything in one place. No spreadsheets or getting lost between tooling
20
- - Ergonomic approach - Essence is designed to be easy to use and understand
17
+ - Tailored components - Flexible by design while streamlining the development process
18
+ - Gorgeous simplicity - Empowers minimalistic user interface with purposeful accents
19
+ - Geared for performance - Built with performance in mind
20
+ - Ergonomic approach - Designed to be easy to use and understand
21
21
 
22
22
  ---
23
23
 
@@ -45,6 +45,7 @@ More information on about the installation can be found in the [documentation](h
45
45
 
46
46
  - [Mintis](https://mintis.app)
47
47
  - [Hansa](https://hansahq.com)
48
+ - [Oversee](https://github.com/primevise/oversee)
48
49
  - [Release Server](https://releaseserver.com)
49
50
  - [College Life Work](https://work.collegelife.co)
50
51
 
@@ -9,8 +9,16 @@ module Essence
9
9
 
10
10
  def call(*args)
11
11
  component_name = args[0][:component_name]
12
+ key = component_name.to_sym
13
+ has_stimulus_controller = Essence.components[key][:stimulus] || false
12
14
 
13
- return puts "> #{component_name}: component unsupported" unless Essence.component_names.include?(component_name.to_sym)
15
+ return puts "> #{component_name}: component unsupported" unless Essence.component_keys.include?(key)
16
+ puts "> [Essence] #{Essence.components[key][:name]}"
17
+
18
+ if has_stimulus_controller
19
+ Essence::CLI::Commands.copy_controller(component_name:)
20
+ puts "> [Stimulus] #{Essence::CLI::Commands::STIMULUS_CONTROLLERS_DESTINATION_DIR.join("#{component_name}_controller.js")}"
21
+ end
14
22
 
15
23
  Essence::CLI::Commands.copy_component(component_name:)
16
24
  Essence::CLI::Commands.replace_component_contents(component_name:)
@@ -20,7 +28,7 @@ module Essence
20
28
  to: Essence::CLI::Commands::PHLEX_COMPONENT_DEFINITION_SUFFIX
21
29
  )
22
30
 
23
- puts "> Successfully added #{component_name} component to #{Essence::CLI::Commands::DESTINATION_DIR.join("#{component_name}.rb")}"
31
+ puts "> [Phlex] #{Essence::CLI::Commands::DESTINATION_DIR.join("#{component_name}.rb")}"
24
32
  end
25
33
  end
26
34
  end
data/lib/essence/cli.rb CHANGED
@@ -17,8 +17,12 @@ module Essence
17
17
  extend Dry::CLI::Registry
18
18
 
19
19
  # Constants
20
+ STIMULUS_CONTROLLERS_DIR = Pathname.new(::Essence.root_path).join("essence/stimulus")
21
+ STIMULUS_CONTROLLERS_DESTINATION_DIR = Pathname.new(File.expand_path(Dir.pwd)).join(::Essence.configuration.stimulus_controller_path)
22
+
20
23
  COMPONENTS_DIR = Pathname.new(File.expand_path("components", __dir__))
21
- DESTINATION_DIR = Pathname.new(File.expand_path(Dir.pwd)).join("app/components")
24
+ DESTINATION_DIR = Pathname.new(File.expand_path(Dir.pwd)).join(::Essence.configuration.phlex_components_path)
25
+
22
26
  COMPONENT_DEFINITION_PREFIX = "class Essence::"
23
27
  COMPONENT_DEFINITION_SUFFIX = "< Essence::Essence"
24
28
  PHLEX_COMPONENT_DEFINITION_PREFIX = "class Components::"
@@ -32,6 +36,7 @@ module Essence
32
36
  private
33
37
 
34
38
  # UTILITIES
39
+ # PHLEX COMPONENTS
35
40
  def self.copy_component(component_name:)
36
41
  source_path = COMPONENTS_DIR.join("#{component_name}.rb")
37
42
  destination_path = DESTINATION_DIR.join("#{component_name}.rb")
@@ -58,6 +63,15 @@ module Essence
58
63
 
59
64
  FileUtils.mv(from, to)
60
65
  end
66
+
67
+ # STIMULUS CONTROLLERS
68
+ def self.copy_controller(component_name:)
69
+ source_path = STIMULUS_CONTROLLERS_DIR.join("#{component_name}_controller.js")
70
+ destination_path = STIMULUS_CONTROLLERS_DESTINATION_DIR.join("#{component_name}_controller.js")
71
+
72
+ FileUtils.mkdir_p(STIMULUS_CONTROLLERS_DESTINATION_DIR)
73
+ FileUtils.copy(source_path, destination_path)
74
+ end
61
75
  end
62
76
  end
63
77
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Essence::Accordion < Essence::Essence
4
+ BASE = "group py-4"
5
+ TRIGGER_BASE = "cursor-pointer list-none flex items-center justify-between text-base font-medium"
6
+ CONTENT_BASE = "py-2 transform transition-all duration-500 not-open:-mt-4 opacity-0 group-open:opacity-100 group-open:mt-0 text-sm"
7
+ CHEVRON_BASE = "transform transition-all duration-300 rotate-90 group-open:-rotate-90 text-lg text-gray-700"
8
+
9
+ attr_reader :attributes
10
+
11
+ def initialize(**attributes)
12
+ super(**attributes)
13
+ @attributes[:class] = merge_classes([ BASE, @attributes[:class]])
14
+ end
15
+
16
+ def view_template(&)
17
+ details(class: "w-full group py-4", &) if block_given?
18
+ end
19
+
20
+ def trigger(**tattributes, &)
21
+ summary(class: merge_classes(TRIGGER_BASE, tattributes[:class])) do
22
+ p(class: "inline", &)
23
+ span(class: CHEVRON_BASE) { "›" }
24
+ end
25
+ end
26
+
27
+ def content(**cattributes, &)
28
+ p(class: merge_classes(CONTENT_BASE, cattributes[:class]), &)
29
+ end
30
+
31
+ private
32
+
33
+ def merge_classes(*classes)
34
+ TAILWIND_MERGER.merge([ *classes ].compact)
35
+ end
36
+ end
@@ -13,9 +13,9 @@ class Essence::Avatar < Essence::Essence
13
13
  attr_reader :size
14
14
 
15
15
  def initialize(size: :md, **attributes)
16
+ super(**attributes)
16
17
  @size = size
17
- @attributes = attributes
18
- @attributes[:class] = construct_classes(@attributes[:class])
18
+ @attributes[:class] = merge_classes([ BASE, SIZES[size], @attributes[:class]])
19
19
  end
20
20
 
21
21
  def view_template(&)
@@ -28,8 +28,4 @@ class Essence::Avatar < Essence::Essence
28
28
  def fallback(**attrs, &)
29
29
  div(**attrs, &)
30
30
  end
31
-
32
- def construct_classes(classes)
33
- TAILWIND_MERGER.merge([ BASE, SIZES[size], classes ].compact)
34
- end
35
31
  end
@@ -25,17 +25,11 @@ class Essence::Badge < Essence::Essence
25
25
  def initialize(size: :md, kind: :primary, **attributes)
26
26
  @size = size
27
27
  @kind = kind
28
- @attributes = attributes
29
- @attributes[:class] = construct_classes(@attributes[:class])
28
+ super(**attributes)
29
+ @attributes[:class] = merge_classes([ BASE, SIZES[size], KINDS[kind], @attributes[:class]])
30
30
  end
31
31
 
32
32
  def view_template(&)
33
33
  div(**attributes, &)
34
34
  end
35
-
36
- private
37
-
38
- def construct_classes(classes)
39
- TAILWIND_MERGER.merge([ BASE, SIZES[size], KINDS[kind], classes ].compact)
40
- end
41
35
  end
@@ -19,7 +19,7 @@ class Essence::Button < Essence::Essence
19
19
  info: "text-white bg-blue-500 hover:bg-blue-400",
20
20
  dark: "text-white bg-gray-900 hover:bg-gray-800",
21
21
  white: "text-gray-900 bg-white hover:bg-gray-200",
22
- ghost: "text-gray-900 bg-white hover:bg-gray-200 hover:text-gray-800"
22
+ ghost: "text-gray-900 hover:bg-gray-200 hover:text-gray-800"
23
23
  }
24
24
 
25
25
  attr_reader :size
@@ -29,8 +29,8 @@ class Essence::Button < Essence::Essence
29
29
  def initialize(size: :md, kind: :primary, **attributes)
30
30
  @size = size
31
31
  @kind = kind
32
- @attributes = attributes
33
- @attributes[:class] = construct_classes(@attributes[:class])
32
+ super(**attributes)
33
+ @attributes[:class] = merge_classes([ BASE, SIZES[size], KINDS[kind], @attributes[:class]])
34
34
  end
35
35
 
36
36
  def view_template(&)
@@ -42,8 +42,4 @@ class Essence::Button < Essence::Essence
42
42
  def element_tag(...)
43
43
  attributes[:href] ? a(...) : button(...)
44
44
  end
45
-
46
- def construct_classes(classes)
47
- TAILWIND_MERGER.merge([ BASE, SIZES[size], KINDS[kind], classes ].compact)
48
- end
49
45
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Essence::Dialog < Essence::Essence
4
+ BASE = ""
5
+
6
+ attr_reader :attributes
7
+
8
+ def initialize(**attributes)
9
+ super(**attributes)
10
+ @attributes[:class] = merge_classes([ BASE, @attributes[:class]])
11
+ end
12
+
13
+ def view_template(&)
14
+ dialog(**attributes) do
15
+ yield if block_given?
16
+ end
17
+ end
18
+
19
+ def footer(&)
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Essence::Dropdown < Essence::Essence
4
+ BASE = ""
5
+
6
+ attr_reader :attributes
7
+
8
+ def initialize(**attributes)
9
+ super(**attributes)
10
+ @attributes[:class] = merge_classes([ BASE, @attributes[:class]])
11
+ end
12
+
13
+ def view_template(&)
14
+ div(**attributes) do
15
+ yield if block_given?
16
+ end
17
+ end
18
+ end
@@ -6,13 +6,11 @@ class Essence::Essence < Phlex::HTML
6
6
  attr_reader :attributes
7
7
 
8
8
  def initialize(**attributes)
9
- @attributes = attributes
10
- @attributes[:class] = TAILWIND_MERGER.merge([self.class::CLASSES, @attributes[:class]]) if @attributes[:class]
9
+ @attributes = default_attributes.deep_merge(attributes)
11
10
  end
12
11
 
13
12
  private
14
13
 
15
- def default_attributes
16
- {}
17
- end
14
+ def default_attributes = {}
15
+ def merge_classes(*classes) = TAILWIND_MERGER.merge([ *classes ].compact)
18
16
  end
@@ -10,8 +10,8 @@ class Essence::Link < Essence::Essence
10
10
  attr_reader :attributes
11
11
 
12
12
  def initialize(kind: :regular, **attributes)
13
- @attributes = attributes
14
- @attributes[:class] = @attributes[:class] ? TAILWIND_MERGER.merge([ BASE, @attributes[:class] ]) : BASE
13
+ super(**attributes)
14
+ @attributes[:class] = merge_classes([ BASE, @attributes[:class]])
15
15
  end
16
16
 
17
17
  def view_template(&)
@@ -14,8 +14,8 @@ class Essence::Row < Essence::Essence
14
14
 
15
15
  def initialize(kind: :default, **attributes)
16
16
  @kind = kind
17
- @attributes = attributes
18
- @attributes[:class] = @attributes[:class] ? TAILWIND_MERGER.merge([ BASE, KINDS[kind], @attributes[:class] ]) : BASE
17
+ super(**attributes)
18
+ @attributes[:class] = merge_classes([ BASE, KINDS[kind], @attributes[:class]])
19
19
  end
20
20
 
21
21
  def view_template(&)
@@ -1,11 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # A skeleton component is used to show a loading state.
4
+ #
5
+ # ==== Examples
6
+ #
7
+ # render Skeleton.new(class: "w-32 h-6")
8
+ #
9
+ # ==== Documentation
10
+ #
11
+ # https://essence.primevise.com/components/skeleton
12
+ #
3
13
  class Essence::Skeleton < Essence::Essence
4
14
  BASE = "animate-pulse bg-gray-200/55 rounded-xs"
5
15
 
6
16
  def initialize(**attributes)
7
- @attributes = attributes
8
- @attributes[:class] = @attributes[:class] ? TAILWIND_MERGER.merge([ BASE, @attributes[:class] ]) : BASE
17
+ super(**attributes)
18
+ @attributes[:class] = merge_classes([ BASE, @attributes[:class]])
9
19
  end
10
20
 
11
21
  def view_template(&)
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Essence::Tabs < Essence::Essence
4
+ BASE = "rounded-lg overflow-hidden"
5
+ TAB_BASE = "inline-flex items-center justify-center w-fit rounded-xs border border-transparent font-medium transition duration-150 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed hover:opacity-90 text-xs px-3 py-2 gap-1.5 text-gray-900 bg-transparent hover:bg-gray-200 hover:text-gray-800"
6
+ TAB_LIST_BASE = "flex items-center gap-2 py-2 border-b"
7
+ PANEL_BASE = "aria-hidden:hidden p-4"
8
+
9
+ attr_reader :attributes
10
+
11
+ def initialize(**attributes)
12
+ super(**attributes)
13
+ @attributes[:class] = merge_classes([ BASE, @attributes[:class] ])
14
+ end
15
+
16
+ def view_template(&)
17
+ div(**attributes, &)
18
+ end
19
+
20
+ def menu(**mattributes, &)
21
+ mattributes[:class] = merge_classes([ TAB_LIST_BASE, mattributes[:class] ])
22
+
23
+ div(**mattributes, &)
24
+ end
25
+
26
+ def tab(key: :general, **mattributes, &)
27
+ mattributes[:id] = "tab-#{key}"
28
+ mattributes[:class] = merge_classes([ TAB_BASE, mattributes[:class] ])
29
+ mattributes[:data] = {
30
+ essence__tabs_target: "tab",
31
+ essence__tabs_panel_id_param: "panel-#{key}",
32
+ action: "essence--tabs#setActiveTab keydown.left->essence--tabs#previous keydown.right->essence--tabs#next"
33
+ }
34
+
35
+ button(**mattributes, &)
36
+ end
37
+
38
+ def panel(key: :general, **mattributes, &)
39
+ mattributes[:id] = "panel-#{key}"
40
+ mattributes[:class] = merge_classes([ PANEL_BASE, mattributes[:class] ])
41
+ mattributes[:data] = {
42
+ essence__tabs_target: "panel"
43
+ }
44
+
45
+ div(**mattributes, &)
46
+ end
47
+
48
+ private
49
+
50
+ def default_attributes
51
+ {
52
+ data: {
53
+ controller: "essence--tabs",
54
+ essence__tabs_active_value: "panel-general"
55
+ }
56
+ }
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ module Essence
2
+ class Configuration
3
+ attr_accessor :phlex_components_path
4
+ attr_accessor :stimulus_controller_path
5
+
6
+ def initialize
7
+ @phlex_components_path = "app/components"
8
+ @stimulus_controller_path = "app/javascript/controllers/essence"
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module Essence
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/essence.rb CHANGED
@@ -2,8 +2,12 @@
2
2
 
3
3
  require "tailwind_merge"
4
4
 
5
+ require_relative "essence/configuration"
6
+
5
7
  module Essence
6
8
  # Autoloading
9
+ # Components
10
+ autoload :Accordion, "essence/components/accordion"
7
11
  autoload :Avatar, "essence/components/avatar"
8
12
  autoload :Badge, "essence/components/badge"
9
13
  autoload :Button, "essence/components/button"
@@ -12,36 +16,83 @@ module Essence
12
16
  autoload :Row, "essence/components/row"
13
17
  autoload :Skeleton, "essence/components/skeleton"
14
18
 
19
+ # CLI
15
20
  autoload :CLI, "essence/cli"
16
21
 
17
- # Components
18
- # Class names and classes are separated to avoid loading in Phlex into the CLI tooling
19
-
20
- def self.component_class_names
21
- @component_class_names ||= {
22
- essence: "Essence::Essence",
23
- avatar: "Essence::Avatar",
24
- badge: "Essence::Badge",
25
- button: "Essence::Button",
26
- link: "Essence::Link",
27
- row: "Essence::Row",
28
- skeleton: "Essence::Skeleton",
29
- }
30
- end
22
+ class << self
23
+ def root_path
24
+ File.dirname(__dir__)
25
+ end
31
26
 
32
- def self.component_classes
33
- @components_classes ||= {
34
- essence: ::Essence::Essence,
35
- avatar: ::Essence::Avatar,
36
- badge: ::Essence::Badge,
37
- button: ::Essence::Button,
38
- link: ::Essence::Link,
39
- row: ::Essence::Row,
40
- skeleton: ::Essence::Skeleton,
41
- }
42
- end
27
+ # CONFIGURATION
28
+ def configuration
29
+ @configuration ||= Configuration.new
30
+ end
31
+
32
+ def configure
33
+ yield configuration
34
+ end
35
+
36
+ # COMPONENTS
37
+ def components
38
+ @components ||= {
39
+ accordion: {
40
+ name: "Accordion",
41
+ class_name: "Essence::Accordion",
42
+ stimulus: false
43
+ },
44
+ avatar: {
45
+ name: "Avatar",
46
+ class_name: "Essence::Avatar",
47
+ stimulus: false
48
+ },
49
+ badge: {
50
+ name: "Badge",
51
+ class_name: "Essence::Badge",
52
+ stimulus: false
53
+ },
54
+ button: {
55
+ name: "Button",
56
+ class_name: "Essence::Button",
57
+ stimulus: false
58
+ },
59
+ link: {
60
+ name: "Link",
61
+ class_name: "Essence::Link",
62
+ stimulus: false
63
+ },
64
+ row: {
65
+ name: "Row",
66
+ class_name: "Essence::Row",
67
+ stimulus: false
68
+ },
69
+ skeleton: {
70
+ name: "Skeleton",
71
+ class_name: "Essence::Skeleton",
72
+ stimulus: false
73
+ },
74
+ tabs: {
75
+ name: "Tabs",
76
+ class_name: "Essence::Tabs",
77
+ stimulus: true
78
+ }
79
+ }
80
+ end
81
+
82
+ def component_keys
83
+ @component_keys ||= components.keys
84
+ end
85
+
86
+ def component_names
87
+ @component_names ||= components.transform_values { |v| v[:name] }
88
+ end
89
+
90
+ def component_class_names
91
+ @component_class_names ||= components.transform_values { |v| v[:class_name] }
92
+ end
43
93
 
44
- def self.component_names
45
- @component_names ||= component_class_names.keys
94
+ def component_classes
95
+ @component_classes ||= component_class_names.transform_values { |v| Object.const_get(v) }
96
+ end
46
97
  end
47
98
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: essence
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elvinas Predkelis
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2024-12-22 00:00:00.000000000 Z
12
+ date: 2025-01-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: dry-cli
@@ -74,13 +74,18 @@ files:
74
74
  - lib/essence/cli/add.rb
75
75
  - lib/essence/cli/install.rb
76
76
  - lib/essence/cli/version.rb
77
+ - lib/essence/components/accordion.rb
77
78
  - lib/essence/components/avatar.rb
78
79
  - lib/essence/components/badge.rb
79
80
  - lib/essence/components/button.rb
81
+ - lib/essence/components/dialog.rb
82
+ - lib/essence/components/dropdown.rb
80
83
  - lib/essence/components/essence.rb
81
84
  - lib/essence/components/link.rb
82
85
  - lib/essence/components/row.rb
83
86
  - lib/essence/components/skeleton.rb
87
+ - lib/essence/components/tabs.rb
88
+ - lib/essence/configuration.rb
84
89
  - lib/essence/version.rb
85
90
  homepage: https://rubygems.org/gems/essence
86
91
  licenses: