├── .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 | Essence GEM Version 7 | 8 | 9 | 10 | Essence GEM Version 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 | Essence GEM Version 7 | 8 | 9 | 10 | Essence GEM Version 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 | --------------------------------------------------------------------------------