├── .gitignore
├── README.md
└── ruby
├── .gitignore
├── .tool-versions
├── CHANGELOG.md
├── Gemfile
├── Gemfile.lock
├── README.md
├── bin
├── console
└── essence
├── essence.gemspec
├── exe
└── essence
└── lib
├── essence.rb
└── essence
├── cli.rb
├── cli
├── add.rb
├── install.rb
└── version.rb
├── client.rb
├── configuration.rb
└── version.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | .ruby-lsp
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Essence UI
2 |
3 | A simple, ergonomic and performant component library for Ruby applications.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ---
14 |
15 | ### Features
16 |
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 |
22 | ---
23 |
24 | ## Installation
25 |
26 | #### Add gem
27 |
28 | Simply add the gem to your Gemfile by running the following command
29 |
30 | ```bash
31 | bundle add essence
32 | ```
33 |
34 | #### Install Essence
35 |
36 | Run the installation command and we'll take care of the rest
37 |
38 | ```bash
39 | bundle exec essence install
40 | ```
41 |
42 | More information on about the installation can be found in the [documentation](https://essenceui.com/installation)
43 |
44 | ## Who uses Essence?
45 |
46 | - [Mintis](https://mintis.app)
47 | - [Hansa](https://hansahq.com)
48 | - [Oversee](https://github.com/primevise/oversee)
49 | - [No Logo X](https://nologox.com)
50 | - [Release Server](https://releaseserver.com)
51 | - [College Life Work](https://work.collegelife.co)
52 |
53 | Do you use Essence in your project? Let us know!
54 |
55 | ## Licence
56 |
57 | MIT
58 |
--------------------------------------------------------------------------------
/ruby/.gitignore:
--------------------------------------------------------------------------------
1 | .ruby-lsp
2 | .prettierrc
3 | *.gem
4 |
5 | # Just to make sure to ignore dummy files.
6 | app
7 |
--------------------------------------------------------------------------------
/ruby/.tool-versions:
--------------------------------------------------------------------------------
1 | ruby 3.4.2
2 |
--------------------------------------------------------------------------------
/ruby/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | This is the changelog for the `essence` gem. For now, most of the updates will be reflected here.
4 |
5 | ### Unreleased
6 |
7 | - feature: `install` command adds `tailwind_merge` gem
8 |
9 | ### 1.0.2
10 |
11 | - refactor: Adjusting the `add` command to fit the API spec
12 |
13 | ### 1.0.1
14 |
15 | - bug: Fixing a bug where an incorrect file extension was added to Stimulus controllers
16 |
17 | ### 1.0.0
18 |
19 | - _GRAND REFACTOR_: Keeping only the CLI functionality and serving components from a registry.
20 | - refactor: Updating the base `Essence` component
21 | - refactor: Simplifying the `Avatar` component
22 |
23 | ### 0.4.0
24 |
25 | - feature: Adding `Alert` component
26 | - feature: Adding `Checkbox` component
27 | - feature: Adding `Input` component
28 | - feature: Adding `Heading` component
29 | - feature: Adding `Label` component
30 | - feature: Adding `Metric` component
31 | - feature: Adding `Separator` component
32 | - feature: Adding `Switch` component
33 | - feature: Adding `Text` component
34 | - fix: Removing `Phlex::Kit` from the base component
35 | - fix: Removing unecessary autoloading
36 |
37 | ### 0.3.1
38 |
39 | - fix: Including Stimulus files in the gemspec
40 |
41 | ### 0.3.0
42 |
43 | - feature: Adding `Tabs` component
44 | - feature: Adding `Stimulus` controller generator via CLI
45 | - feature: Adding configuration options: `phlex_components_path`, `stimulus_controller_path`
46 | - chore: Initializing some basic RDoc documentation
47 |
48 | ### 0.2.3
49 |
50 | - feature: Adding `Accordion` component
51 | - feature: Merging classes inside the base component
52 | - fix: Fixing the ghost variant of the `Button` component.
53 |
54 | ### 0.2.2
55 |
56 | - fix: Fixing `Avatar` component. It was mixed up with badge for some reason. Oops!
57 | - fix: Fixing `Badge` component. It was mixed up with badge for some reason. Oops!
58 | - fix: Fixing `Button` component. It was mixed up with badge for some reason. Oops!
59 |
60 | ### 0.2.1
61 |
62 | - feature: Adding `Avatar` component
63 | - feature: Adding `Badge` component
64 | - feature: Adding `w-fit` to `Button` component
65 | - fix: Adding `w-fit` to `Link`
66 | - fix: Typo in Row component item definition
67 | - fix: Unifying base class string
68 |
69 | ### 0.2.0
70 |
71 | - feature: Adding a _CLI_ to streamline the process of managing components
72 | - feature: Adding a _CLI_ `install` to install Essence into the project
73 | - feature: Adding a _CLI_ `add` to add component to the project
74 | - chore: Tweaking the components here and there
75 |
--------------------------------------------------------------------------------
/ruby/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3 |
4 | # Specify your gem's dependencies in essence.gemspec.
5 | gemspec
6 |
7 | # Start debugger with binding.b [https://github.com/ruby/debug]
8 | # gem "debug", ">= 1.0.0"
9 |
--------------------------------------------------------------------------------
/ruby/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | essence (1.0.2)
5 | dry-cli (>= 0.7, < 2)
6 | faraday (~> 2.13)
7 |
8 | GEM
9 | remote: https://rubygems.org/
10 | specs:
11 | dry-cli (1.2.0)
12 | faraday (2.13.1)
13 | faraday-net_http (>= 2.0, < 3.5)
14 | json
15 | logger
16 | faraday-net_http (3.4.0)
17 | net-http (>= 0.5.0)
18 | json (2.11.3)
19 | logger (1.7.0)
20 | net-http (0.6.0)
21 | uri
22 | uri (1.0.3)
23 |
24 | PLATFORMS
25 | arm64-darwin-23
26 | ruby
27 |
28 | DEPENDENCIES
29 | essence!
30 |
31 | BUNDLED WITH
32 | 2.5.9
33 |
--------------------------------------------------------------------------------
/ruby/README.md:
--------------------------------------------------------------------------------
1 | # Essence
2 |
3 | A simple, ergonomic and performant component library for Ruby applications.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ---
14 |
15 | ### Features
16 |
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 |
22 | ---
23 |
24 | ## Installation
25 |
26 | #### Add gem
27 |
28 | Simply add the gem to your Gemfile by running the following command
29 |
30 | ```bash
31 | bundle add essence
32 | ```
33 |
34 | #### Install Essence
35 |
36 | Run the installation command and we'll take care of the rest
37 |
38 | ```bash
39 | bundle exec essence install
40 | ```
41 |
42 | More information on about the installation can be found in the [documentation](https://essence.primevise.com/installation)
43 |
44 | ## Who uses Essence?
45 |
46 | - [Mintis](https://mintis.app)
47 | - [Hansa](https://hansahq.com)
48 | - [Oversee](https://github.com/primevise/oversee)
49 | - [Release Server](https://releaseserver.com)
50 | - [College Life Work](https://work.collegelife.co)
51 |
52 | Do you use Essence in your project? Let us know!
53 |
54 | ## Licence
55 |
56 | MIT
57 |
--------------------------------------------------------------------------------
/ruby/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require "bundler/setup"
5 | require "phlex"
6 | require "essence"
7 | require "irb"
8 |
9 | IRB.start(__FILE__)
10 |
--------------------------------------------------------------------------------
/ruby/bin/essence:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "bundler/setup"
4 | require "essence"
5 |
6 | Essence::CLI.call
7 |
--------------------------------------------------------------------------------
/ruby/essence.gemspec:
--------------------------------------------------------------------------------
1 | require_relative "lib/essence/version"
2 |
3 | Gem::Specification.new do |spec|
4 | spec.name = "essence"
5 | spec.version = Essence::VERSION
6 | spec.license = "MIT"
7 | spec.authors = ["Elvinas Predkelis"]
8 | spec.email = ["elvinas@primevise.com"]
9 | spec.homepage = "https://rubygems.org/gems/essence"
10 | spec.summary = "Component library for Ruby applications using Phlex"
11 | spec.description = "Component library for Ruby applications using Phlex"
12 | spec.required_ruby_version = ">= 3.3.1"
13 |
14 | spec.metadata["homepage_uri"] = spec.homepage
15 | spec.metadata["source_code_uri"] = "https://github.com/primevise/essence"
16 |
17 | spec.files = Dir.chdir(File.expand_path(__dir__)) do
18 | Dir["essence/**/*", "{components,lib}/**/*", "exe/*", "LICENCE", "Rakefile", "README.md"]
19 | end
20 |
21 | spec.bindir = "exe"
22 | spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
23 |
24 | spec.add_dependency "dry-cli", ">= 0.7", "< 2"
25 | spec.add_dependency "faraday", "~> 2.13"
26 | end
27 |
--------------------------------------------------------------------------------
/ruby/exe/essence:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require "bundler/setup"
5 | require_relative "../lib/essence"
6 |
7 | Essence::CLI.call
8 |
--------------------------------------------------------------------------------
/ruby/lib/essence.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # require "tailwind_merge"
4 |
5 | require_relative "essence/configuration"
6 | require_relative "essence/definitions"
7 |
8 | module Essence
9 | autoload :CLI, "essence/cli"
10 | autoload :Client, "essence/client"
11 |
12 | class << self
13 | def root_path
14 | File.dirname(__dir__)
15 | end
16 |
17 | # CONFIGURATION
18 | def configuration
19 | @configuration ||= Configuration.new
20 | end
21 |
22 | def configure
23 | yield configuration
24 | end
25 |
26 | def definitions
27 | @definitions ||= Essence::DEFINITIONS
28 | end
29 |
30 | # COMPONENTS
31 | def components
32 | @components ||= {
33 | accordion: {
34 | name: "Accordion",
35 | class_name: "Essence::Accordion",
36 | stimulus: false
37 | },
38 | alert: {
39 | name: "Alert",
40 | class_name: "Essence::Alert",
41 | stimulus: false
42 | },
43 | avatar: {
44 | name: "Avatar",
45 | class_name: "Essence::Avatar",
46 | stimulus: false
47 | },
48 | badge: {
49 | name: "Badge",
50 | class_name: "Essence::Badge",
51 | stimulus: false
52 | },
53 | button: {
54 | name: "Button",
55 | class_name: "Essence::Button",
56 | stimulus: false
57 | },
58 | checkbox: {
59 | name: "Checkbox",
60 | class_name: "Essence::Checkbox",
61 | stimulus: false
62 | },
63 | label: {
64 | name: "Label",
65 | class_name: "Essence::Label",
66 | stimulus: false
67 | },
68 | input: {
69 | name: "Input",
70 | class_name: "Essence::Input",
71 | stimulus: false
72 | },
73 | link: {
74 | name: "Link",
75 | class_name: "Essence::Link",
76 | stimulus: false
77 | },
78 | metric: {
79 | name: "Metric",
80 | class_name: "Essence::Metric",
81 | stimulus: false
82 | },
83 | row: {
84 | name: "Row",
85 | class_name: "Essence::Row",
86 | stimulus: false
87 | },
88 | separator: {
89 | name: "Separator",
90 | class_name: "Essence::Separator",
91 | stimulus: false
92 | },
93 | skeleton: {
94 | name: "Skeleton",
95 | class_name: "Essence::Skeleton",
96 | stimulus: false
97 | },
98 | switch: {
99 | name: "Switch",
100 | class_name: "Essence::Switch",
101 | stimulus: true
102 | },
103 | tabs: {
104 | name: "Tabs",
105 | class_name: "Essence::Tabs",
106 | stimulus: true
107 | }
108 | }
109 | end
110 |
111 | def component_keys
112 | @component_keys ||= components.keys
113 | end
114 |
115 | def component_names
116 | @component_names ||= components.transform_values { |v| v[:name] }
117 | end
118 |
119 | def component_class_names
120 | @component_class_names ||= components.transform_values { |v| v[:class_name] }
121 | end
122 |
123 | def component_classes
124 | @component_classes ||= component_class_names.transform_values { |v| Object.const_get(v) }
125 | end
126 | end
127 | end
128 |
--------------------------------------------------------------------------------
/ruby/lib/essence/cli.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "dry/cli"
4 |
5 | # CLI Commands
6 | require_relative "cli/add"
7 | require_relative "cli/install"
8 | require_relative "cli/version"
9 |
10 | module Essence
11 | module CLI
12 | def self.call(*args)
13 | Dry::CLI.new(Commands).call
14 | end
15 |
16 | module Commands
17 | extend Dry::CLI::Registry
18 |
19 | register "add", Add, aliases: ["a", "generate", "g"]
20 | register "install", Install, aliases: ["i"]
21 | register "version", Version, aliases: ["v", "-v", "--version"]
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/ruby/lib/essence/cli/add.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'fileutils'
4 |
5 | module Essence
6 | module CLI
7 | class Add < Dry::CLI::Command
8 | attr_reader :slug
9 |
10 | desc "Add an Essence UI component"
11 | argument :component, required: true, desc: "Component name"
12 | example Essence.component_names
13 |
14 | def call(*args)
15 | @slug = args[0][:component].to_sym
16 |
17 | puts "[Essence UI] Fetching..."
18 | specification = ::Essence::Client.new.get_component(slug:)
19 | return puts "[Essence UI] Component not found. Stopping" if specification == ""
20 |
21 |
22 | artifacts = specification.dig("artifacts")
23 | return puts "[Essence UI] Something went wrong. Stopping" unless artifacts
24 |
25 | artifacts.each { handle_artifact(artifact: _1) }
26 | puts "[Essence UI] #{specification.dig("title")} has been successfully added!"
27 | end
28 |
29 | private
30 |
31 | def handle_artifact(artifact:)
32 | case artifact["kind"]
33 | when "phlex", "stimulus"
34 | insert_file(artifact:)
35 | when "node_package"
36 | # TODO
37 | end
38 | end
39 |
40 | def insert_file(artifact:)
41 | destination_path = build_destination_path(kind: artifact["kind"], slug:)
42 | return unless destination_path
43 |
44 | ::FileUtils.mkdir_p(destination_path.dirname)
45 | ::File.write(destination_path, artifact.dig("content"))
46 | puts "[Essence UI] Adding #{destination_path}"
47 | end
48 |
49 | def build_destination_path(kind:, slug:)
50 | case kind
51 | when "phlex"
52 | ::Essence.configuration.phlex_components_dir.join("#{slug}.rb")
53 | when "stimulus"
54 | ::Essence.configuration.stimulus_controllers_dir.join("#{slug}_controller.js")
55 | else
56 | nil
57 | end
58 | end
59 | end
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/ruby/lib/essence/cli/install.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Essence
4 | module CLI
5 | class Install < Dry::CLI::Command
6 | BASE_COMPONENT_NAME = "essence"
7 | BASE_DEFINITION_PREFIX = "class Essence::Essence"
8 | PHLEX_BASE_DEFINITION_PREFIX = "class Components::Essence"
9 |
10 | desc "Install Essence UI to your codebase"
11 | def call(*)
12 | puts "[Essence UI] Installing..."
13 | ::Essence::CLI::Add.new.call(*[{component: "essence"}])
14 |
15 |
16 | add_gem("tailwind_merge") unless has_gem?("tailwind_merge")
17 |
18 | # begin
19 | # system(*command)
20 | # if $?.success?
21 | # puts "✅ Successfully added gem 'tailwind_merge' to your Gemfile"
22 | # else
23 | # puts "❌ Failed to add gem 'tailwind_merge' to your Gemfile (exit code: #{$?.exitstatus})"
24 | # end
25 | # rescue => e
26 | # puts "❌ Error: #{e.message}"
27 | # end
28 |
29 | puts "[Essence UI] Done!"
30 | end
31 |
32 | private
33 |
34 | def has_gem?(title)
35 | Bundler.load.specs.find { |s| s.name == title }
36 | end
37 |
38 | def add_gem(title)
39 | puts "[Essence UI] Adding #{title} gem"
40 | command = ["bundle", "add", title]
41 |
42 | begin
43 | system(*command)
44 | if $?.success?
45 | puts "[Essence UI] Successfully added gem 'tailwind_merge' to your Gemfile"
46 | else
47 | puts "[Essence UI] Failed to add gem 'tailwind_merge' to your Gemfile (exit code: #{$?.exitstatus})"
48 | end
49 | rescue => e
50 | puts "[Essence UI] Error: #{e.message}"
51 | end
52 | end
53 | end
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/ruby/lib/essence/cli/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Essence
4 | module CLI
5 | class Version < Dry::CLI::Command
6 | desc "Print version of Essence UI CLI"
7 |
8 | def call(*)
9 | puts Essence::VERSION
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/ruby/lib/essence/client.rb:
--------------------------------------------------------------------------------
1 | require "faraday"
2 |
3 | module Essence
4 | class Client
5 | attr_reader :client
6 |
7 | def initialize(**attributes)
8 | @client = ::Faraday.new(url: "https://essenceui.com/") do |f|
9 | f.request :authorization, "Bearer", -> { ::Essence.configuration.licence_key }
10 | f.request :json
11 | f.response :json
12 | end
13 | end
14 |
15 | def get_component(slug: nil)
16 | return if nil
17 | client.get("api/v1/components/#{slug}").body
18 | rescue Faraday::Error => error
19 | puts error
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/ruby/lib/essence/configuration.rb:
--------------------------------------------------------------------------------
1 | module Essence
2 | class Configuration
3 | attr_accessor :licence_key
4 | attr_accessor :phlex_components_path
5 | attr_accessor :stimulus_controllers_path
6 |
7 | attr_reader :phlex_components_dir
8 | attr_reader :stimulus_controllers_dir
9 |
10 | def initialize
11 | @licence_key = nil
12 | @phlex_components_path = "app/components"
13 | @stimulus_controllers_path = "app/javascript/controllers/essence"
14 |
15 | @phlex_components_dir = Pathname.new(File.expand_path(Dir.pwd)).join(@phlex_components_path)
16 | @stimulus_controllers_dir = Pathname.new(File.expand_path(Dir.pwd)).join(@stimulus_controllers_path)
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/ruby/lib/essence/version.rb:
--------------------------------------------------------------------------------
1 | module Essence
2 | VERSION = "1.0.2"
3 | end
4 |
--------------------------------------------------------------------------------