Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
PATH
remote: .
specs:
rolemodel-rails (1.1.0)
rolemodel-rails (2.0.0)
benchmark
rails (> 7.1)

GEM
Expand Down
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ rails db:create
Add this line to your application's Gemfile:

```ruby
gem 'rolemodel-rails', group: :development
gem 'rolemodel-rails'
```

> [!IMPORTANT]
> We used to recommend putting rolemodel-rails in the development gem group. This is no longer supported, because some Rolemodel namespaced utility modules and classes are expected to be available at runtime.

And then execute:

$ bundle
$ bundle install

## Usage

Expand Down Expand Up @@ -116,10 +119,6 @@ bin/new_generator testing/fantasitic_specs 'A Fantastic Testing Framework'
We use the embeded Rails apps (`example_rails_current` & `example_rails_legacy`) to test generators against. They reference the rolemodel-rails gem by local path,
so you can navigate into one of them and run your generator for immediate feedback while developing.

> [!IMPORTANT]
> Before submitting a PR, run `bin/bump_version` to ensure the Gem builds successfully & that everything continues to stay in sync & up-to-date.<br /><br />
> For very small changes & bug fixes, prefer `bin/bump_version --patch`.

## Testing

Generator specs should be added to the [spec](./spec) directory.
Expand Down
2 changes: 1 addition & 1 deletion example_rails_legacy/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: ..
specs:
rolemodel-rails (1.1.0)
rolemodel-rails (2.0.0)
rails (> 7.1)

GEM
Expand Down
7 changes: 6 additions & 1 deletion lib/generators/rolemodel/optics/icons/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@

## What you get

Adds icon helper for handling material icons and custom icons
Adds icon helper for handling icon generation using the provider of your choice.

## Icon Builder Customization

Run the generator with the `-i` option to install the IconBuilders themselves in your
application's `lib/rolemodel/optics` directory.
23 changes: 14 additions & 9 deletions lib/generators/rolemodel/optics/icons/icons_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Rolemodel
module Optics
# Generates the icon helper and icon builders for the chosen icon library
class IconsGenerator < Rolemodel::GeneratorBase
BUILDER_DIR = 'rolemodel/optics'
SUPPORTED_LIBRARIES = HashWithIndifferentAccess.new(
material: 'filled, size, weight, emphasis, additional_classes, color, hover_text',
phosphor: 'duotone, filled, size, weight, additional_classes, color, hover_text',
Expand All @@ -14,30 +15,34 @@ class IconsGenerator < Rolemodel::GeneratorBase
).freeze

source_root File.expand_path('templates', __dir__)
class_option :install_builders, aliases: '-i', type: :boolean, default: false,
desc: "Install IconBuilder classes for customization"

class_exclusive do
SUPPORTED_LIBRARIES.keys.each do |library|
class_option library, type: :boolean, lazy_default: false, desc: "Use #{library} icon library"
end
end

def remove_existing_icon_helper_and_builders
remove_dir 'app/icon_builders'
remove_file 'app/helpers/icon_helper.rb'
end

def add_view_helper
@chosen_library = capture_user_selection
@supported_properties = SUPPORTED_LIBRARIES.fetch(@chosen_library)

template 'app/icon_builders/icon_builder.rb'
template "app/icon_builders/#{@chosen_library}_icon_builder.rb"
template 'app/helpers/icon_helper.rb'
template 'app/helpers/icon_helper.rb', force: true
end

def install_builders
return unless options.install_builders?

source_paths << File.expand_path(BUILDER_DIR, Rolemodel::GEM_LIB)
copy_file 'icon_builder.rb', "lib/#{BUILDER_DIR}/icon_builder.rb", force: true
copy_file "#{@chosen_library}_icon_builder.rb", "lib/#{BUILDER_DIR}/#{@chosen_library}_icon_builder.rb", force: true
end

private

