diff --git a/examples/api_only_example.cr b/examples/api_only_example.cr new file mode 100644 index 000000000..81b974fcf --- /dev/null +++ b/examples/api_only_example.cr @@ -0,0 +1,41 @@ +# Example: API-only Lucky application +# Compile with: crystal build examples/api_only_example.cr -D lucky_no_html +# +# This demonstrates how to create a Lucky app without HTML functionality +# for pure API applications, resulting in smaller binary size. + +require "../src/lucky" + +class Api::V1::Status < Lucky::Action + get "/api/v1/status" do + json({ + status: "ok", + version: "1.0.0", + timestamp: Time.utc.to_unix + }) + end +end + +class Api::V1::Users::Index < Lucky::Action + get "/api/v1/users" do + json({ + users: [ + {id: 1, name: "Alice"}, + {id: 2, name: "Bob"} + ] + }) + end +end + +# Note: The following would cause compilation errors with -D lucky_no_html: +# +# class HomePage < Lucky::HTMLPage +# def render +# h1 "This won't compile in API-only mode!" +# end +# end + +puts "API-only Lucky app example compiled successfully!" +puts "Available routes:" +puts " GET /api/v1/status" +puts " GET /api/v1/users" \ No newline at end of file diff --git a/examples/lucky_html_example.cr b/examples/lucky_html_example.cr new file mode 100644 index 000000000..6f80eb2c0 --- /dev/null +++ b/examples/lucky_html_example.cr @@ -0,0 +1,63 @@ +# Example: Using LuckyHtml module independently +# This demonstrates how LuckyHtml can be used as a standalone module + +require "../src/lucky_html" + +# Create a page using LuckyHtml modules +class WelcomePage + include LuckyHtml::HTMLPage + + def render + html do + head do + title "LuckyHtml Example" + css_link "/assets/app.css" + end + + body do + h1 "Welcome to LuckyHtml!" + + div class: "content" do + para "LuckyHtml provides type-safe HTML generation for Crystal applications." + + ul do + li "Type-safe HTML DSL" + li "Component-based architecture" + li "Built-in form helpers" + li "CSRF protection" + end + end + + mount ExampleComponent, message: "Hello from a component!" + end + end + end +end + +# Create a reusable component +class ExampleComponent < LuckyHtml::BaseComponent + needs message : String + + def render + div class: "component" do + h2 "Component Example" + para message + + button "Click me", data_action: "click->example#handleClick" + end + end +end + +# Usage example +require "http/server" + +context = HTTP::Server::Context.new( + HTTP::Request.new("GET", "/"), + HTTP::Server::Response.new(IO::Memory.new) +) + +page = WelcomePage.new(context: context) +html_output = page.perform_render + +puts "Generated HTML:" +puts html_output \ No newline at end of file diff --git a/spec/api_only_test.cr b/spec/api_only_test.cr new file mode 100644 index 000000000..ac77dc189 --- /dev/null +++ b/spec/api_only_test.cr @@ -0,0 +1,19 @@ +# This file tests that Lucky can be compiled without HTML functionality +# Run with: crystal build spec/api_only_test.cr -D lucky_no_html + +require "../src/lucky" + +# Test API action without HTML +class Api::Users::Index < Lucky::Action + get "/api/users" do + json({users: ["alice", "bob"]}) + end +end + +# This should work in API-only mode +puts "API-only compilation successful!" + +# The following would fail with lucky_no_html flag: +# class TestPage +# include Lucky::HTMLPage +# end \ No newline at end of file diff --git a/spec/lucky/conditional_html_spec.cr b/spec/lucky/conditional_html_spec.cr new file mode 100644 index 000000000..1dedc5a2f --- /dev/null +++ b/spec/lucky/conditional_html_spec.cr @@ -0,0 +1,43 @@ +require "../spec_helper" + +include ContextHelper + +# Test that HTML functionality can be conditionally excluded +describe "Conditional HTML loading" do + it "Lucky HTML modules are available by default" do + # This test verifies that HTML modules exist + Lucky::HTMLPage.should_not be_nil + Lucky::HTMLBuilder.should_not be_nil + Lucky::BaseComponent.should_not be_nil + end + + it "allows creating pages with Lucky HTML modules" do + page = TestPage.new(context: build_context) + page.perform_render.to_s.should contain("Test Page") + end + + it "allows rendering components" do + component = TestComponent.new + component.render_to_string.should contain("Test Component") + end + + pending "API-only apps can exclude HTML with lucky_no_html flag" do + # This test would verify that HTML is excluded when compiled with -D lucky_no_html + # but we can't test compile-time flags at runtime + # This is documented for manual testing + end +end + +class TestPage + include Lucky::HTMLPage + + def render + h1 "Test Page" + end +end + +class TestComponent < Lucky::BaseComponent + def render + div "Test Component" + end +end \ No newline at end of file diff --git a/spec/lucky_html/delegator_spec.cr b/spec/lucky_html/delegator_spec.cr new file mode 100644 index 000000000..bf6c9f666 --- /dev/null +++ b/spec/lucky_html/delegator_spec.cr @@ -0,0 +1,36 @@ +require "../spec_helper" +require "../../src/lucky_html" + +include ContextHelper + +# Test that LuckyHtml modules work as expected +describe "LuckyHtml delegator" do + it "allows using LuckyHtml modules" do + # Create a test page using LuckyHtml modules + test_page = TestLuckyHtmlPage.new(context: build_context) + + # Test should compile and run + test_page.perform_render.to_s.should contain("Hello from LuckyHtml") + end + + it "allows using LuckyHtml components" do + component = TestLuckyHtmlComponent.new + component.render_to_string.should contain("LuckyHtml Component") + end +end + +# Test page using LuckyHtml modules +class TestLuckyHtmlPage + include LuckyHtml::HTMLPage + + def render + h1 "Hello from LuckyHtml" + end +end + +# Test component using LuckyHtml +class TestLuckyHtmlComponent < LuckyHtml::BaseComponent + def render + div "LuckyHtml Component" + end +end \ No newline at end of file diff --git a/src/lucky_html.cr b/src/lucky_html.cr new file mode 100644 index 000000000..7a81859b4 --- /dev/null +++ b/src/lucky_html.cr @@ -0,0 +1,7 @@ +# LuckyHtml - HTML rendering module for Lucky framework +# This module can be used independently or as part of Lucky +require "./lucky_html/**" + +module LuckyHtml + VERSION = "0.1.0" +end \ No newline at end of file diff --git a/src/lucky_html/delegator.cr b/src/lucky_html/delegator.cr new file mode 100644 index 000000000..23dc6ae06 --- /dev/null +++ b/src/lucky_html/delegator.cr @@ -0,0 +1,87 @@ +# This file creates delegating modules for LuckyHtml that wrap the existing Lucky HTML functionality +# This allows LuckyHtml to be used as a standalone module while maintaining compatibility + +require "../lucky" + +# Delegate modules +module LuckyHtml::HTMLBuilder + include Lucky::HTMLBuilder +end + +module LuckyHtml::HTMLPage + include Lucky::HTMLPage +end + +abstract class LuckyHtml::BaseComponent < Lucky::BaseComponent +end + +# Tag modules delegation +module LuckyHtml::BaseTags + include Lucky::BaseTags +end + +module LuckyHtml::CustomTags + include Lucky::CustomTags +end + +module LuckyHtml::SpecialtyTags + include Lucky::SpecialtyTags +end + +module LuckyHtml::TagDefaults + include Lucky::TagDefaults +end + +module LuckyHtml::LinkHelpers + include Lucky::LinkHelpers +end + +module LuckyHtml::FormHelpers + include Lucky::FormHelpers +end + +module LuckyHtml::ForgeryProtectionHelpers + include Lucky::ForgeryProtectionHelpers +end + +module LuckyHtml::LiveReloadTag + include Lucky::LiveReloadTag +end + +module LuckyHtml::CheckTagContent + include Lucky::CheckTagContent +end + +# Page helpers delegation +module LuckyHtml::HTMLTextHelpers + include Lucky::HTMLTextHelpers +end + +module LuckyHtml::TextHelpers + include Lucky::TextHelpers +end + +module LuckyHtml::NumberToCurrency + include Lucky::NumberToCurrency +end + +module LuckyHtml::TimeHelpers + include Lucky::TimeHelpers +end + +module LuckyHtml::RenderIfDefined + include Lucky::RenderIfDefined +end + +module LuckyHtml::SvgInliner + include Lucky::SvgInliner +end + +module LuckyHtml::HelpfulParagraphError + include Lucky::HelpfulParagraphError +end + +# Component helpers delegation +module LuckyHtml::MountComponent + include Lucky::MountComponent +end \ No newline at end of file