shadcn-ui 0.0.1 → 0.0.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 +4 -4
- data/.prettierrc.json +6 -0
- data/README.md +260 -0
- data/app/assets/stylesheets/application.tailwind.css +101 -0
- data/app/controllers/components_controller.rb +1 -1
- data/app/controllers/documentation_controller.rb +9 -0
- data/app/helpers/application_helper.rb +19 -0
- data/app/helpers/components/card_helper.rb +1 -1
- data/app/helpers/components/filter_helper.rb +12 -0
- data/app/helpers/components/input_helper.rb +21 -0
- data/app/helpers/components/label_helper.rb +5 -0
- data/app/helpers/components/list_helper.rb +15 -0
- data/app/helpers/components/progress_helper.rb +5 -0
- data/app/helpers/components/sheet_helper.rb +20 -0
- data/app/helpers/components/skeleton_helper.rb +5 -0
- data/app/helpers/components/slider_helper.rb +5 -0
- data/app/helpers/documentation_helper.rb +2 -0
- data/app/javascript/controllers/theme_controller.js +25 -0
- data/app/javascript/controllers/ui/dialog_controller.js +3 -1
- data/app/javascript/controllers/ui/dropdown_controller.js +2 -22
- data/app/javascript/controllers/ui/filter_controller.js +20 -0
- data/app/javascript/controllers/ui/popover_controller.js +29 -1
- data/app/javascript/controllers/ui/sheet_controller.js +33 -0
- data/app/javascript/controllers/ui/slider_controller.js +14 -0
- data/app/javascript/controllers/ui/tooltip_controller.js +1 -1
- data/app/views/application/index.html.erb +122 -0
- data/app/views/components/ui/_alert_dialog.html.erb +1 -1
- data/app/views/components/ui/_card.html.erb +2 -2
- data/app/views/components/ui/_checkbox.html.erb +1 -6
- data/app/views/components/ui/_command.html.erb +0 -0
- data/app/views/components/ui/_dialog.html.erb +1 -1
- data/app/views/components/ui/_filter.html.erb +14 -0
- data/app/views/components/ui/_input.html.erb +8 -0
- data/app/views/components/ui/_label.html.erb +3 -0
- data/app/views/components/ui/_list.html.erb +5 -0
- data/app/views/components/ui/_progress.html.erb +15 -0
- data/app/views/components/ui/_sheet.html.erb +44 -0
- data/app/views/components/ui/_skeleton.html.erb +1 -0
- data/app/views/components/ui/_slider.html.erb +2 -0
- data/app/views/components/ui/_textarea.html.erb +1 -1
- data/app/views/components/ui/shared/{_dialog_background.html.erb → _backdrop.html.erb} +1 -0
- data/app/views/components/ui/svg/_check.html.erb +11 -0
- data/app/views/documentation/about.html.md +20 -0
- data/app/views/documentation/index.html.erb.bak +70 -0
- data/app/views/documentation/index.html.md +15 -0
- data/app/views/documentation/installation.html.md +249 -0
- data/app/views/examples/components/filter.html.erb +25 -0
- data/app/views/examples/components/input.html.erb +18 -0
- data/app/views/examples/components/label.html.erb +13 -0
- data/app/views/examples/components/progress.html.erb +12 -0
- data/app/views/examples/components/sheet.html.erb +19 -0
- data/app/views/examples/components/skeleton.html.erb +12 -0
- data/app/views/examples/components/slider.html.erb +12 -0
- data/app/views/layouts/application.html.erb +2 -3
- data/app/views/layouts/component.html.erb +2 -2
- data/app/views/layouts/documentation.html.erb +39 -0
- data/app/views/layouts/shared/_components.html.erb +61 -0
- data/app/views/layouts/shared/_header.html.erb +25 -33
- data/app/views/layouts/shared/_sidebar.html.erb +10 -0
- data/config/application.rb +2 -1
- data/config/importmap.rb +6 -6
- data/config/initializers/markdown.rb +24 -0
- data/config/routes.rb +7 -1
- data/lib/components.json +301 -0
- data/lib/generators/shadcn_ui_generator.rb +64 -15
- data/lib/shadcn-ui/version.rb +1 -1
- data/public/accordion.png +0 -0
- metadata +44 -4
- data/app/views/layouts/_sidebar.html.erb +0 -270
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a6f3c1462c5fec38163ab5cbac5af561ca2d05f3944ca41bab01649c14ac6fa
|
4
|
+
data.tar.gz: 5a7fb75ae5e0f7d0db67bf0e55fdc55e65390e5bf535b351f17d69b4b03dd23c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1923bfc2b23ab4fd10aff954938111600c1d4e820c47b87827b67c8529bf1540eb36ae058d8bb0973dce3090802855414e6b200f633d08cfeac75db698e75057
|
7
|
+
data.tar.gz: b16a329953472dee87d8851958f17e2757b1c8709e21c3e5825990486ef80c1ed1b78f459ce23c3d55645786b8173fce76ad6d5b834ecafbadf9940970330410
|
data/.prettierrc.json
CHANGED
data/README.md
CHANGED
@@ -5,8 +5,268 @@
|
|
5
5
|
Accessible and customizable components that you can copy and paste into your apps. Free. Open
|
6
6
|
Source. **Use this to build your own component library**.
|
7
7
|
|
8
|
+
## About
|
9
|
+
|
10
|
+
This is **NOT** a component library. It's a collection of re-usable components that you can copy and
|
11
|
+
paste into your apps.
|
12
|
+
|
13
|
+
**What do you mean by not a component library?**
|
14
|
+
|
15
|
+
I mean you do not install it as a dependency. It is not available or distributed via npm.
|
16
|
+
|
17
|
+
Pick the components you need. Copy and paste the code into your project and customize to your needs.
|
18
|
+
The code is yours.
|
19
|
+
|
20
|
+
Use this as a reference to build your own component libraries.
|
21
|
+
|
8
22
|

