Skip to content

Commit

Permalink
Merge pull request #1 from inhouse-work/generation-nt
Browse files Browse the repository at this point in the history
Generation nt
  • Loading branch information
nolantait authored Dec 19, 2024
2 parents f178123 + 24e7c9d commit 2921b01
Show file tree
Hide file tree
Showing 320 changed files with 16,060 additions and 127 deletions.
6 changes: 6 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ inherit_gem:

AllCops:
TargetRubyVersion: 3.1

Metrics/MethodLength:
CountAsOne: ['array', 'method_call']

Metrics/ClassLength:
CountAsOne: ['array', 'method_call']
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## [Unreleased]

## [0.4.0] - 2024-12-18

- Removes `unsafe_raw` replaced with protos component generation
- Removes old class lookup, uses constant auto loading instead
- Adds `protos` as an explicit dependency

## [0.3.1] - 2024-12-18

- Fixes issues with passing extra arguments to inhouse icons
Expand Down
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ source "https://rubygems.org"
gemspec

gem "debug"
gem "dry-files"
gem "erb"
gem "phlexing"
gem "rake"
gem "rspec"
gem "rubocop-inhouse", require: false
gem "tqdm"
gem "zeitwerk"
52 changes: 40 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Protos::Icon

Icon component for Phlex with heroicons built in so far. It currently just uses
`unsafe_raw` to output the content of the `.svg` files downloaded from the
heroicons repo.
This gem uses [phlexing](https://github.com/marcoroth/phlexing) component
generation to convert SVG icons into protos components.

This gem does not add any classes or contain the SVG in a container.
It just outputs the SVG. It would be expected you would build this into your own
component or helper.
Other similar libraries to check out:

- [phlex-icons](https://phlex-icons.fun/)

## Installation

Expand All @@ -24,7 +23,7 @@ If bundler is not being used to manage dependencies, install the gem by executin
require "protos-icon"

# This just returns a Phlex component
render Protos::Icon.heroicon("academic-cap", variant: :mini)
render Protos::Icon.find("academic-cap").new(variant: :solid)
```

Or you can include the module in a class and render them as an element:
Expand All @@ -34,15 +33,44 @@ class MyComponent < Phlex::HTML
include Protos::Icon

def template
div(class: "w-6 h-6") do
icon("academic-cap", variant: :mini)
end
icon("academic-cap", variant: :solid, class: "w-6 h-6")
end
end
```

This will call render on the icon component and output it directly to the
component.
Or you can wrap the helper inside your own component:

```ruby
module Ui
class Icon < ApplicationComponent
include Protos::Icon

param :name
option :size, default: -> { :md }
option :variant, default: -> { :solid }

STYLES = {
xs: ["w-3 h-3"],
sm: ["w-4 h-4"],
md: ["w-6 h-6"],
lg: ["w-8 h-8"],
xl: ["w-12 h-12"]
}.freeze

def view_template
icon(name, variant:, **attrs)
end

private

def theme
{
container: STYLES[size]
}
end
end
end
```

## Development

Expand Down
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ RSpec::Core::RakeTask.new(:spec)

task default: :spec

desc "Download Heroicons"
task :download_heroicons do
system "git clone https://github.com/tailwindlabs/heroicons.git"
system "cp -r heroicons/optimized/* assets/heroicons"
Expand Down
10 changes: 2 additions & 8 deletions assets/inhouse/facebook.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 2 additions & 8 deletions assets/inhouse/twitter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 2 additions & 8 deletions assets/inhouse/youtube.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions generators/helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

require "erb"
require "zeitwerk"
require "phlexing"
require "dry/files"
require "tqdm"

def add_autoload_entries(module_file, resources) # rubocop:disable Style/TopLevelMethodDefinition
autoload_content = resources.map do |resource|
(" " * 6) + "autoload :#{resource.name}, \"#{resource.relative_file_path}\""
end

lines = File.readlines(module_file)
start = lines.index { |line| line.include?("# autogenerated:start") }
finish = lines.index { |line| line.include?("# autogenerated:finish") }

# Remove existing lines
lines.slice!(start + 1..finish - 1)
# Place new lines
lines.insert(start + 1, "#{autoload_content.join("\n")}\n")

File.write(module_file, lines.join)
end
129 changes: 129 additions & 0 deletions generators/heroicon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# frozen_string_literal: true

require_relative "helpers"

OUTPUT_DIR = Pathname.new("lib/protos/icon/heroicon").freeze

RUBOCOPS = %w[
Layout/LineLength
].join(", ")

TEMPLATE = ERB.new <<~ERB
# frozen_string_literal: true
# This file was generated by the `generators/heroicon.rb` generator.
# rubocop:disable #{RUBOCOPS}
module Protos
module Icon
module Heroicon
class <%= icon_class_name %> < HeroiconComponent
def solid
<%= solid_icon %>
end
def outline
<%= outline_icon %>
end
end
end
end
end
# rubocop:enable #{RUBOCOPS}
ERB

require "debug"

class ResourcePath
REGEXP = %r{heroicons/24/(?<variant>solid|outline)/(?<name>.+)\.svg}

attr_reader :variant, :name

def initialize(path)
@path = path
@variant, @name = path.to_s.match(REGEXP).captures
end

def icon_class_name
@name.split("-").map(&:capitalize).join
end

def solid?
@variant == "solid"
end

def outline?
@variant == "outline"
end

def filename
@path.basename.to_s.split(".").first.tr("-", "_")
end

def read
File.read(@path)
end
end

class Resource
attr_reader :name

def initialize(name, paths)
@name = name
@solid_path = paths.find(&:solid?)
@outline_path = paths.find(&:outline?)
end

def file_name
OUTPUT_DIR.join("#{@solid_path.filename}.rb")
end

def relative_file_path
file_name.relative_path_from(Pathname.new("lib")).to_s
end

def solid_icon
build_icon(@solid_path)
end

def outline_icon
build_icon(@outline_path)
end

private

def build_icon(path)
Phlexing::Converter
.convert(path.read)
.sub("svg(", "svg(\n **attrs,")
.split("\n")
.map { |line| (" " * 10) + line }
.join("\n")
end
end

resource_paths = Pathname.glob("assets/heroicons/24/**/*.svg").map do |path|
ResourcePath.new(path)
end

resources = resource_paths
.group_by(&:icon_class_name)
.map do |icon_class_name, paths|
Resource.new(icon_class_name, paths)
end

module_file = OUTPUT_DIR.join("..", "heroicon.rb")
add_autoload_entries(module_file, resources)

resources.with_progress.each do |resource|
File.write(
resource.file_name,
TEMPLATE.result_with_hash(
{
icon_class_name: resource.name,
solid_icon: resource.solid_icon,
outline_icon: resource.outline_icon
}
)
)
end
Loading

0 comments on commit 2921b01

Please sign in to comment.