diff --git a/.gitignore b/.gitignore index 9daa824..7948b66 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store node_modules +/app/assets/builds/* diff --git a/LICENSE.txt b/LICENSE.txt index e860eef..89c27dd 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2024 PhlexUI +Copyright (c) 2024 RBUI Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lib/generators/rbui/base_generator.rb b/lib/generators/rbui/base_generator.rb new file mode 100644 index 0000000..1d2a63b --- /dev/null +++ b/lib/generators/rbui/base_generator.rb @@ -0,0 +1,15 @@ +require "rails/generators" + +module RBUI + module Generators + class BaseGenerator < defined?(Rails::Generators::Base) ? Rails::Generators::Base : Object + namespace "rbui:base" + + source_root File.join(__dir__, "templates") + + def copy_templates + template "base_store_initializer.rb", "config/initializers/rbui.rb" + end + end + end +end diff --git a/lib/generators/rbui/install/install_generator.rb b/lib/generators/rbui/install/install_generator.rb new file mode 100644 index 0000000..945f8d8 --- /dev/null +++ b/lib/generators/rbui/install/install_generator.rb @@ -0,0 +1,128 @@ +module RBUI + module Generators + class InstallGenerator < defined?(Rails::Generators::Base) ? Rails::Generators::Base : Object + namespace "rbui:install" + + if defined?(Rails::Generators::Base) + source_root File.expand_path("templates", __dir__) + + def add_phlex_rails + say "Checking for Phlex Rails" + if gem_installed?("phlex-rails") + say "Phlex Rails is already installed", :green + else + say "Adding Phlex Rails" + run "bundle add phlex-rails" + end + + if yes?("Do you want to run the Phlex installer? (y/n)") + say "Run Phlex install" + run "bin/rails generate phlex:install" + end + end + + def install_stuff + if yes?("Do you want to set up the dev test data? (y/n)") + say "Add index controller" + run "bin/rails generate controller static index --no-helper --no-assets --no-test-framework --no-jbuilder" + + say "Add index view" + run "bin/rails g phlex:view Static::Index" + + append_to_file "app/controllers/static_controller.rb", after: " def index" do + "\n render Static::IndexView" + end + + template "index_view.rb", "app/views/static/index_view.rb", force: true + + say "Add index route" + append_to_file "config/routes.rb", after: "Rails.application.routes.draw do" do + "\n root to: \"static#index\"\n" + end + end + + say "Checking for Tailwind CSS" + if gem_installed?("tailwindcss-rails") + say "Tailwind CSS is already installed", :green + + if yes?("Do you want to run the Tailwind installer? (y/n)") + say "Run Tailwind install" + run "./bin/rails tailwindcss:install" + end + elsif yes?("Do you want us to install Tailwind CSS? (y/n)") + say "Adding Tailwind CSS" + run "./bin/bundle add tailwindcss-rails" + + say "Run Tailwind install" + run "./bin/rails tailwindcss:install" + end + + say "Add tailwind animate" + run "yarn add tailwindcss-animate" + + say "update tailwind.config.js" + template "tailwind.config.js", "config/tailwind.config.js", force: true + + say "Add CSS variables" + template "application.tailwind.css", "app/assets/stylesheets/application.tailwind.css", force: true + end + + def pin_rbui_js + importmap_binstub = Rails.root.join("bin/importmap") + importmap_config_path = Rails.root.join("config/importmap.rb") + stimulus_path = Rails.root.join("app/javascript/application.js") + package_name = "rbui-js" + + if importmap_binstub.exist? + say "Pin #{package_name}" + append_to_file importmap_config_path do + # %(pin "rbui-js", to: "rbui-js.js"\n) + %(pin #{package_name}, to: "rbui-js.js"\n) + end + else + say "Add rbui-js package" + run "yarn add #{package_name}" + end + + if stimulus_path.exist? + say "Add RBUI Stimulus controllers" + append_to_file stimulus_path do + "\nimport \"#{package_name}\";\n" + end + run "yarn build" + else + say "Default Stimulus location is missing: app/javascript/controllers/index.js", :red + say " Add to your Stimulus index.js:" + say " import \"#{package_name}\"" + end + end + + def include_rbui + say "Add RBUI to your global component layout" + insert_into_file "app/views/application_view.rb", after: "class ApplicationView < ApplicationComponent\n" do + " include RBUI\n" + end + end + + else + def self.source_root + File.expand_path("templates", __dir__) + end + + def add_stylesheet_link + puts "This generator can only be run in a Rails environment." + end + + def revoke + puts "This generator can only be run in a Rails environment." + end + end + + private + + def gem_installed?(name) + Gem::Specification.find_all_by_name(name).any? + end + end + end +end diff --git a/lib/generators/rbui/install/templates/.keep b/lib/generators/rbui/install/templates/.keep new file mode 100644 index 0000000..e69de29 diff --git a/lib/generators/rbui/install/templates/application.tailwind.css.tt b/lib/generators/rbui/install/templates/application.tailwind.css.tt new file mode 100644 index 0000000..26fa13a --- /dev/null +++ b/lib/generators/rbui/install/templates/application.tailwind.css.tt @@ -0,0 +1,76 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 5.9% 10%; + --radius: 0.5rem; + + /* rbui especific */ + --warning: 38 92% 50%; + --warning-foreground: 0 0% 100%; + --success: 87 100% 37%; + --success-foreground: 0 0% 100%; + } + + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + + /* rbui especific */ + --warning: 38 92% 50%; + --warning-foreground: 0 0% 100%; + --success: 84 81% 44%; + --success-foreground: 0 0% 100%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + font-feature-settings: "rlig" 1, "calt" 1; + + /* docs specific */ + /* https://css-tricks.com/snippets/css/system-font-stack/ */ + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + } +} diff --git a/lib/generators/rbui/install/templates/index_view.rb.tt b/lib/generators/rbui/install/templates/index_view.rb.tt new file mode 100644 index 0000000..963dc8d --- /dev/null +++ b/lib/generators/rbui/install/templates/index_view.rb.tt @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class Static::IndexView < ApplicationView + def template + render RBUI::Button.new { "click me" } + br {} + + # UI.Button { "click me" } + + AlertDialog do + AlertDialogTrigger do + Button { "Show dialog" } + end + AlertDialogContent do + AlertDialogHeader do + AlertDialogTitle { "Are you absolutely sure?" } + AlertDialogDescription { "This action cannot be undone. This will permanently delete your account and remove your data from our servers." } + end + AlertDialogFooter do + AlertDialogCancel { "Cancel" } + AlertDialogAction { "Continue" } # Will probably be a link to a controller action (e.g. delete account) + end + end + end + h1 { "Static::Index" } + p { "Find me in app/views/static/index_view.rb" } + end +end + diff --git a/lib/generators/rbui/install/templates/tailwind.config.js.tt b/lib/generators/rbui/install/templates/tailwind.config.js.tt new file mode 100644 index 0000000..58ad8ce --- /dev/null +++ b/lib/generators/rbui/install/templates/tailwind.config.js.tt @@ -0,0 +1,85 @@ +// For importing tailwind styles from rbui gem +const execSync = require('child_process').execSync; + +// Import rbui gem path +const outputRBUI = execSync('bundle show rbui', { encoding: 'utf-8' }); +const rbui_path = outputRBUI.trim() + '/**/*.rb'; + +const defaultTheme = require('tailwindcss/defaultTheme') + +module.exports = { + darkMode: ["class"], + content: [ + './app/views/**/*.{erb,haml,html,slim,rb}', + './app/helpers/**/*.rb', + './app/assets/stylesheets/**/*.css', + './app/javascript/**/*.js', + rbui_path + ], + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + /* rbui especific */ + warning: { + DEFAULT: "hsl(var(--warning))", + foreground: "hsl(var(--warning-foreground))", + }, + success: { + DEFAULT: "hsl(var(--success))", + foreground: "hsl(var(--success-foreground))", + }, + }, + borderRadius: { + lg: `var(--radius)`, + md: `calc(var(--radius) - 2px)`, + sm: "calc(var(--radius) - 4px)", + }, + fontFamily: { + sans: ["var(--font-sans)", ...defaultTheme.fontFamily.sans], + }, + }, + }, + plugins: [ + require("tailwindcss-animate"), + ], +} diff --git a/lib/generators/rbui/templates/base_store_initializer.rb.tt b/lib/generators/rbui/templates/base_store_initializer.rb.tt new file mode 100644 index 0000000..c07b3f6 --- /dev/null +++ b/lib/generators/rbui/templates/base_store_initializer.rb.tt @@ -0,0 +1,9 @@ +RBUI.setup do |config| + # Setting a namespace allows you to access RBUI components through this namespace. + # For example, with namespace set to "UI", you can use: + # UI::Button.new instead of RBUI::Button.new + # UI::Card.new instead of RBUI::Card.new + # This can help avoid naming conflicts and allows for cleaner, more concise code. + # If you prefer to use RBUI components directly, you can leave this unset. + config.namespace = "UI" +end diff --git a/lib/rbui.rb b/lib/rbui.rb index 7d96425..d1f6f2c 100644 --- a/lib/rbui.rb +++ b/lib/rbui.rb @@ -42,3 +42,8 @@ def self.create_namespace_module # Manually require all the files Dir.glob(File.join(__dir__, "rbui", "**", "*.rb")).sort.each { |file| require file } + +# If you need to require generators (assuming they're needed) +if defined?(Rails::Generators) + require_relative "generators/rbui/install/install_generator" +end diff --git a/lib/rbui/railtie.rb b/lib/rbui/railtie.rb new file mode 100644 index 0000000..39288f7 --- /dev/null +++ b/lib/rbui/railtie.rb @@ -0,0 +1,17 @@ +module RBUI + if defined?(Rails) + class Railtie < ::Rails::Railtie + generators do + require_relative "../generators/rbui/install/install_generator" + + config.app_generators do |g| + g.templates.unshift File.expand_path("../templates", __FILE__) + end + + initializer "rbui.set_generator_namespace" do + Rails::Generators.namespace(RBUI::Generators, as: "rbui") + end + end + end + end +end diff --git a/rbui.gemspec b/rbui.gemspec index 3e437c5..8ad9766 100644 --- a/rbui.gemspec +++ b/rbui.gemspec @@ -8,6 +8,7 @@ Gem::Specification.new do |s| s.authors = ["George Kettle"] s.email = "george.kettle@icloud.com" s.files = Dir["lib/**/*.rb", "tasks/**/*.rake"] + s.require_path = "lib" s.homepage = "https://rubygems.org/gems/rbui" s.license = "MIT" diff --git a/test/test_helper.rb b/test/test_helper.rb index c4e7c96..d516fc7 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -17,3 +17,9 @@ def view_template(&) def phlex_context(&) render TestContext.new, & end + +# this is a tracepoint that will output the path of all files loaded that contain the string "phlex" +# trace = TracePoint.new(:class) do |tp| +# puts "Loaded: #{tp.path}" if tp.path.include?("phlex") +# end +# trace.enable