|
9
23
|
|
24
|
+
## Alpha Usage/Installation
|
25
|
+
|
26
|
+
Prior to the initial gem release, you can use this as an alpha by cloning this repository and
|
27
|
+
starting up the app as you would a standard rails app.
|
28
|
+
|
29
|
+
```
|
30
|
+
git clone https://github.com/aviflombaum/shadcn-rails.git
|
31
|
+
cd shadcn-rails
|
32
|
+
bundle install
|
33
|
+
./bin/dev
|
34
|
+
```
|
35
|
+
|
36
|
+
There are very few dependencies and no database so it should just boot up. Visit
|
37
|
+
http://localhost:3000 to see the demo app which is also the documentation. You'll be able to browse
|
38
|
+
the components at http://localhost:3000/components.
|
39
|
+
|
40
|
+
If there's a component you want to try in your app, you will be copying the code from this app to
|
41
|
+
yours. There's a few other steps you'll need.
|
42
|
+
|
43
|
+
## Installing a Component
|
44
|
+
|
45
|
+
### Add Tailwind CSS
|
46
|
+
|
47
|
+
Components are styled using Tailwind CSS. You need to install Tailwind CSS in your project.
|
48
|
+
|
49
|
+
[Follow the Tailwind CSS installation instructions to get started.](https://tailwindcss.com/docs/installation)
|
50
|
+
|
51
|
+
### Add dependencies
|
52
|
+
|
53
|
+
If you haven't already, install Tailwind into your rails application by adding `tailwindcss-rails`
|
54
|
+
to your `Gemfile` and install tailwind into your app:
|
55
|
+
|
56
|
+
```sh
|
57
|
+
./bin/bundle add tailwindcss-rails
|
58
|
+
./bin/rails tailwindcss:install
|
59
|
+
```
|
60
|
+
|
61
|
+
Then install ./bin/rails tailwindcss:install
|
62
|
+
|
63
|
+
### Configure tailwind.config.js
|
64
|
+
|
65
|
+
Here's what my `tailwind.config.js` file looks like:
|
66
|
+
|
67
|
+
```js title="tailwind.config.js"
|
68
|
+
const defaultTheme = require("tailwindcss/defaultTheme");
|
69
|
+
|
70
|
+
module.exports = {
|
71
|
+
darkMode: ["class"],
|
72
|
+
content: [
|
73
|
+
"./public/*.html",
|
74
|
+
"./app/helpers/**/*.rb",
|
75
|
+
"./app/javascript/**/*.js",
|
76
|
+
"./app/views/**/*.{erb,haml,html,slim}",
|
77
|
+
],
|
78
|
+
theme: {
|
79
|
+
container: {
|
80
|
+
center: true,
|
81
|
+
padding: "2rem",
|
82
|
+
screens: {
|
83
|
+
"2xl": "1400px",
|
84
|
+
},
|
85
|
+
},
|
86
|
+
extend: {
|
87
|
+
colors: {
|
88
|
+
border: "hsl(var(--border))",
|
89
|
+
input: "hsl(var(--input))",
|
90
|
+
ring: "hsl(var(--ring))",
|
91
|
+
background: "hsl(var(--background))",
|
92
|
+
foreground: "hsl(var(--foreground))",
|
93
|
+
primary: {
|
94
|
+
DEFAULT: "hsl(var(--primary))",
|
95
|
+
foreground: "hsl(var(--primary-foreground))",
|
96
|
+
},
|
97
|
+
secondary: {
|
98
|
+
DEFAULT: "hsl(var(--secondary))",
|
99
|
+
foreground: "hsl(var(--secondary-foreground))",
|
100
|
+
},
|
101
|
+
destructive: {
|
102
|
+
DEFAULT: "hsl(var(--destructive))",
|
103
|
+
foreground: "hsl(var(--destructive-foreground))",
|
104
|
+
},
|
105
|
+
muted: {
|
106
|
+
DEFAULT: "hsl(var(--muted))",
|
107
|
+
foreground: "hsl(var(--muted-foreground))",
|
108
|
+
},
|
109
|
+
accent: {
|
110
|
+
DEFAULT: "hsl(var(--accent))",
|
111
|
+
foreground: "hsl(var(--accent-foreground))",
|
112
|
+
},
|
113
|
+
popover: {
|
114
|
+
DEFAULT: "hsl(var(--popover))",
|
115
|
+
foreground: "hsl(var(--popover-foreground))",
|
116
|
+
},
|
117
|
+
card: {
|
118
|
+
DEFAULT: "hsl(var(--card))",
|
119
|
+
foreground: "hsl(var(--card-foreground))",
|
120
|
+
},
|
121
|
+
},
|
122
|
+
borderRadius: {
|
123
|
+
lg: `var(--radius)`,
|
124
|
+
md: `calc(var(--radius) - 2px)`,
|
125
|
+
sm: "calc(var(--radius) - 4px)",
|
126
|
+
},
|
127
|
+
fontFamily: {
|
128
|
+
sans: ["var(--font-sans)", ...defaultTheme.fontFamily.sans],
|
129
|
+
},
|
130
|
+
keyframes: {
|
131
|
+
"accordion-down": {
|
132
|
+
from: { height: 0 },
|
133
|
+
to: { height: "var(--radix-accordion-content-height)" },
|
134
|
+
},
|
135
|
+
"accordion-up": {
|
136
|
+
from: { height: "var(--radix-accordion-content-height)" },
|
137
|
+
to: { height: 0 },
|
138
|
+
},
|
139
|
+
},
|
140
|
+
animation: {
|
141
|
+
"accordion-down": "accordion-down 0.2s ease-out",
|
142
|
+
"accordion-up": "accordion-up 0.2s ease-out",
|
143
|
+
},
|
144
|
+
},
|
145
|
+
},
|
146
|
+
plugins: [
|
147
|
+
require("@tailwindcss/forms"),
|
148
|
+
require("@tailwindcss/aspect-ratio"),
|
149
|
+
require("@tailwindcss/typography"),
|
150
|
+
require("@tailwindcss/container-queries"),
|
151
|
+
require("tailwindcss-animate"),
|
152
|
+
],
|
153
|
+
};
|
154
|
+
```
|
155
|
+
|
156
|
+
### Configure styles
|
157
|
+
|
158
|
+
Add the following to your app/assets/stylesheets/application.tailwind.css file.
|
159
|
+
|
160
|
+
```css title="application.tailwind.css"
|
161
|
+
@tailwind base;
|
162
|
+
@tailwind components;
|
163
|
+
@tailwind utilities;
|
164
|
+
|
165
|
+
@layer base {
|
166
|
+
:root {
|
167
|
+
--background: 0 0% 100%;
|
168
|
+
--foreground: 222.2 47.4% 11.2%;
|
169
|
+
|
170
|
+
--muted: 210 40% 96.1%;
|
171
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
172
|
+
|
173
|
+
--popover: 0 0% 100%;
|
174
|
+
--popover-foreground: 222.2 47.4% 11.2%;
|
175
|
+
|
176
|
+
--border: 214.3 31.8% 91.4%;
|
177
|
+
--input: 214.3 31.8% 91.4%;
|
178
|
+
|
179
|
+
--card: 0 0% 100%;
|
180
|
+
--card-foreground: 222.2 47.4% 11.2%;
|
181
|
+
|
182
|
+
--primary: 222.2 47.4% 11.2%;
|
183
|
+
--primary-foreground: 210 40% 98%;
|
184
|
+
|
185
|
+
--secondary: 210 40% 96.1%;
|
186
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
187
|
+
|
188
|
+
--accent: 210 40% 96.1%;
|
189
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
190
|
+
|
191
|
+
--destructive: 0 100% 50%;
|
192
|
+
--destructive-foreground: 210 40% 98%;
|
193
|
+
|
194
|
+
--ring: 215 20.2% 65.1%;
|
195
|
+
|
196
|
+
--radius: 0.5rem;
|
197
|
+
}
|
198
|
+
|
199
|
+
.dark {
|
200
|
+
--background: 224 71% 4%;
|
201
|
+
--foreground: 213 31% 91%;
|
202
|
+
|
203
|
+
--muted: 223 47% 11%;
|
204
|
+
--muted-foreground: 215.4 16.3% 56.9%;
|
205
|
+
|
206
|
+
--accent: 216 34% 17%;
|
207
|
+
--accent-foreground: 210 40% 98%;
|
208
|
+
|
209
|
+
--popover: 224 71% 4%;
|
210
|
+
--popover-foreground: 215 20.2% 65.1%;
|
211
|
+
|
212
|
+
--border: 216 34% 17%;
|
213
|
+
--input: 216 34% 17%;
|
214
|
+
|
215
|
+
--card: 224 71% 4%;
|
216
|
+
--card-foreground: 213 31% 91%;
|
217
|
+
|
218
|
+
--primary: 210 40% 98%;
|
219
|
+
--primary-foreground: 222.2 47.4% 1.2%;
|
220
|
+
|
221
|
+
--secondary: 222.2 47.4% 11.2%;
|
222
|
+
--secondary-foreground: 210 40% 98%;
|
223
|
+
|
224
|
+
--destructive: 0 63% 31%;
|
225
|
+
--destructive-foreground: 210 40% 98%;
|
226
|
+
|
227
|
+
--ring: 216 34% 17%;
|
228
|
+
|
229
|
+
--radius: 0.5rem;
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
@layer base {
|
234
|
+
* {
|
235
|
+
@apply border-border;
|
236
|
+
}
|
237
|
+
body {
|
238
|
+
@apply bg-background text-foreground;
|
239
|
+
font-feature-settings:
|
240
|
+
"rlig" 1,
|
241
|
+
"calt" 1;
|
242
|
+
}
|
243
|
+
}
|
244
|
+
```
|
245
|
+
|
246
|
+
### Copy a a component's files to your application
|
247
|
+
|
248
|
+
For example, if you want to use the Accordion component, you would copy the following files to your
|
249
|
+
application:
|
250
|
+
|
251
|
+
- `app/javascript/controllers/components/ui/accordion_controller.js` The Stimulus controller for any
|
252
|
+
component that requires javascript.
|
253
|
+
- `app/helpers/components/accordion_helper.rb` The helper for the component that allows for easy
|
254
|
+
rendering within views.
|
255
|
+
- `app/views/components/ui/_accordion.html.erb` The html for the component.
|
256
|
+
|
257
|
+
Once those are copied in your application you can render an accordion with:
|
258
|
+
|
259
|
+
```erb
|
260
|
+
<%= render_accordion title: "Did you know?", description: "You can wrap shadcn helpers in any
|
261
|
+
component library you want!" %>
|
262
|
+
<%= render_accordion title: "Use the generators.", description: "Add components with #{code("rails g shadcn_ui add accordion")}".html_safe %>
|
263
|
+
```
|
264
|
+
|
265
|
+
See the component's demo page in `app/views/examples/components/accordion.html.erb` for more
|
266
|
+
examples.
|
267
|
+
|
268
|
+
This will be similar for each component.
|
269
|
+
|
10
270
|
## Documentation
|
11
271
|
|
12
272
|
Visit https://avi.nyc/shadcn-on-rails to view the documentation.
|
@@ -90,3 +90,104 @@
|
|
90
90
|
@apply bg-zinc-950;
|
91
91
|
}
|
92
92
|
}
|
93
|
+
input[type="range"] {
|
94
|
+
display: inline-block;
|
95
|
+
vertical-align: middle;
|
96
|
+
font-size: 1em;
|
97
|
+
font-family: Arial, sans-serif;
|
98
|
+
}
|
99
|
+
|
100
|
+
/* input[type="range"]:focus,
|
101
|
+
input[type="number"]:focus {
|
102
|
+
box-shadow: 0 0 3px 1px #4b81dd;
|
103
|
+
outline: none;
|
104
|
+
} */
|
105
|
+
|
106
|
+
input[type="range"] {
|
107
|
+
-webkit-appearance: none;
|
108
|
+
margin-right: 15px;
|
109
|
+
width: 200px;
|
110
|
+
height: 7px;
|
111
|
+
background: #f4f4f5;
|
112
|
+
border-radius: 5px;
|
113
|
+
background-image: linear-gradient(#000, #000);
|
114
|
+
background-repeat: no-repeat;
|
115
|
+
}
|
116
|
+
|
117
|
+
/* Input Thumb */
|
118
|
+
input[type="range"]::-webkit-slider-thumb {
|
119
|
+
-webkit-appearance: none;
|
120
|
+
height: 20px;
|
121
|
+
width: 20px;
|
122
|
+
border-radius: 50%;
|
123
|
+
background: #fff;
|
124
|
+
cursor: ew-resize;
|
125
|
+
box-shadow: 0 0 2px 0 #000;
|
126
|
+
transition: background 0.3s ease-in-out;
|
127
|
+
}
|
128
|
+
|
129
|
+
input[type="range"]::-moz-range-thumb {
|
130
|
+
-webkit-appearance: none;
|
131
|
+
height: 20px;
|
132
|
+
width: 20px;
|
133
|
+
border-radius: 50%;
|
134
|
+
background: #fff;
|
135
|
+
cursor: ew-resize;
|
136
|
+
box-shadow: 0 0 2px 0 #000;
|
137
|
+
transition: background 0.3s ease-in-out;
|
138
|
+
}
|
139
|
+
|
140
|
+
input[type="range"]::-ms-thumb {
|
141
|
+
-webkit-appearance: none;
|
142
|
+
height: 20px;
|
143
|
+
width: 20px;
|
144
|
+
border-radius: 50%;
|
145
|
+
background: #fff;
|
146
|
+
cursor: ew-resize;
|
147
|
+
box-shadow: 0 0 2px 0 #000;
|
148
|
+
transition: background 0.3s ease-in-out;
|
149
|
+
}
|
150
|
+
|
151
|
+
/* input[type="range"]::-webkit-slider-thumb:hover {
|
152
|
+
background: #a1a1aa;
|
153
|
+
}
|
154
|
+
|
155
|
+
input[type="range"]::-moz-range-thumb:hover {
|
156
|
+
background: #a1a1aa;
|
157
|
+
}
|
158
|
+
|
159
|
+
input[type="range"]::-ms-thumb:hover {
|
160
|
+
background: #a1a1aa;
|
161
|
+
} */
|
162
|
+
|
163
|
+
input[type="range"]::-moz-range-track {
|
164
|
+
-webkit-appearance: none;
|
165
|
+
box-shadow: none;
|
166
|
+
border: none;
|
167
|
+
background: transparent;
|
168
|
+
}
|
169
|
+
|
170
|
+
input[type="range"]::-ms-track {
|
171
|
+
-webkit-appearance: none;
|
172
|
+
box-shadow: none;
|
173
|
+
border: none;
|
174
|
+
background: transparent;
|
175
|
+
}
|
176
|
+
|
177
|
+
article.documentation h1 {
|
178
|
+
@apply scroll-m-20 text-4xl font-bold tracking-tight;
|
179
|
+
}
|
180
|
+
article.documentation subtitle {
|
181
|
+
@apply text-lg text-muted-foreground;
|
182
|
+
}
|
183
|
+
article.documentation p {
|
184
|
+
@apply leading-7 [&:not(:first-child)]:mt-6;
|
185
|
+
}
|
186
|
+
|
187
|
+
article.documentation :where(code):not(:where([class~="not-prose"] *)):before {
|
188
|
+
content: "";
|
189
|
+
}
|
190
|
+
|
191
|
+
article.documentation :where(code):not(:where([class~="not-prose"] *)):after {
|
192
|
+
content: "";
|
193
|
+
}
|
@@ -1,2 +1,21 @@
|
|
1
1
|
module ApplicationHelper
|
2
|
+
def page_title
|
3
|
+
@page_title = ""
|
4
|
+
if request.path.include?("/docs/components")
|
5
|
+
component_name = params[:component].to_s.titleize
|
6
|
+
@page_title << "#{component_name} - " if component_name.present?
|
7
|
+
end
|
8
|
+
@page_title << "shadcn/ui on Rails"
|
9
|
+
@page_title
|
10
|
+
end
|
11
|
+
|
12
|
+
def sidebar_link(text, path)
|
13
|
+
classes = "group flex w-full items-center rounded-md border border-transparent px-2 py-1 hover:underline"
|
14
|
+
classes << if request.path == path
|
15
|
+
" text-foreground font-bold"
|
16
|
+
else
|
17
|
+
" text-muted-foreground"
|
18
|
+
end
|
19
|
+
link_to text, path, class: classes
|
20
|
+
end
|
2
21
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Components::CardHelper
|
2
2
|
def render_card(footer: nil, title: nil, subtitle: nil, body: nil, **options, &block)
|
3
|
-
render "components/ui/card", title: title, subtitle: subtitle, footer: footer, body: (block ? capture(&block) : body), block:,
|
3
|
+
render "components/ui/card", title: title, subtitle: subtitle, footer: footer, body: (block ? capture(&block) : body), block:, options: options
|
4
4
|
end
|
5
5
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Components::FilterHelper
|
2
|
+
def filter_icon(&block)
|
3
|
+
content_for :filter_icon, capture(&block), flush: true
|
4
|
+
end
|
5
|
+
|
6
|
+
def render_filter(items, **options, &block)
|
7
|
+
content_for :filter_icon, "", flush: true
|
8
|
+
content = capture(&block) if block
|
9
|
+
input_class = content_for?(:filter_icon) ? "pl-1" : ""
|
10
|
+
render "components/ui/filter", items: items, options: options, input_class: input_class, content: content
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Components::InputHelper
|
2
|
+
def render_input(name:, label: false, id: nil, type: :text, value: nil, **options)
|
3
|
+
options[:class] = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 #{options[:class]} "
|
4
|
+
options[:class] << case options[:style]
|
5
|
+
when :borderless
|
6
|
+
" border-0 focus-visible:outline-none focus-visible:shadow-none focus-visible:ring-transparent"
|
7
|
+
else
|
8
|
+
" focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:border-muted"
|
9
|
+
end
|
10
|
+
options.reverse_merge!(required: false, disabled: false,
|
11
|
+
readonly: false, label: false, placeholder: "Type here...")
|
12
|
+
render partial: "components/ui/input", locals: {
|
13
|
+
type:,
|
14
|
+
label:,
|
15
|
+
name:,
|
16
|
+
value:,
|
17
|
+
id:,
|
18
|
+
options: options
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Components::ListHelper
|
2
|
+
def list_item(value:, name:, selected: false, as: :div)
|
3
|
+
content_tag as, value,
|
4
|
+
class: "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm
|
5
|
+
outline-none aria-selected:bg-accent aria-selected:text-accent-foreground hover:bg-accent hover:text-accent-foreground
|
6
|
+
data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
7
|
+
role: "option",
|
8
|
+
data: {value:, selected:},
|
9
|
+
aria: {selected:}
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_list(items, as: :div, **options)
|
13
|
+
render "components/ui/list", items:, as:, **options
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Components::SheetHelper
|
2
|
+
def render_sheet(**options, &block)
|
3
|
+
options[:direction] ||= "left"
|
4
|
+
options[:width] ||= "w-3/4"
|
5
|
+
|
6
|
+
content_for :sheet_trigger, "", flush: true
|
7
|
+
content_for :sheet_content, "", flush: true
|
8
|
+
|
9
|
+
content = capture(&block) if block
|
10
|
+
render "components/ui/sheet", content: content, options: options
|
11
|
+
end
|
12
|
+
|
13
|
+
def sheet_trigger(&block)
|
14
|
+
content_for :sheet_trigger, capture(&block), flush: true
|
15
|
+
end
|
16
|
+
|
17
|
+
def sheet_content(&block)
|
18
|
+
content_for :sheet_content, capture(&block), flush: true
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static targets = ["toggleButton"];
|
5
|
+
|
6
|
+
connect() {
|
7
|
+
this.loadThemePreference();
|
8
|
+
}
|
9
|
+
|
10
|
+
toggle() {
|
11
|
+
const isDarkMode = document.documentElement.classList.toggle("dark");
|
12
|
+
this.saveThemePreference(isDarkMode);
|
13
|
+
}
|
14
|
+
|
15
|
+
loadThemePreference() {
|
16
|
+
const isDarkMode = localStorage.getItem("themePreference") === "true";
|
17
|
+
if (isDarkMode) {
|
18
|
+
document.documentElement.classList.add("dark");
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
saveThemePreference(isDarkMode) {
|
23
|
+
localStorage.setItem("themePreference", isDarkMode);
|
24
|
+
}
|
25
|
+
}
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import { Controller } from "@hotwired/stimulus";
|
3
3
|
import "@kanety/stimulus-static-actions";
|
4
4
|
|
5
|
-
export default class extends Controller {
|
5
|
+
export default class UIDialog extends Controller {
|
6
6
|
static targets = ["dialog", "modal", "focus", "drag", "backdrop", "closeButton"];
|
7
7
|
static actions = [
|
8
8
|
["element", "keydown@window->closeByKey"],
|
@@ -64,6 +64,8 @@ export default class extends Controller {
|
|
64
64
|
this.dispatch("closed", { detail: { target: target } });
|
65
65
|
}
|
66
66
|
|
67
|
+
// Refactor Me
|
68
|
+
// This needs to be combined with the toggle method in sheet_controller
|
67
69
|
toggleClass(visible) {
|
68
70
|
if (visible) {
|
69
71
|
this.dialogTarget.classList.remove("hidden");
|
@@ -1,25 +1,5 @@
|
|
1
1
|
// Inspired By: https://github.com/stimulus-components/stimulus-dropdown/blob/master/src/index.ts
|
2
|
-
import
|
2
|
+
import UIPopover from "controllers/ui/popover_controller";
|
3
3
|
import { useTransition } from "stimulus-use";
|
4
4
|
|
5
|
-
export default class extends
|
6
|
-
// menuTarget: HTMLElement
|
7
|
-
// toggleTransition: (event?: Event) => void
|
8
|
-
// leave: (event?: Event) => void
|
9
|
-
// transitioned: false
|
10
|
-
// static targets = ['menu']
|
11
|
-
// connect (): void {
|
12
|
-
// useTransition(this, {
|
13
|
-
// element: this.menuTarget
|
14
|
-
// })
|
15
|
-
// }
|
16
|
-
// toggle (): void {
|
17
|
-
// this.toggleTransition()
|
18
|
-
// }
|
19
|
-
// hide (event: Event): void {
|
20
|
-
// // @ts-ignore
|
21
|
-
// if (!this.element.contains(event.target) && !this.menuTarget.classList.contains('hidden')) {
|
22
|
-
// this.leave()
|
23
|
-
// }
|
24
|
-
// }
|
25
|
-
}
|
5
|
+
export default class extends UIPopover {}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
export default class UIFilter extends Controller {
|
4
|
+
static targets = ["source", "item"];
|
5
|
+
|
6
|
+
connect() {}
|
7
|
+
|
8
|
+
filter(event) {
|
9
|
+
let lowerCaseFilterTerm = this.sourceTarget.value.toLowerCase();
|
10
|
+
let regex = new RegExp("^" + lowerCaseFilterTerm);
|
11
|
+
if (this.hasItemTarget) {
|
12
|
+
this.itemTargets.forEach((el, i) => {
|
13
|
+
let filterableKey = el.innerText.toLowerCase();
|
14
|
+
|
15
|
+
// Check for consecutive characters match using regex
|
16
|
+
el.classList.toggle("hidden", !regex.test(filterableKey));
|
17
|
+
});
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
@@ -3,7 +3,7 @@
|
|
3
3
|
import { Controller } from "@hotwired/stimulus";
|
4
4
|
import { createPopper } from "@popperjs/core";
|
5
5
|
|
6
|
-
export default class extends Controller {
|
6
|
+
export default class UIPopover extends Controller {
|
7
7
|
static values = {
|
8
8
|
dismissAfter: Number,
|
9
9
|
};
|
@@ -24,4 +24,32 @@ export default class extends Controller {
|
|
24
24
|
],
|
25
25
|
});
|
26
26
|
}
|
27
|
+
|
28
|
+
// Show the popover
|
29
|
+
show() {
|
30
|
+
this.contentTarget.classList.remove("hidden");
|
31
|
+
this.contentTarget.dataset.state = "open";
|
32
|
+
}
|
33
|
+
|
34
|
+
// Hide the popover
|
35
|
+
hide() {
|
36
|
+
this.contentTarget.classList.add("hidden");
|
37
|
+
this.contentTarget.dataset.state = "closed";
|
38
|
+
}
|
39
|
+
|
40
|
+
// Toggle the popover on demand
|
41
|
+
toggle(event) {
|
42
|
+
this.popperInstance.update();
|
43
|
+
if (this.contentTarget.classList.contains("hidden")) {
|
44
|
+
this.show();
|
45
|
+
|
46
|
+
if (this.hasDismissAfterValue) {
|
47
|
+
setTimeout(() => {
|
48
|
+
this.hide();
|
49
|
+
}, this.dismissAfterValue);
|
50
|
+
}
|
51
|
+
} else {
|
52
|
+
this.hide();
|
53
|
+
}
|
54
|
+
}
|
27
55
|
}
|