def capture_user_selection
options.except(*%i[skip_namespace skip_collision_check]).invert[true] || ask(
options.slice(*SUPPORTED_LIBRARIES.keys).invert[true] || ask(
'What icon library would you like to add?',
default: SUPPORTED_LIBRARIES.keys.first.to_s,
limited_to: SUPPORTED_LIBRARIES.keys.map(&:to_s)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'rolemodel/optics'

# Helper method that renders icons from your icon library of choice.
#
# Usage:
Expand All @@ -14,11 +16,11 @@
module IconHelper
# <%= @supported_properties %>
def icon(name, **)
<%= @chosen_library.classify %>IconBuilder.new(name, **).build
Rolemodel::Optics::<%= @chosen_library.classify %>IconBuilder.new(name, **).build
end

# <%= @supported_properties %>
def flash_icon(type, **)
<%= @chosen_library.classify %>IconBuilder.flash_icon(type, **).build
Rolemodel::Optics::<%= @chosen_library.classify %>IconBuilder.flash_icon(type, **).build
end
end
2 changes: 2 additions & 0 deletions lib/rolemodel-rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Rolemodel
NODE_VERSION = '24.12.0'
RUBY_VERSION = '4.0.1'

GEM_LIB = File.expand_path(__dir__)
end

require 'rolemodel/version'
Expand Down
9 changes: 9 additions & 0 deletions lib/rolemodel/optics.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Rolemodel::Optics
autoload :IconBuilder, 'rolemodel/optics/icon_builder'
autoload :CustomIconBuilder, 'rolemodel/optics/custom_icon_builder'
autoload :FeatherIconBuilder, 'rolemodel/optics/feather_icon_builder'
autoload :LucideIconBuilder, 'rolemodel/optics/lucide_icon_builder'
autoload :MaterialIconBuilder, 'rolemodel/optics/material_icon_builder'
autoload :PhosphorIconBuilder, 'rolemodel/optics/phosphor_icon_builder'
autoload :TablerIconBuilder, 'rolemodel/optics/tabler_icon_builder'
end
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# CustomIconBuilder is an IconBuilder that allows for custom SVG icons to be used in the application.
class CustomIconBuilder < IconBuilder
class Rolemodel::Optics::CustomIconBuilder < Rolemodel::Optics::IconBuilder
def self.flash_icons
{
notice: 'circle-check',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# FeatherIconBuilder is an IconBuilder that allows for Feather icons to be used in the application.
# https://feathericons.com/
class FeatherIconBuilder < IconBuilder
class Rolemodel::Optics::FeatherIconBuilder < Rolemodel::Optics::IconBuilder
def self.flash_icons
{
notice: 'check-circle',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# frozen_string_literal: true

class IconBuilder
class Rolemodel::Optics::IconBuilder
include ActionView::Helpers::TagHelper

attr_reader :name, :filled, :size, :weight, :emphasis, :duotone, :additional_classes, :color, :hover_text
alias title hover_text

DEFAULT_SIZE = 'medium'
DEFAULT_WEIGHT = 'normal'
DEFAULT_EMPHASIS = 'normal'

# TODO: consider Data.define a custom options object if all of these parameters are indeed necessary.
def initialize( # rubocop:disable Metrics/ParameterLists
name,
filled: false,
Expand Down Expand Up @@ -42,32 +44,21 @@ def self.flash_icons
def build
options = {
class: tag_classes.compact_blank.join(' '),
title: hover_text
}

if color.present?
title: hover_text,
# color: primary, neutral, alerts-notice, alerts-warning, alerts-danger, alerts-info
options[:style] = "#{color_attribute}: var(--op-color-#{color}-base);"
end
style: ("#{color_attribute}: var(--op-color-#{color}-base);" if color.present?)
}.compact_blank

tag.send(tag_method, tag_contents, **options)
tag.public_send(tag_method, tag_contents, **options)
end

private

def tag_method
raise NotImplementedError
end

def tag_contents
''
end

def tag_classes
['icon', size == DEFAULT_SIZE ? '' : "icon--#{size}", additional_classes]
end

def color_attribute
'color'
end
def color_attribute = 'color'
def tag_contents = ''
def tag_method = :i
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# LucideIconBuilder is an IconBuilder that allows for Lucide icons to be used in the application.
# https://lucide.dev/icons/
class LucideIconBuilder < IconBuilder
class Rolemodel::Optics::LucideIconBuilder < Rolemodel::Optics::IconBuilder
def self.flash_icons
{
notice: 'circle-check',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# MaterialIconBuilder is an IconBuilder that allows for Material icons to be used in the application.
# https://fonts.google.com/icons
class MaterialIconBuilder < IconBuilder
class Rolemodel::Optics::MaterialIconBuilder < Rolemodel::Optics::IconBuilder
def self.flash_icons
{
notice: 'check_circle',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# PhosphorIconBuilder is an IconBuilder that allows for Phosphor icons to be used in the application.
# https://phosphoricons.com/
class PhosphorIconBuilder < IconBuilder
class Rolemodel::Optics::PhosphorIconBuilder < Rolemodel::Optics::IconBuilder
def self.flash_icons
{
notice: 'check-circle',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# TablerIconBuilder is an IconBuilder that allows for Tabler icons to be used in the application.
# https://tablericons.com/
class TablerIconBuilder < IconBuilder
class Rolemodel::Optics::TablerIconBuilder < Rolemodel::Optics::IconBuilder
def self.flash_icons
{
notice: 'circle-check',
Expand Down
3 changes: 3 additions & 0 deletions lib/rolemodel/utility.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Rolemodel::Utility
autoload :TaskTools, 'rolemodel/utility/task_tools'
end
42 changes: 42 additions & 0 deletions lib/rolemodel/utility/task_tools.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require 'benchmark'

module Rolemodel
module Utility
module TaskTools
PROGRESS = %w[⠏ ⠇ ⠧ ⠦ ⠴ ⠼ ⠸ ⠹ ⠙ ⠋].cycle

# based on the migration helper of the same name
def say_with_time(message, &)
say message
time = Benchmark.measure(&)
say '%.4fs' % time.real, subitem: true
end

def say(message, subitem: false)
puts "#{subitem ? ' ->' : '--'} #{message}" # rubocop:disable Rails/Output
end

##
# Indicate the progress of a long-running process
#
# Usage (with a known total):
# 100.times do |i|
# indicate_progress(i, 100)
# end
#
# Only update every 'report_interval' iteration for eye-trackable animation speed
# Also displays a completion percentage if a total is provided
def indicate_progress(index, total = nil, report_interval: 9)
return unless (index % report_interval).zero?

print("#{PROGRESS.next} #{to_percent(index, total) if total}\r") # rubocop:disable Rails/Output
end

private

def to_percent(index, total)
'%3.f%%' % (index / total.to_f * 100.0)
end
end
end
end
2 changes: 1 addition & 1 deletion lib/rolemodel/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Rolemodel
VERSION = '1.1.0'
VERSION = '2.0.0'
end
1 change: 1 addition & 0 deletions rolemodel-rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
spec.require_paths = ['lib']

spec.add_dependency 'rails', '> 7.1'
spec.add_dependency 'benchmark'

spec.add_development_dependency 'bundler', '~> 4'
spec.add_development_dependency 'generator_spec', '~> 0.10'
Expand Down
Loading