rails_site_engine 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +137 -0
- data/Rakefile +6 -0
- data/app/assets/stylesheets/rails_site_engine/application.css +15 -0
- data/app/assets/stylesheets/rails_site_engine/engine.css +2 -0
- data/app/assets/stylesheets/rails_site_engine/engine.tailwind.css +5 -0
- data/app/controllers/rails_site_engine/application_controller.rb +27 -0
- data/app/controllers/rails_site_engine/contacts_controller.rb +35 -0
- data/app/controllers/rails_site_engine/meta_controller.rb +20 -0
- data/app/controllers/rails_site_engine/pages_controller.rb +18 -0
- data/app/helpers/rails_site_engine/application_helper.rb +266 -0
- data/app/javascript/controllers/rails_site_engine/color_mode_controller.js +83 -0
- data/app/javascript/controllers/rails_site_engine/form_submit_controller.js +22 -0
- data/app/javascript/controllers/rails_site_engine/mobile_nav_controller.js +45 -0
- data/app/javascript/rails_site_engine/application.js +8 -0
- data/app/jobs/rails_site_engine/application_job.rb +4 -0
- data/app/mailers/rails_site_engine/application_mailer.rb +6 -0
- data/app/mailers/rails_site_engine/contact_mailer.rb +25 -0
- data/app/models/rails_site_engine/application_record.rb +5 -0
- data/app/models/rails_site_engine/contact_message.rb +16 -0
- data/app/views/layouts/mailer.html.erb +13 -0
- data/app/views/layouts/mailer.text.erb +1 -0
- data/app/views/layouts/rails_site_engine/application.html.erb +54 -0
- data/app/views/rails_site_engine/contact_mailer/notify.text.erb +9 -0
- data/app/views/rails_site_engine/contacts/new.html.erb +1 -0
- data/app/views/rails_site_engine/pages/show.html.erb +15 -0
- data/app/views/rails_site_engine/sections/_contact_form.html.erb +112 -0
- data/app/views/rails_site_engine/sections/_cta_band.html.erb +27 -0
- data/app/views/rails_site_engine/sections/_faq.html.erb +29 -0
- data/app/views/rails_site_engine/sections/_feature_cards.html.erb +30 -0
- data/app/views/rails_site_engine/sections/_hero.html.erb +39 -0
- data/app/views/rails_site_engine/sections/_pricing_cards.html.erb +53 -0
- data/app/views/rails_site_engine/sections/_process_steps.html.erb +35 -0
- data/app/views/rails_site_engine/sections/_project_cards.html.erb +48 -0
- data/app/views/rails_site_engine/sections/_proof_strip.html.erb +16 -0
- data/app/views/rails_site_engine/sections/_rich_text.html.erb +15 -0
- data/app/views/rails_site_engine/sections/_stats.html.erb +34 -0
- data/app/views/rails_site_engine/sections/_testimonials.html.erb +40 -0
- data/app/views/rails_site_engine/sections/_unknown.html.erb +6 -0
- data/app/views/rails_site_engine/shared/_flash.html.erb +18 -0
- data/app/views/rails_site_engine/shared/_footer.html.erb +41 -0
- data/app/views/rails_site_engine/shared/_navbar.html.erb +118 -0
- data/config/importmap.rb +5 -0
- data/config/locales/en.yml +27 -0
- data/config/routes.rb +9 -0
- data/config/site_profiles.yml +23 -0
- data/lib/generators/rails_site_engine/install/install_generator.rb +454 -0
- data/lib/generators/rails_site_engine/install/templates/config/theme.yml +3 -0
- data/lib/generators/rails_site_engine/install/templates/content/pages/about.md +12 -0
- data/lib/generators/rails_site_engine/install/templates/content/pages/contact.md +13 -0
- data/lib/generators/rails_site_engine/install/templates/content/pages/home.md +39 -0
- data/lib/generators/rails_site_engine/install/templates/content/pages/privacy.md +43 -0
- data/lib/generators/rails_site_engine/install/templates/content/pages/services.md +25 -0
- data/lib/generators/rails_site_engine/install/templates/content/site.yml +36 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-carpentry/config/theme.yml +3 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-carpentry/content/pages/about.md +14 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-carpentry/content/pages/contact.md +12 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-carpentry/content/pages/home.md +55 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-carpentry/content/pages/privacy.md +43 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-carpentry/content/pages/services.md +29 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-carpentry/content/site.yml +36 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-electrician/config/theme.yml +3 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-electrician/content/pages/about.md +14 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-electrician/content/pages/contact.md +12 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-electrician/content/pages/home.md +55 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-electrician/content/pages/privacy.md +43 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-electrician/content/pages/services.md +29 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-electrician/content/site.yml +36 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-general/config/theme.yml +3 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-general/content/pages/about.md +14 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-general/content/pages/contact.md +12 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-general/content/pages/home.md +55 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-general/content/pages/privacy.md +43 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-general/content/pages/services.md +29 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-general/content/site.yml +36 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-plumbing/config/theme.yml +3 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-plumbing/content/pages/about.md +14 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-plumbing/content/pages/contact.md +12 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-plumbing/content/pages/home.md +55 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-plumbing/content/pages/privacy.md +43 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-plumbing/content/pages/services.md +29 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/home-services-plumbing/content/site.yml +36 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/portfolio/config/theme.yml +3 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/portfolio/content/pages/about.md +26 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/portfolio/content/pages/contact.md +12 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/portfolio/content/pages/home.md +43 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/portfolio/content/pages/privacy.md +43 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/portfolio/content/pages/work.md +27 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/portfolio/content/site.yml +36 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/software-contracting/config/theme.yml +3 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/software-contracting/content/pages/about.md +14 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/software-contracting/content/pages/contact.md +12 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/software-contracting/content/pages/home.md +48 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/software-contracting/content/pages/pricing.md +57 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/software-contracting/content/pages/privacy.md +43 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/software-contracting/content/pages/projects.md +27 -0
- data/lib/generators/rails_site_engine/install/templates/site_profiles/software-contracting/content/site.yml +38 -0
- data/lib/rails_site_engine/content/store.rb +297 -0
- data/lib/rails_site_engine/engine.rb +15 -0
- data/lib/rails_site_engine/markdown_renderer.rb +37 -0
- data/lib/rails_site_engine/profile_defaults.rb +83 -0
- data/lib/rails_site_engine/site_engine_config.rb +78 -0
- data/lib/rails_site_engine/site_profiles.rb +166 -0
- data/lib/rails_site_engine/sitemap_xml.rb +26 -0
- data/lib/rails_site_engine/theme.rb +54 -0
- data/lib/rails_site_engine/version.rb +3 -0
- data/lib/rails_site_engine.rb +13 -0
- data/lib/tasks/rails_site_engine_tasks.rake +7 -0
- metadata +179 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<%
|
|
2
|
+
@contact_message ||= RailsSiteEngine::ContactMessage.new
|
|
3
|
+
heading = section["heading"].to_s.strip.presence || t("rails_site_engine.contact.form_title")
|
|
4
|
+
intro = section["body"].to_s.strip.presence
|
|
5
|
+
errors = @contact_message.errors
|
|
6
|
+
|
|
7
|
+
name_errors = errors[:name]
|
|
8
|
+
email_errors = errors[:email]
|
|
9
|
+
phone_errors = errors[:phone]
|
|
10
|
+
message_errors = errors[:message]
|
|
11
|
+
%>
|
|
12
|
+
|
|
13
|
+
<section class="mb-14">
|
|
14
|
+
<div class="card border border-base-200 bg-base-100 shadow-sm">
|
|
15
|
+
<div class="card-body">
|
|
16
|
+
<% if heading.present? %>
|
|
17
|
+
<%= tag.public_send(heading_tag, heading, class: "card-title text-2xl") %>
|
|
18
|
+
<% end %>
|
|
19
|
+
|
|
20
|
+
<% if intro.present? %>
|
|
21
|
+
<p class="text-base-content/80"><%= intro %></p>
|
|
22
|
+
<% end %>
|
|
23
|
+
|
|
24
|
+
<%= form_with model: @contact_message,
|
|
25
|
+
scope: :rails_site_engine_contact_message,
|
|
26
|
+
url: contact_page_path,
|
|
27
|
+
method: :post,
|
|
28
|
+
class: "space-y-5",
|
|
29
|
+
data: { controller: "rails-site-engine--form-submit", action: "submit->rails-site-engine--form-submit#submit" } do |f| %>
|
|
30
|
+
<% if errors.any? %>
|
|
31
|
+
<div class="alert alert-error alert-soft" role="alert" aria-live="assertive">
|
|
32
|
+
<div>
|
|
33
|
+
<p class="font-semibold"><%= t("rails_site_engine.contact.errors_title") %></p>
|
|
34
|
+
<ul class="mt-2 list-disc pl-5 text-sm">
|
|
35
|
+
<% errors.full_messages.each do |error_message| %>
|
|
36
|
+
<li><%= error_message %></li>
|
|
37
|
+
<% end %>
|
|
38
|
+
</ul>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<% end %>
|
|
42
|
+
|
|
43
|
+
<div class="grid gap-5 md:grid-cols-2">
|
|
44
|
+
<div class="fieldset">
|
|
45
|
+
<%= f.label :name, t("rails_site_engine.contact.fields.name"), class: "fieldset-legend" %>
|
|
46
|
+
<%= f.text_field :name,
|
|
47
|
+
class: "input input-bordered w-full #{'input-error' if name_errors.any?}",
|
|
48
|
+
autocomplete: "name",
|
|
49
|
+
required: true,
|
|
50
|
+
"aria-invalid": name_errors.any?,
|
|
51
|
+
"aria-describedby": ("contact-name-error" if name_errors.any?) %>
|
|
52
|
+
<% if name_errors.any? %>
|
|
53
|
+
<p id="contact-name-error" class="mt-1 text-sm text-error"><%= name_errors.first %></p>
|
|
54
|
+
<% end %>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class="fieldset">
|
|
58
|
+
<%= f.label :email, t("rails_site_engine.contact.fields.email"), class: "fieldset-legend" %>
|
|
59
|
+
<%= f.email_field :email,
|
|
60
|
+
class: "input input-bordered w-full #{'input-error' if email_errors.any?}",
|
|
61
|
+
autocomplete: "email",
|
|
62
|
+
required: true,
|
|
63
|
+
"aria-invalid": email_errors.any?,
|
|
64
|
+
"aria-describedby": ("contact-email-error" if email_errors.any?) %>
|
|
65
|
+
<% if email_errors.any? %>
|
|
66
|
+
<p id="contact-email-error" class="mt-1 text-sm text-error"><%= email_errors.first %></p>
|
|
67
|
+
<% end %>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div class="fieldset">
|
|
72
|
+
<%= f.label :phone, t("rails_site_engine.contact.fields.phone"), class: "fieldset-legend" %>
|
|
73
|
+
<%= f.telephone_field :phone,
|
|
74
|
+
class: "input input-bordered w-full #{'input-error' if phone_errors.any?}",
|
|
75
|
+
autocomplete: "tel",
|
|
76
|
+
"aria-invalid": phone_errors.any?,
|
|
77
|
+
"aria-describedby": ("contact-phone-error" if phone_errors.any?) %>
|
|
78
|
+
<% if phone_errors.any? %>
|
|
79
|
+
<p id="contact-phone-error" class="mt-1 text-sm text-error"><%= phone_errors.first %></p>
|
|
80
|
+
<% end %>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="fieldset">
|
|
84
|
+
<%= f.label :message, t("rails_site_engine.contact.fields.message"), class: "fieldset-legend" %>
|
|
85
|
+
<%= f.text_area :message,
|
|
86
|
+
class: "textarea textarea-bordered min-h-36 w-full #{'textarea-error' if message_errors.any?}",
|
|
87
|
+
required: true,
|
|
88
|
+
"aria-invalid": message_errors.any?,
|
|
89
|
+
"aria-describedby": ("contact-message-error" if message_errors.any?) %>
|
|
90
|
+
<% if message_errors.any? %>
|
|
91
|
+
<p id="contact-message-error" class="mt-1 text-sm text-error"><%= message_errors.first %></p>
|
|
92
|
+
<% end %>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div class="hidden" aria-hidden="true">
|
|
96
|
+
<%= f.label :website %>
|
|
97
|
+
<%= f.text_field :website, tabindex: "-1", autocomplete: "off" %>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="card-actions justify-end">
|
|
101
|
+
<button type="submit" class="btn btn-primary" data-rails-site-engine--form-submit-target="submitButton">
|
|
102
|
+
<span data-rails-site-engine--form-submit-target="submitText"><%= t("rails_site_engine.contact.submit") %></span>
|
|
103
|
+
<span class="hidden items-center gap-2" data-rails-site-engine--form-submit-target="submittingText">
|
|
104
|
+
<span class="loading loading-spinner loading-xs"></span>
|
|
105
|
+
<%= t("rails_site_engine.contact.submitting") %>
|
|
106
|
+
</span>
|
|
107
|
+
</button>
|
|
108
|
+
</div>
|
|
109
|
+
<% end %>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</section>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence || section["title"].to_s.strip.presence
|
|
3
|
+
body = section["body"].to_s.strip.presence
|
|
4
|
+
cta = section["cta"].is_a?(Hash) ? section["cta"] : {}
|
|
5
|
+
cta_href = resolve_link_href(cta)
|
|
6
|
+
%>
|
|
7
|
+
|
|
8
|
+
<% if heading.present? || body.present? || cta_href.present? %>
|
|
9
|
+
<section class="mb-14">
|
|
10
|
+
<div class="rounded-box border border-primary/20 bg-primary px-6 py-8 text-primary-content sm:px-8 sm:py-10">
|
|
11
|
+
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
12
|
+
<div>
|
|
13
|
+
<% if heading.present? %>
|
|
14
|
+
<h2 class="text-2xl font-bold tracking-tight"><%= heading %></h2>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% if body.present? %>
|
|
17
|
+
<p class="mt-2 max-w-2xl text-primary-content/90"><%= body %></p>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<% if cta["label"].to_s.strip.present? && cta_href.present? %>
|
|
22
|
+
<%= link_to cta["label"], cta_href, class: "btn btn-neutral" %>
|
|
23
|
+
<% end %>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</section>
|
|
27
|
+
<% end %>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence
|
|
3
|
+
items = section["items"]
|
|
4
|
+
items = items.is_a?(Array) ? items.select { |item| item.is_a?(Hash) } : []
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<% if items.any? %>
|
|
8
|
+
<section class="mb-14">
|
|
9
|
+
<% if heading.present? %>
|
|
10
|
+
<%= tag.public_send(heading_tag, heading, class: "mb-6 text-3xl font-bold tracking-tight") %>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<div class="space-y-3">
|
|
14
|
+
<% items.each_with_index do |item, index| %>
|
|
15
|
+
<% question = item["question"].to_s.strip %>
|
|
16
|
+
<% answer = item["answer"].to_s.strip %>
|
|
17
|
+
<% next if question.blank? && answer.blank? %>
|
|
18
|
+
|
|
19
|
+
<div class="collapse collapse-plus border border-base-200 bg-base-100">
|
|
20
|
+
<input type="checkbox" name="faq-<%= page.id %>-<%= index %>">
|
|
21
|
+
<div class="collapse-title pr-10 text-base font-semibold"><%= question %></div>
|
|
22
|
+
<div class="collapse-content text-sm leading-relaxed text-base-content/80">
|
|
23
|
+
<%= answer %>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<% end %>
|
|
27
|
+
</div>
|
|
28
|
+
</section>
|
|
29
|
+
<% end %>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence || section["title"].to_s.strip.presence
|
|
3
|
+
items = section["items"]
|
|
4
|
+
items = items.is_a?(Array) ? items.select { |item| item.is_a?(Hash) } : []
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<section class="mb-14">
|
|
8
|
+
<% if heading.present? %>
|
|
9
|
+
<%= tag.public_send(heading_tag, heading, class: "mb-6 text-3xl font-bold tracking-tight") %>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<div class="grid gap-5 md:grid-cols-2 xl:grid-cols-3">
|
|
13
|
+
<% items.each do |item| %>
|
|
14
|
+
<% item_title = item["title"].to_s.strip %>
|
|
15
|
+
<% item_description = item["description"].to_s.strip %>
|
|
16
|
+
<% next if item_title.blank? && item_description.blank? %>
|
|
17
|
+
|
|
18
|
+
<article class="card border border-base-200 bg-base-100 shadow-sm">
|
|
19
|
+
<div class="card-body">
|
|
20
|
+
<% if item_title.present? %>
|
|
21
|
+
<h3 class="card-title text-lg"><%= item_title %></h3>
|
|
22
|
+
<% end %>
|
|
23
|
+
<% if item_description.present? %>
|
|
24
|
+
<p class="text-base-content/80"><%= item_description %></p>
|
|
25
|
+
<% end %>
|
|
26
|
+
</div>
|
|
27
|
+
</article>
|
|
28
|
+
<% end %>
|
|
29
|
+
</div>
|
|
30
|
+
</section>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence || section["headline"].to_s.strip.presence || page.title.to_s
|
|
3
|
+
subheading = section["subheading"].to_s.strip.presence || section["subhead"].to_s.strip.presence
|
|
4
|
+
kicker = section["kicker"].to_s.strip.presence
|
|
5
|
+
primary = section["primary_cta"].is_a?(Hash) ? section["primary_cta"] : {}
|
|
6
|
+
secondary = section["secondary_cta"].is_a?(Hash) ? section["secondary_cta"] : {}
|
|
7
|
+
primary_href = resolve_link_href(primary)
|
|
8
|
+
secondary_href = resolve_link_href(secondary)
|
|
9
|
+
%>
|
|
10
|
+
|
|
11
|
+
<section class="mb-14">
|
|
12
|
+
<div class="hero rounded-box border border-base-200 bg-base-200/60">
|
|
13
|
+
<div class="hero-content w-full py-12 sm:py-16">
|
|
14
|
+
<div class="max-w-3xl">
|
|
15
|
+
<% if kicker.present? %>
|
|
16
|
+
<p class="mb-4"><span class="badge badge-primary badge-outline"><%= kicker %></span></p>
|
|
17
|
+
<% end %>
|
|
18
|
+
|
|
19
|
+
<%= tag.public_send(heading_tag, heading, class: "text-4xl font-extrabold tracking-tight sm:text-5xl") if heading.present? %>
|
|
20
|
+
|
|
21
|
+
<% if subheading.present? %>
|
|
22
|
+
<p class="mt-5 max-w-2xl text-lg text-base-content/80"><%= subheading %></p>
|
|
23
|
+
<% end %>
|
|
24
|
+
|
|
25
|
+
<% if primary_href.present? || secondary_href.present? %>
|
|
26
|
+
<div class="mt-8 flex flex-wrap gap-3">
|
|
27
|
+
<% if primary["label"].to_s.strip.present? && primary_href.present? %>
|
|
28
|
+
<%= link_to primary["label"], primary_href, class: "btn btn-primary btn-wide sm:btn-md" %>
|
|
29
|
+
<% end %>
|
|
30
|
+
|
|
31
|
+
<% if secondary["label"].to_s.strip.present? && secondary_href.present? %>
|
|
32
|
+
<%= link_to secondary["label"], secondary_href, class: "btn btn-ghost" %>
|
|
33
|
+
<% end %>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</section>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence
|
|
3
|
+
items = section["items"]
|
|
4
|
+
items = items.is_a?(Array) ? items.select { |item| item.is_a?(Hash) } : []
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<% if items.any? %>
|
|
8
|
+
<section class="mb-14">
|
|
9
|
+
<% if heading.present? %>
|
|
10
|
+
<%= tag.public_send(heading_tag, heading, class: "mb-6 text-3xl font-bold tracking-tight") %>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<div class="grid gap-5 md:grid-cols-2 xl:grid-cols-3">
|
|
14
|
+
<% items.each do |item| %>
|
|
15
|
+
<% name = item["name"].to_s.strip %>
|
|
16
|
+
<% starting_price = item["starting_price"].to_s.strip %>
|
|
17
|
+
<% description = item["description"].to_s.strip %>
|
|
18
|
+
<% includes = item["includes"] %>
|
|
19
|
+
<% includes = includes.is_a?(Array) ? includes.map { |entry| entry.to_s.strip }.reject(&:blank?) : [] %>
|
|
20
|
+
<% cta = item["cta"].is_a?(Hash) ? item["cta"] : {} %>
|
|
21
|
+
<% cta_href = resolve_link_href(cta) %>
|
|
22
|
+
<% next if name.blank? && starting_price.blank? && description.blank? && includes.empty? && cta_href.blank? %>
|
|
23
|
+
|
|
24
|
+
<article class="card border border-base-200 bg-base-100 shadow-sm">
|
|
25
|
+
<div class="card-body">
|
|
26
|
+
<% if name.present? %>
|
|
27
|
+
<h3 class="card-title text-lg"><%= name %></h3>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% if starting_price.present? %>
|
|
30
|
+
<p class="text-2xl font-bold text-primary"><%= starting_price %></p>
|
|
31
|
+
<% end %>
|
|
32
|
+
<% if description.present? %>
|
|
33
|
+
<p class="text-base-content/80"><%= description %></p>
|
|
34
|
+
<% end %>
|
|
35
|
+
<% if includes.any? %>
|
|
36
|
+
<ul class="mt-2 list-disc space-y-1 pl-5 text-sm text-base-content/80">
|
|
37
|
+
<% includes.each do |entry| %>
|
|
38
|
+
<li><%= entry %></li>
|
|
39
|
+
<% end %>
|
|
40
|
+
</ul>
|
|
41
|
+
<% end %>
|
|
42
|
+
|
|
43
|
+
<% if cta["label"].to_s.strip.present? && cta_href.present? %>
|
|
44
|
+
<div class="card-actions mt-4 justify-start">
|
|
45
|
+
<%= link_to cta["label"], cta_href, class: "btn btn-primary btn-sm" %>
|
|
46
|
+
</div>
|
|
47
|
+
<% end %>
|
|
48
|
+
</div>
|
|
49
|
+
</article>
|
|
50
|
+
<% end %>
|
|
51
|
+
</div>
|
|
52
|
+
</section>
|
|
53
|
+
<% end %>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence
|
|
3
|
+
items = section["items"]
|
|
4
|
+
items = items.is_a?(Array) ? items.select { |item| item.is_a?(Hash) } : []
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<% if items.any? %>
|
|
8
|
+
<section class="mb-14">
|
|
9
|
+
<% if heading.present? %>
|
|
10
|
+
<%= tag.public_send(heading_tag, heading, class: "mb-6 text-3xl font-bold tracking-tight") %>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<ol class="grid gap-4 md:grid-cols-3">
|
|
14
|
+
<% items.each_with_index do |item, index| %>
|
|
15
|
+
<% title = item["title"].to_s.strip %>
|
|
16
|
+
<% body = item["description"].to_s.strip %>
|
|
17
|
+
<% next if title.blank? && body.blank? %>
|
|
18
|
+
|
|
19
|
+
<li class="card border border-base-200 bg-base-100 shadow-sm">
|
|
20
|
+
<div class="card-body">
|
|
21
|
+
<div class="mb-2">
|
|
22
|
+
<span class="badge badge-primary badge-outline"><%= format("%02d", index + 1) %></span>
|
|
23
|
+
</div>
|
|
24
|
+
<% if title.present? %>
|
|
25
|
+
<h3 class="text-lg font-semibold"><%= title %></h3>
|
|
26
|
+
<% end %>
|
|
27
|
+
<% if body.present? %>
|
|
28
|
+
<p class="text-base-content/80"><%= body %></p>
|
|
29
|
+
<% end %>
|
|
30
|
+
</div>
|
|
31
|
+
</li>
|
|
32
|
+
<% end %>
|
|
33
|
+
</ol>
|
|
34
|
+
</section>
|
|
35
|
+
<% end %>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence
|
|
3
|
+
items = section["items"]
|
|
4
|
+
items = items.is_a?(Array) ? items.select { |item| item.is_a?(Hash) } : []
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<% if items.any? %>
|
|
8
|
+
<section class="mb-14">
|
|
9
|
+
<% if heading.present? %>
|
|
10
|
+
<%= tag.public_send(heading_tag, heading, class: "mb-6 text-3xl font-bold tracking-tight") %>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<div class="grid gap-5 md:grid-cols-2 xl:grid-cols-3">
|
|
14
|
+
<% items.each do |item| %>
|
|
15
|
+
<% title = item["title"].to_s.strip %>
|
|
16
|
+
<% summary = item["summary"].to_s.strip %>
|
|
17
|
+
<% stack = item["stack"].to_s.strip %>
|
|
18
|
+
<% outcome = item["outcome"].to_s.strip %>
|
|
19
|
+
<% url = item["url"].to_s.strip %>
|
|
20
|
+
<% next if title.blank? && summary.blank? && stack.blank? && outcome.blank? && url.blank? %>
|
|
21
|
+
|
|
22
|
+
<article class="card border border-base-200 bg-base-100 shadow-sm">
|
|
23
|
+
<div class="card-body">
|
|
24
|
+
<% if title.present? %>
|
|
25
|
+
<h3 class="card-title text-lg"><%= title %></h3>
|
|
26
|
+
<% end %>
|
|
27
|
+
<% if summary.present? %>
|
|
28
|
+
<p class="text-base-content/80"><%= summary %></p>
|
|
29
|
+
<% end %>
|
|
30
|
+
<% if stack.present? %>
|
|
31
|
+
<p class="mt-2 text-sm"><span class="font-semibold">Stack:</span> <%= stack %></p>
|
|
32
|
+
<% end %>
|
|
33
|
+
<% if outcome.present? %>
|
|
34
|
+
<p class="mt-1 text-sm"><span class="font-semibold">Outcome:</span> <%= outcome %></p>
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<% if url.present? %>
|
|
38
|
+
<% external = url.start_with?("http://", "https://") %>
|
|
39
|
+
<div class="card-actions mt-4 justify-start">
|
|
40
|
+
<%= link_to "View project", url, class: "btn btn-sm btn-outline", target: (external ? "_blank" : nil), rel: (external ? "noopener noreferrer" : nil) %>
|
|
41
|
+
</div>
|
|
42
|
+
<% end %>
|
|
43
|
+
</div>
|
|
44
|
+
</article>
|
|
45
|
+
<% end %>
|
|
46
|
+
</div>
|
|
47
|
+
</section>
|
|
48
|
+
<% end %>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<%
|
|
2
|
+
items = section["items"]
|
|
3
|
+
items = items.is_a?(Array) ? items.map { |item| item.to_s.strip }.reject(&:blank?) : []
|
|
4
|
+
%>
|
|
5
|
+
|
|
6
|
+
<% if items.any? %>
|
|
7
|
+
<section class="mb-12">
|
|
8
|
+
<div class="rounded-box border border-base-200 bg-base-100 px-4 py-4 sm:px-6">
|
|
9
|
+
<ul class="flex flex-wrap items-center gap-3 sm:gap-4">
|
|
10
|
+
<% items.each do |item| %>
|
|
11
|
+
<li class="badge badge-lg badge-outline"><%= item %></li>
|
|
12
|
+
<% end %>
|
|
13
|
+
</ul>
|
|
14
|
+
</div>
|
|
15
|
+
</section>
|
|
16
|
+
<% end %>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence
|
|
3
|
+
markdown = section["markdown"].to_s.strip.presence || page.body_markdown.to_s
|
|
4
|
+
html = section["markdown"].to_s.strip.present? ? RailsSiteEngine::MarkdownRenderer.render(markdown) : page.body_html
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<section class="mb-14">
|
|
8
|
+
<% if heading.present? %>
|
|
9
|
+
<%= tag.public_send(heading_tag, heading, class: "mb-6 text-3xl font-bold tracking-tight") %>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<div class="prose max-w-none">
|
|
13
|
+
<%= html %>
|
|
14
|
+
</div>
|
|
15
|
+
</section>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence
|
|
3
|
+
items = section["items"]
|
|
4
|
+
items = items.is_a?(Array) ? items.select { |item| item.is_a?(Hash) } : []
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<% if items.any? %>
|
|
8
|
+
<section class="mb-14">
|
|
9
|
+
<% if heading.present? %>
|
|
10
|
+
<%= tag.public_send(heading_tag, heading, class: "mb-6 text-3xl font-bold tracking-tight") %>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<div class="stats stats-vertical w-full border border-base-200 bg-base-100 shadow-sm lg:stats-horizontal">
|
|
14
|
+
<% items.each do |item| %>
|
|
15
|
+
<% value = item["value"].to_s.strip %>
|
|
16
|
+
<% label = item["label"].to_s.strip %>
|
|
17
|
+
<% detail = item["description"].to_s.strip %>
|
|
18
|
+
<% next if value.blank? && label.blank? && detail.blank? %>
|
|
19
|
+
|
|
20
|
+
<div class="stat">
|
|
21
|
+
<% if label.present? %>
|
|
22
|
+
<div class="stat-title"><%= label %></div>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% if value.present? %>
|
|
25
|
+
<div class="stat-value text-primary"><%= value %></div>
|
|
26
|
+
<% end %>
|
|
27
|
+
<% if detail.present? %>
|
|
28
|
+
<div class="stat-desc"><%= detail %></div>
|
|
29
|
+
<% end %>
|
|
30
|
+
</div>
|
|
31
|
+
<% end %>
|
|
32
|
+
</div>
|
|
33
|
+
</section>
|
|
34
|
+
<% end %>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<%
|
|
2
|
+
heading = section["heading"].to_s.strip.presence || section["title"].to_s.strip.presence
|
|
3
|
+
items = section["items"]
|
|
4
|
+
items = items.is_a?(Array) ? items.select { |item| item.is_a?(Hash) } : []
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
<% if items.any? %>
|
|
8
|
+
<section class="mb-14">
|
|
9
|
+
<% if heading.present? %>
|
|
10
|
+
<%= tag.public_send(heading_tag, heading, class: "mb-6 text-3xl font-bold tracking-tight") %>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<div class="grid gap-5 md:grid-cols-2">
|
|
14
|
+
<% items.each do |item| %>
|
|
15
|
+
<% quote = item["quote"].to_s.strip %>
|
|
16
|
+
<% author = item["author"].to_s.strip %>
|
|
17
|
+
<% role = item["role"].to_s.strip %>
|
|
18
|
+
<% next if quote.blank? && author.blank? && role.blank? %>
|
|
19
|
+
|
|
20
|
+
<figure class="card border border-base-200 bg-base-100 shadow-sm">
|
|
21
|
+
<blockquote class="card-body">
|
|
22
|
+
<% if quote.present? %>
|
|
23
|
+
<p class="text-lg leading-relaxed">“<%= quote %>”</p>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% if author.present? || role.present? %>
|
|
26
|
+
<figcaption class="mt-4 text-sm text-base-content/70">
|
|
27
|
+
<% if author.present? %>
|
|
28
|
+
<span class="font-medium text-base-content"><%= author %></span>
|
|
29
|
+
<% end %>
|
|
30
|
+
<% if role.present? %>
|
|
31
|
+
<span><%= author.present? ? " · #{role}" : role %></span>
|
|
32
|
+
<% end %>
|
|
33
|
+
</figcaption>
|
|
34
|
+
<% end %>
|
|
35
|
+
</blockquote>
|
|
36
|
+
</figure>
|
|
37
|
+
<% end %>
|
|
38
|
+
</div>
|
|
39
|
+
</section>
|
|
40
|
+
<% end %>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<% flash.each do |key, message| %>
|
|
2
|
+
<% next if message.blank? %>
|
|
3
|
+
|
|
4
|
+
<% alert_class, role, live =
|
|
5
|
+
case key.to_s
|
|
6
|
+
when "notice"
|
|
7
|
+
[ "alert-success", "status", "polite" ]
|
|
8
|
+
when "alert"
|
|
9
|
+
[ "alert-error", "alert", "assertive" ]
|
|
10
|
+
else
|
|
11
|
+
[ "alert-info", "status", "polite" ]
|
|
12
|
+
end
|
|
13
|
+
%>
|
|
14
|
+
|
|
15
|
+
<div class="alert sm:alert-horizontal <%= alert_class %> mb-6 shadow-sm" role="<%= role %>" aria-live="<%= live %>">
|
|
16
|
+
<span><%= message %></span>
|
|
17
|
+
</div>
|
|
18
|
+
<% end %>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<footer class="border-t border-base-200 bg-base-200/30">
|
|
2
|
+
<div class="mx-auto w-full max-w-6xl px-4 py-10">
|
|
3
|
+
<div class="grid gap-8 md:grid-cols-[2fr_1fr_1fr]">
|
|
4
|
+
<section>
|
|
5
|
+
<h2 class="text-base font-semibold"><%= site_name %></h2>
|
|
6
|
+
<% if (description = site_config.dig("seo", "default_description").to_s.strip.presence) %>
|
|
7
|
+
<p class="mt-3 max-w-md text-sm text-base-content/80"><%= description %></p>
|
|
8
|
+
<% end %>
|
|
9
|
+
</section>
|
|
10
|
+
|
|
11
|
+
<nav aria-label="<%= t("rails_site_engine.footer.navigation") %>">
|
|
12
|
+
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/70"><%= t("rails_site_engine.footer.quick_links") %></h2>
|
|
13
|
+
<ul class="menu menu-sm mt-2 w-fit gap-1 p-0">
|
|
14
|
+
<% links = footer_nav_items.presence || primary_nav_items %>
|
|
15
|
+
<% links.each do |item| %>
|
|
16
|
+
<li>
|
|
17
|
+
<%= link_to item[:label], item[:href], **nav_link_options(item) %>
|
|
18
|
+
</li>
|
|
19
|
+
<% end %>
|
|
20
|
+
</ul>
|
|
21
|
+
</nav>
|
|
22
|
+
|
|
23
|
+
<section>
|
|
24
|
+
<h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/70"><%= t("rails_site_engine.footer.contact") %></h2>
|
|
25
|
+
<div class="mt-2 space-y-2 text-sm">
|
|
26
|
+
<% if (phone = contact_channels[:phone]).present? %>
|
|
27
|
+
<p><%= link_to phone, "tel:#{phone}", class: "link link-hover" %></p>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% if (email = contact_channels[:email]).present? %>
|
|
30
|
+
<p><%= link_to email, "mailto:#{email}", class: "link link-hover" %></p>
|
|
31
|
+
<% end %>
|
|
32
|
+
</div>
|
|
33
|
+
</section>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="mt-8 flex flex-col gap-2 border-t border-base-300 pt-4 text-sm text-base-content/70 sm:flex-row sm:items-center sm:justify-between">
|
|
37
|
+
<div>© <%= Time.current.year %> <%= site_name %></div>
|
|
38
|
+
<a href="#" class="link link-hover"><%= t("rails_site_engine.footer.back_to_top") %></a>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</footer>
|