basecoat 0.1.3 → 1.0.1
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 +4 -4
- data/.idea/codeStyles/codeStyleConfig.xml +5 -0
- data/README.md +1 -0
- data/lib/basecoat/version.rb +1 -1
- data/lib/generators/basecoat/templates/application.html.erb +1 -1
- data/lib/generators/basecoat/templates/devise.html.erb +2 -5
- data/lib/generators/basecoat/templates/layouts/_header.html.erb +2 -5
- data/lib/generators/basecoat/templates/layouts/_theme_toggle.html.erb +4 -0
- data/lib/generators/basecoat/templates/sessions.html.erb +2 -5
- data/lib/generators/basecoat/templates/theme_controller.js +29 -0
- data/lib/tasks/basecoat.rake +110 -40
- data/lib/templates/erb/scaffold/edit.html.erb.tt +1 -3
- data/lib/templates/erb/scaffold/index.html.erb.tt +38 -14
- data/lib/templates/erb/scaffold/new.html.erb.tt +1 -3
- data/lib/templates/erb/scaffold/show.html.erb.tt +34 -17
- metadata +4 -3
- data/lib/generators/basecoat/templates/basecoat-helper.js +0 -38
- data/lib/templates/erb/scaffold/partial.html.erb.tt +0 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 17085310ec6fbb84cd7e779e04cf55362947f1cf440c7d92d5762d2e5759bf6c
|
|
4
|
+
data.tar.gz: 8370e2d4f4237d2f8d59ca917ca21edcacbec77cf45a4ee9acbfdc841a4bdff1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5e8baf2623834233d0dfeb1dc08939ca7ab3f0e0994ff2a0401b7b40f0e05ec948c072d8eb840c1afd20b3b1073b55240106bebf663dadb17e31e98733c56165
|
|
7
|
+
data.tar.gz: bd091f59684a2d9e5370b46e2f7bce65c0cc8e3d658c9153adc2d671ce6380c786577fb46fd1e83711d4b68afd840ae5668b194b37e09b6d9d9487d150033295
|
data/README.md
CHANGED
|
@@ -167,6 +167,7 @@ The authentication views include:
|
|
|
167
167
|
- Tailwind CSS ([installation instructions](https://github.com/rails/tailwindcss-rails))
|
|
168
168
|
- Basecoat CSS
|
|
169
169
|
- Turbo Rails (for scaffold templates)
|
|
170
|
+
- Stimulus (for the theme toggle, can be moved to something else if you desire...)
|
|
170
171
|
|
|
171
172
|
## How It Works
|
|
172
173
|
|
data/lib/basecoat/version.rb
CHANGED
|
@@ -5,17 +5,14 @@
|
|
|
5
5
|
<%= render 'layouts/notice', notice: notice if notice %>
|
|
6
6
|
<div class="grid min-h-svh lg:grid-cols-2">
|
|
7
7
|
<div class="flex flex-col gap-4 p-6 md:p-10">
|
|
8
|
-
<div class="flex justify-between items-center gap-2">
|
|
8
|
+
<div class="flex justify-between items-center gap-2" data-controller="theme">
|
|
9
9
|
<a href="#" class="flex items-center gap-2 font-medium">
|
|
10
10
|
<div class="bg-primary text-primary-foreground flex size-6 items-center justify-center rounded-md">
|
|
11
11
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" class="h-4 w-4"><rect width="256" height="256" fill="none"></rect><line x1="208" y1="128" x2="128" y2="208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line><line x1="192" y1="40" x2="40" y2="192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line></svg>
|
|
12
12
|
</div>
|
|
13
13
|
Basecoat
|
|
14
14
|
</a>
|
|
15
|
-
|
|
16
|
-
<span class="hidden dark:block"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></svg></span>
|
|
17
|
-
<span class="block dark:hidden"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg></span>
|
|
18
|
-
</button>
|
|
15
|
+
<%= render "layouts/theme_toggle" %>
|
|
19
16
|
</div>
|
|
20
17
|
<%= render 'layouts/alert', alert: alert if alert %>
|
|
21
18
|
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
<header class="bg-background sticky inset-x-0 top-0 isolate flex shrink-0 items-center gap-2 border-b z-10 px-4">
|
|
1
|
+
<header class="bg-background sticky inset-x-0 top-0 isolate flex shrink-0 items-center gap-2 border-b z-10 px-4" data-controller="theme">
|
|
2
2
|
<div class="flex h-14 flex-1 items-center gap-2">
|
|
3
3
|
<button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'))" aria-label="Toggle sidebar" data-tooltip="Toggle sidebar" data-side="bottom" data-align="start" class="btn-sm-icon-ghost mr-auto size-7 -ml-1.5">
|
|
4
4
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"></rect><path d="M9 3v18"></path></svg>
|
|
5
5
|
</button>
|
|
6
|
-
|
|
7
|
-
<span class="hidden dark:block"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></svg></span>
|
|
8
|
-
<span class="block dark:hidden"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg></span>
|
|
9
|
-
</button>
|
|
6
|
+
<%= render "layouts/theme_toggle" %>
|
|
10
7
|
<!-- DEVISE_USER_DROPDOWN -->
|
|
11
8
|
</div>
|
|
12
9
|
</header>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<button type="button" aria-label="Toggle dark mode" data-tooltip="Toggle dark mode" data-side="left" data-action="click->theme#toggle" class="btn-icon-outline size-8">
|
|
2
|
+
<span class="hidden dark:block"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></svg></span>
|
|
3
|
+
<span class="block dark:hidden"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg></span>
|
|
4
|
+
</button>
|
|
@@ -5,17 +5,14 @@
|
|
|
5
5
|
<%= render 'layouts/notice', notice: notice if notice %>
|
|
6
6
|
<div class="grid min-h-svh lg:grid-cols-2">
|
|
7
7
|
<div class="flex flex-col gap-4 p-6 md:p-10">
|
|
8
|
-
<div class="flex justify-between items-center gap-2">
|
|
8
|
+
<div class="flex justify-between items-center gap-2" data-controller="theme">
|
|
9
9
|
<a href="#" class="flex items-center gap-2 font-medium">
|
|
10
10
|
<div class="bg-primary text-primary-foreground flex size-6 items-center justify-center rounded-md">
|
|
11
11
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" class="h-4 w-4"><rect width="256" height="256" fill="none"></rect><line x1="208" y1="128" x2="128" y2="208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line><line x1="192" y1="40" x2="40" y2="192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line></svg>
|
|
12
12
|
</div>
|
|
13
13
|
Basecoat
|
|
14
14
|
</a>
|
|
15
|
-
|
|
16
|
-
<span class="hidden dark:block"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></svg></span>
|
|
17
|
-
<span class="block dark:hidden"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg></span>
|
|
18
|
-
</button>
|
|
15
|
+
<%= render "layouts/theme_toggle" %>
|
|
19
16
|
</div>
|
|
20
17
|
<%= render 'layouts/alert', alert: alert if alert %>
|
|
21
18
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
connect() {
|
|
5
|
+
// Apply theme on initial load (runs immediately to prevent flash)
|
|
6
|
+
this.applyStoredTheme()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
toggle() {
|
|
10
|
+
const isDark = !document.documentElement.classList.contains('dark')
|
|
11
|
+
this.apply(isDark)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
apply(dark) {
|
|
15
|
+
document.documentElement.classList.toggle('dark', dark)
|
|
16
|
+
try {
|
|
17
|
+
localStorage.setItem('themeMode', dark ? 'dark' : 'light')
|
|
18
|
+
} catch (_) {}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
applyStoredTheme() {
|
|
22
|
+
try {
|
|
23
|
+
const stored = localStorage.getItem('themeMode')
|
|
24
|
+
if (stored ? stored === 'dark' : matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
25
|
+
document.documentElement.classList.add('dark')
|
|
26
|
+
}
|
|
27
|
+
} catch (_) {}
|
|
28
|
+
}
|
|
29
|
+
}
|
data/lib/tasks/basecoat.rake
CHANGED
|
@@ -3,10 +3,27 @@ require 'fileutils'
|
|
|
3
3
|
namespace :basecoat do
|
|
4
4
|
desc "Install Basecoat application layout and partials"
|
|
5
5
|
task :install do
|
|
6
|
-
# Install basecoat-css (
|
|
6
|
+
# Install basecoat-css (detect package manager)
|
|
7
7
|
puts "\n📦 Installing basecoat-css..."
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
# Detect package manager
|
|
10
|
+
if File.exist?(Rails.root.join("bun.lockb"))
|
|
11
|
+
system("bun add basecoat-css")
|
|
12
|
+
puts " Installed: basecoat-css via bun"
|
|
13
|
+
elsif File.exist?(Rails.root.join("yarn.lock"))
|
|
14
|
+
system("yarn add basecoat-css")
|
|
15
|
+
puts " Installed: basecoat-css via yarn"
|
|
16
|
+
elsif File.exist?(Rails.root.join("package-lock.json"))
|
|
17
|
+
system("npm install basecoat-css")
|
|
18
|
+
puts " Installed: basecoat-css via npm"
|
|
19
|
+
elsif File.exist?(Rails.root.join("pnpm-lock.yaml"))
|
|
20
|
+
system("pnpm add basecoat-css")
|
|
21
|
+
puts " Installed: basecoat-css via pnpm"
|
|
22
|
+
else
|
|
23
|
+
# Fallback: try bun first, then yarn, then npm
|
|
24
|
+
system("bun add basecoat-css") || system("yarn add basecoat-css") || system("npm install basecoat-css")
|
|
25
|
+
puts " Installed: basecoat-css"
|
|
26
|
+
end
|
|
10
27
|
|
|
11
28
|
# If using importmap, also add to importmap.rb for JS
|
|
12
29
|
if File.exist?(Rails.root.join("config/importmap.rb"))
|
|
@@ -41,21 +58,38 @@ namespace :basecoat do
|
|
|
41
58
|
puts " Added: basecoat-css import to app/javascript/application.js"
|
|
42
59
|
end
|
|
43
60
|
|
|
44
|
-
#
|
|
45
|
-
helper_source = File.expand_path("../generators/basecoat/templates/basecoat-helper.js", __dir__)
|
|
46
|
-
helper_destination = Rails.root.join("app/javascript/basecoat-helper.js")
|
|
47
|
-
|
|
48
|
-
FileUtils.cp(helper_source, helper_destination)
|
|
49
|
-
puts " Created: app/javascript/basecoat-helper.js"
|
|
50
|
-
|
|
51
|
-
# Add basecoat-helper import
|
|
61
|
+
# Add basecoat helper JavaScript directly to application.js
|
|
52
62
|
js_content = File.read(js_path)
|
|
53
|
-
unless js_content.include?("basecoat-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
unless js_content.include?("Re-initialize basecoat-css components")
|
|
64
|
+
basecoat_js = <<~JS
|
|
65
|
+
|
|
66
|
+
// Re-initialize basecoat-css components after Turbo navigation
|
|
67
|
+
document.addEventListener('turbo:load', () => {
|
|
68
|
+
document.dispatchEvent(new Event('DOMContentLoaded', { bubbles: true, cancelable: false }))
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// View transitions for turbo frame navigation
|
|
72
|
+
addEventListener("turbo:before-frame-render", (event) => {
|
|
73
|
+
if (document.startViewTransition) {
|
|
74
|
+
const originalRender = event.detail.render
|
|
75
|
+
event.detail.render = async (currentElement, newElement) => {
|
|
76
|
+
const transition = document.startViewTransition(() => originalRender(currentElement, newElement))
|
|
77
|
+
await transition.finished
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
JS
|
|
82
|
+
File.open(js_path, "a") { |f| f.write(basecoat_js) }
|
|
83
|
+
puts " Added: Basecoat helper JavaScript to app/javascript/application.js"
|
|
58
84
|
end
|
|
85
|
+
|
|
86
|
+
# Copy theme_controller.js
|
|
87
|
+
theme_controller_source = File.expand_path("../generators/basecoat/templates/theme_controller.js", __dir__)
|
|
88
|
+
theme_controller_destination = Rails.root.join("app/javascript/controllers/theme_controller.js")
|
|
89
|
+
|
|
90
|
+
FileUtils.mkdir_p(File.dirname(theme_controller_destination))
|
|
91
|
+
FileUtils.cp(theme_controller_source, theme_controller_destination)
|
|
92
|
+
puts " Created: app/javascript/controllers/theme_controller.js"
|
|
59
93
|
end
|
|
60
94
|
|
|
61
95
|
# Add CSS imports and styles
|
|
@@ -71,40 +105,76 @@ namespace :basecoat do
|
|
|
71
105
|
File.write(tailwind_css, updated_content)
|
|
72
106
|
puts " Added: basecoat-css import to app/assets/tailwind/application.css"
|
|
73
107
|
end
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
108
|
+
end
|
|
109
|
+
# Traditional setup with app/assets/stylesheets
|
|
110
|
+
# Check for application.tailwind.css first, then application.css
|
|
111
|
+
css_path = if File.exist?(Rails.root.join("app/assets/stylesheets/application.tailwind.css"))
|
|
112
|
+
Rails.root.join("app/assets/stylesheets/application.tailwind.css")
|
|
113
|
+
else
|
|
114
|
+
Rails.root.join("app/assets/stylesheets/application.css")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
if File.exist?(css_path)
|
|
118
|
+
css_content = File.read(css_path)
|
|
119
|
+
|
|
120
|
+
css_code = <<~CSS
|
|
121
|
+
.field_with_errors {
|
|
122
|
+
label {
|
|
123
|
+
color: var(--color-destructive);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
input {
|
|
127
|
+
border-color: var(--color-destructive);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
dl {
|
|
132
|
+
font-size: var(--text-sm);
|
|
133
|
+
dt {
|
|
134
|
+
font-weight: var(--font-weight-bold);
|
|
135
|
+
margin-top: calc(var(--spacing)*4);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
CSS
|
|
139
|
+
File.open(css_path, "a") { |f| f.write(css_code) }
|
|
140
|
+
puts " Added: basic styles to #{css_path.relative_path_from(Rails.root)}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Extract <head> from existing application.html.erb BEFORE overwriting it
|
|
144
|
+
layout_destination = Rails.root.join("app/views/layouts/application.html.erb")
|
|
145
|
+
partials_source = File.expand_path("../generators/basecoat/templates/layouts", __dir__)
|
|
146
|
+
partials_destination = Rails.root.join("app/views/layouts")
|
|
147
|
+
|
|
148
|
+
FileUtils.mkdir_p(partials_destination)
|
|
149
|
+
|
|
150
|
+
if File.exist?(layout_destination)
|
|
151
|
+
content = File.read(layout_destination)
|
|
152
|
+
# Extract everything between <head> and </head>
|
|
153
|
+
if content =~ /(<head>.*?<\/head>)/m
|
|
154
|
+
head_content = $1
|
|
155
|
+
head_destination = partials_destination.join("_head.html.erb")
|
|
156
|
+
File.write(head_destination, head_content + "\n")
|
|
157
|
+
puts " Created: app/views/layouts/_head.html.erb (extracted from existing application.html.erb)"
|
|
158
|
+
else
|
|
159
|
+
# Fallback: copy the template if no <head> found in existing layout
|
|
160
|
+
FileUtils.cp("#{partials_source}/_head.html.erb", partials_destination.join("_head.html.erb"))
|
|
161
|
+
puts " Created: app/views/layouts/_head.html.erb (from template)"
|
|
91
162
|
end
|
|
163
|
+
else
|
|
164
|
+
# No existing layout, use template
|
|
165
|
+
FileUtils.cp("#{partials_source}/_head.html.erb", partials_destination.join("_head.html.erb"))
|
|
166
|
+
puts " Created: app/views/layouts/_head.html.erb (from template)"
|
|
92
167
|
end
|
|
93
168
|
|
|
94
169
|
# Copy application layout
|
|
95
170
|
layout_source = File.expand_path("../generators/basecoat/templates/application.html.erb", __dir__)
|
|
96
|
-
layout_destination = Rails.root.join("app/views/layouts/application.html.erb")
|
|
97
|
-
|
|
98
|
-
FileUtils.mkdir_p(File.dirname(layout_destination))
|
|
99
171
|
FileUtils.cp(layout_source, layout_destination)
|
|
100
172
|
puts " Created: app/views/layouts/application.html.erb"
|
|
101
173
|
|
|
102
|
-
# Copy layout partials
|
|
103
|
-
partials_source = File.expand_path("../generators/basecoat/templates/layouts", __dir__)
|
|
104
|
-
partials_destination = Rails.root.join("app/views/layouts")
|
|
105
|
-
|
|
174
|
+
# Copy layout partials (except _head.html.erb which we already handled)
|
|
106
175
|
Dir.glob("#{partials_source}/*").each do |file|
|
|
107
176
|
filename = File.basename(file)
|
|
177
|
+
next if filename == "_head.html.erb" # Skip _head.html.erb, we already created it
|
|
108
178
|
FileUtils.cp(file, partials_destination.join(filename))
|
|
109
179
|
puts " Created: app/views/layouts/#{filename}"
|
|
110
180
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<%%= turbo_frame_tag "main_content" do %>
|
|
2
|
-
<%%= render 'layouts/notice', notice: notice if notice %>
|
|
3
|
-
<div class="container mx-auto px-4 py-8">
|
|
2
|
+
<%%= render 'layouts/notice', notice: notice if notice %>
|
|
4
3
|
<div class="max-w-2xl mx-auto">
|
|
5
4
|
<div class="card">
|
|
6
5
|
<header>
|
|
@@ -17,5 +16,4 @@
|
|
|
17
16
|
<%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper(type: :path) %>, class: "btn-outline", data: { turbo_action: "advance" } %>
|
|
18
17
|
</div>
|
|
19
18
|
</div>
|
|
20
|
-
</div>
|
|
21
19
|
<%% end %>
|
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
<%%= turbo_frame_tag "main_content" do %>
|
|
2
|
-
<%%= render 'layouts/notice', notice: notice if notice %>
|
|
3
|
-
<div class="container mx-auto px-4 py-8">
|
|
2
|
+
<%%= render 'layouts/notice', notice: notice if notice %>
|
|
4
3
|
<div class="flex justify-between items-center mb-8">
|
|
5
4
|
<h1 class="text-3xl"><%= human_name.pluralize %></h1>
|
|
6
5
|
<%%= link_to "New <%= human_name.downcase %>", <%= new_helper(type: :path) %>, class: "btn", data: { turbo_action: "advance" } %>
|
|
7
6
|
</div>
|
|
8
7
|
|
|
9
|
-
<div class="
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
<div class="overflow-x-auto" id="<%= plural_table_name %>">
|
|
9
|
+
<table class="table">
|
|
10
|
+
<thead>
|
|
11
|
+
<tr class="hover:bg-background">
|
|
12
|
+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
|
13
|
+
<th>
|
|
14
|
+
<%= attribute.human_name %>
|
|
15
|
+
</th>
|
|
16
|
+
<% end -%>
|
|
17
|
+
<th class="bg-background sticky right-0">
|
|
18
|
+
Actions
|
|
19
|
+
</th>
|
|
20
|
+
</tr>
|
|
21
|
+
</thead>
|
|
22
|
+
<tbody>
|
|
23
|
+
<%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
|
|
24
|
+
<tr class="hover:bg-background">
|
|
25
|
+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
|
26
|
+
<td>
|
|
27
|
+
<% if attribute.attachment? -%>
|
|
28
|
+
<%%= link_to <%= singular_table_name %>.<%= attribute.column_name %>.filename, <%= singular_table_name %>.<%= attribute.column_name %>, target: :_blank, class: "text-blue-600 hover:text-blue-800 underline" if <%= singular_table_name %>.<%= attribute.column_name %>.attached? %>
|
|
29
|
+
<% elsif attribute.attachments? -%>
|
|
30
|
+
<%% <%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
|
|
31
|
+
<div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %>, target: :_blank, class: "text-blue-600 hover:text-blue-800 underline" %></div>
|
|
32
|
+
<%% end %>
|
|
33
|
+
<% else -%>
|
|
34
|
+
<%%= <%= singular_table_name %>.<%= attribute.column_name %> %>
|
|
35
|
+
<% end -%>
|
|
36
|
+
</td>
|
|
37
|
+
<% end -%>
|
|
38
|
+
<td class="bg-background sticky right-0">
|
|
39
|
+
<%%= link_to "Show", <%= model_resource_name(singular_table_name) %>, class: "btn-outline", data: { turbo_action: "advance" } %>
|
|
40
|
+
</td>
|
|
41
|
+
</tr>
|
|
42
|
+
<%% end %>
|
|
43
|
+
</tbody>
|
|
44
|
+
</table>
|
|
20
45
|
</div>
|
|
21
46
|
|
|
22
47
|
<%% if @<%= plural_table_name %>.empty? %>
|
|
@@ -31,5 +56,4 @@
|
|
|
31
56
|
<%%= link_to "New <%= human_name.downcase %>", <%= new_helper(type: :path) %>, class: "btn", data: { turbo_action: "advance" } %>
|
|
32
57
|
</div>
|
|
33
58
|
<%% end %>
|
|
34
|
-
</div>
|
|
35
59
|
<%% end %>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<%%= turbo_frame_tag "main_content" do %>
|
|
2
|
-
<%%= render 'layouts/notice', notice: notice if notice %>
|
|
3
|
-
<div class="container mx-auto px-4 py-8">
|
|
2
|
+
<%%= render 'layouts/notice', notice: notice if notice %>
|
|
4
3
|
<div class="max-w-2xl mx-auto">
|
|
5
4
|
<div class="card">
|
|
6
5
|
<header>
|
|
@@ -16,5 +15,4 @@
|
|
|
16
15
|
<%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper(type: :path) %>, class: "btn-outline", data: { turbo_action: "advance" } %>
|
|
17
16
|
</div>
|
|
18
17
|
</div>
|
|
19
|
-
</div>
|
|
20
18
|
<%% end %>
|
|
@@ -1,23 +1,40 @@
|
|
|
1
1
|
<%%= turbo_frame_tag "main_content" do %>
|
|
2
2
|
<%%= render 'layouts/notice', notice: notice if notice %>
|
|
3
|
-
<div class="
|
|
4
|
-
<div class="
|
|
5
|
-
<
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
<div class="max-w-2xl mx-auto">
|
|
4
|
+
<div class="card">
|
|
5
|
+
<section>
|
|
6
|
+
<div id="<%%= dom_id @<%= singular_table_name %> %>">
|
|
7
|
+
<dl>
|
|
8
|
+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
|
9
|
+
<dt>
|
|
10
|
+
<%= attribute.human_name %>:
|
|
11
|
+
</dt>
|
|
12
|
+
<dd>
|
|
13
|
+
<% if attribute.attachment? -%>
|
|
14
|
+
<%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %>, target: :_blank if @<%= singular_table_name %>.<%= attribute.column_name %>.attached? %>
|
|
15
|
+
<% elsif attribute.attachments? -%>
|
|
16
|
+
<%% @<%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
|
|
17
|
+
<div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %>, target: :_blank %></div>
|
|
18
|
+
<%% end %>
|
|
19
|
+
<% else -%>
|
|
20
|
+
<%%= @<%= singular_table_name %>.<%= attribute.column_name %> %>
|
|
21
|
+
<% end -%>
|
|
22
|
+
</dd>
|
|
23
|
+
<% end -%>
|
|
24
|
+
</dl>
|
|
25
|
+
</div>
|
|
26
|
+
</section>
|
|
27
|
+
</div>
|
|
10
28
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
</div>
|
|
29
|
+
<div class="flex flex-wrap gap-3 mt-6">
|
|
30
|
+
<%%= link_to "Edit this <%= human_name.downcase %>", <%= edit_helper(type: :path) %>, class: "btn", data: { turbo_action: "advance" } %>
|
|
31
|
+
<%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper(type: :path) %>, class: "btn-outline", data: { turbo_action: "advance" } %>
|
|
32
|
+
<%%= button_to "Delete this <%= human_name.downcase %>",
|
|
33
|
+
<%= model_resource_name(prefix: "@") %>,
|
|
34
|
+
method: :delete,
|
|
35
|
+
class: "btn-destructive",
|
|
36
|
+
data: { turbo_confirm: "Are you sure you want to delete this <%= human_name.downcase %>?", turbo_action: "advance" },
|
|
37
|
+
form_class: "inline-block" %>
|
|
21
38
|
</div>
|
|
22
39
|
</div>
|
|
23
40
|
<%% end %>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: basecoat
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Martijn Lafeber
|
|
@@ -33,6 +33,7 @@ extra_rdoc_files: []
|
|
|
33
33
|
files:
|
|
34
34
|
- ".idea/.gitignore"
|
|
35
35
|
- ".idea/basecoat.iml"
|
|
36
|
+
- ".idea/codeStyles/codeStyleConfig.xml"
|
|
36
37
|
- ".idea/misc.xml"
|
|
37
38
|
- ".idea/modules.xml"
|
|
38
39
|
- ".idea/vcs.xml"
|
|
@@ -43,7 +44,6 @@ files:
|
|
|
43
44
|
- lib/basecoat/railtie.rb
|
|
44
45
|
- lib/basecoat/version.rb
|
|
45
46
|
- lib/generators/basecoat/templates/application.html.erb
|
|
46
|
-
- lib/generators/basecoat/templates/basecoat-helper.js
|
|
47
47
|
- lib/generators/basecoat/templates/devise.html.erb
|
|
48
48
|
- lib/generators/basecoat/templates/devise/confirmations/new.html.erb
|
|
49
49
|
- lib/generators/basecoat/templates/devise/mailer/confirmation_instructions.html.erb
|
|
@@ -65,18 +65,19 @@ files:
|
|
|
65
65
|
- lib/generators/basecoat/templates/layouts/_head.html.erb
|
|
66
66
|
- lib/generators/basecoat/templates/layouts/_header.html.erb
|
|
67
67
|
- lib/generators/basecoat/templates/layouts/_notice.html.erb
|
|
68
|
+
- lib/generators/basecoat/templates/layouts/_theme_toggle.html.erb
|
|
68
69
|
- lib/generators/basecoat/templates/pagy.scss
|
|
69
70
|
- lib/generators/basecoat/templates/passwords/edit.html.erb
|
|
70
71
|
- lib/generators/basecoat/templates/passwords/new.html.erb
|
|
71
72
|
- lib/generators/basecoat/templates/scaffold_hook.rb
|
|
72
73
|
- lib/generators/basecoat/templates/sessions.html.erb
|
|
73
74
|
- lib/generators/basecoat/templates/sessions/new.html.erb
|
|
75
|
+
- lib/generators/basecoat/templates/theme_controller.js
|
|
74
76
|
- lib/tasks/basecoat.rake
|
|
75
77
|
- lib/templates/erb/scaffold/_form.html.erb.tt
|
|
76
78
|
- lib/templates/erb/scaffold/edit.html.erb.tt
|
|
77
79
|
- lib/templates/erb/scaffold/index.html.erb.tt
|
|
78
80
|
- lib/templates/erb/scaffold/new.html.erb.tt
|
|
79
|
-
- lib/templates/erb/scaffold/partial.html.erb.tt
|
|
80
81
|
- lib/templates/erb/scaffold/show.html.erb.tt
|
|
81
82
|
- sig/basecoat.rbs
|
|
82
83
|
homepage: https://github.com/lafeber/basecoat-rb
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// Re-initialize basecoat-css components after Turbo navigation
|
|
2
|
-
document.addEventListener('turbo:load', () => {
|
|
3
|
-
document.dispatchEvent(new Event('DOMContentLoaded', { bubbles: true, cancelable: false }))
|
|
4
|
-
})
|
|
5
|
-
|
|
6
|
-
// View transitions for turbo frame navigation
|
|
7
|
-
addEventListener("turbo:before-frame-render", (event) => {
|
|
8
|
-
if (document.startViewTransition) {
|
|
9
|
-
const originalRender = event.detail.render
|
|
10
|
-
event.detail.render = async (currentElement, newElement) => {
|
|
11
|
-
const transition = document.startViewTransition(() => originalRender(currentElement, newElement))
|
|
12
|
-
await transition.finished
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
// Dark mode toggle
|
|
18
|
-
const apply = dark => {
|
|
19
|
-
document.documentElement.classList.toggle('dark', dark);
|
|
20
|
-
try { localStorage.setItem('themeMode', dark ? 'dark' : 'light'); } catch (_) {}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// Apply theme on initial load (runs immediately to prevent flash)
|
|
24
|
-
try {
|
|
25
|
-
const stored = localStorage.getItem('themeMode');
|
|
26
|
-
if (stored ? stored === 'dark'
|
|
27
|
-
: matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
28
|
-
document.documentElement.classList.add('dark');
|
|
29
|
-
}
|
|
30
|
-
} catch (_) {}
|
|
31
|
-
|
|
32
|
-
// Set up theme toggle event listener
|
|
33
|
-
document.addEventListener('basecoat:theme', (event) => {
|
|
34
|
-
const mode = event.detail?.mode;
|
|
35
|
-
apply(mode === 'dark' ? true
|
|
36
|
-
: mode === 'light' ? false
|
|
37
|
-
: !document.documentElement.classList.contains('dark'));
|
|
38
|
-
})
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<div id="<%%= dom_id <%= singular_table_name %> %>" class="space-y-4">
|
|
2
|
-
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
|
3
|
-
<div class="flex flex-col sm:flex-row sm:items-center py-2">
|
|
4
|
-
<dt class="text-sm font-medium sm:w-1/3 mb-1 sm:mb-0">
|
|
5
|
-
<%= attribute.human_name %>:
|
|
6
|
-
</dt>
|
|
7
|
-
<dd class="text-sm sm:w-2/3">
|
|
8
|
-
<% if attribute.attachment? -%>
|
|
9
|
-
<%%= link_to <%= singular_table_name %>.<%= attribute.column_name %>.filename, <%= singular_table_name %>.<%= attribute.column_name %>, target: :_blank, class: "text-blue-600 hover:text-blue-800 underline" if <%= singular_table_name %>.<%= attribute.column_name %>.attached? %>
|
|
10
|
-
<% elsif attribute.attachments? -%>
|
|
11
|
-
<%% <%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
|
|
12
|
-
<div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %>, target: :_blank, class: "text-blue-600 hover:text-blue-800 underline" %></div>
|
|
13
|
-
<%% end %>
|
|
14
|
-
<% else -%>
|
|
15
|
-
<%%= <%= singular_table_name %>.<%= attribute.column_name %> %>
|
|
16
|
-
<% end -%>
|
|
17
|
-
</dd>
|
|
18
|
-
</div>
|
|
19
|
-
<% end -%>
|
|
20
|
-
</div>
|