warped 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +25 -0
- data/Gemfile +0 -2
- data/Gemfile.lock +25 -19
- data/README.md +116 -270
- data/app/assets/config/warped_manifest.js +2 -0
- data/app/assets/javascript/warped/controllers/filter_controller.js +76 -0
- data/app/assets/javascript/warped/controllers/filters_controller.js +21 -0
- data/app/assets/javascript/warped/index.js +2 -0
- data/app/assets/stylesheets/warped/application.css +15 -0
- data/app/assets/stylesheets/warped/base.css +23 -0
- data/app/assets/stylesheets/warped/filters.css +115 -0
- data/app/assets/stylesheets/warped/pagination.css +74 -0
- data/app/assets/stylesheets/warped/search.css +33 -0
- data/app/assets/stylesheets/warped/table.css +114 -0
- data/app/views/warped/_actions.html.erb +9 -0
- data/app/views/warped/_cell.html.erb +3 -0
- data/app/views/warped/_column.html.erb +35 -0
- data/app/views/warped/_filters.html.erb +21 -0
- data/app/views/warped/_hidden_fields.html.erb +19 -0
- data/app/views/warped/_pagination.html.erb +34 -0
- data/app/views/warped/_row.html.erb +19 -0
- data/app/views/warped/_search.html.erb +21 -0
- data/app/views/warped/_table.html.erb +52 -0
- data/app/views/warped/filters/_filter.html.erb +40 -0
- data/config/importmap.rb +3 -0
- data/docs/controllers/FILTERABLE.md +193 -0
- data/docs/controllers/PAGEABLE.md +70 -0
- data/docs/controllers/README.md +8 -0
- data/docs/controllers/SEARCHABLE.md +95 -0
- data/docs/controllers/SORTABLE.md +94 -0
- data/docs/controllers/TABULATABLE.md +28 -0
- data/docs/controllers/views/PARTIALS.md +285 -0
- data/docs/jobs/README.md +22 -0
- data/docs/services/README.md +81 -0
- data/lib/generators/warped/install_generator.rb +1 -1
- data/lib/warped/api/filter/base/value.rb +52 -0
- data/lib/warped/api/filter/base.rb +84 -0
- data/lib/warped/api/filter/boolean.rb +41 -0
- data/lib/warped/api/filter/date.rb +26 -0
- data/lib/warped/api/filter/date_time.rb +32 -0
- data/lib/warped/api/filter/decimal.rb +31 -0
- data/lib/warped/api/filter/factory.rb +38 -0
- data/lib/warped/api/filter/integer.rb +38 -0
- data/lib/warped/api/filter/string.rb +25 -0
- data/lib/warped/api/filter/time.rb +25 -0
- data/lib/warped/api/filter.rb +14 -0
- data/lib/warped/api/sort/value.rb +40 -0
- data/lib/warped/api/sort.rb +65 -0
- data/lib/warped/controllers/filterable/ui.rb +46 -0
- data/lib/warped/controllers/filterable.rb +79 -42
- data/lib/warped/controllers/pageable/ui.rb +70 -0
- data/lib/warped/controllers/pageable.rb +11 -11
- data/lib/warped/controllers/searchable/ui.rb +37 -0
- data/lib/warped/controllers/searchable.rb +2 -0
- data/lib/warped/controllers/sortable/ui.rb +53 -0
- data/lib/warped/controllers/sortable.rb +53 -33
- data/lib/warped/controllers/tabulatable/ui.rb +54 -0
- data/lib/warped/controllers/tabulatable.rb +13 -27
- data/lib/warped/emails/components/align.rb +21 -0
- data/lib/warped/emails/components/base.rb +116 -0
- data/lib/warped/emails/components/button.rb +58 -0
- data/lib/warped/emails/components/divider.rb +15 -0
- data/lib/warped/emails/components/heading.rb +65 -0
- data/lib/warped/emails/components/layouts/columns.rb +36 -0
- data/lib/warped/emails/components/layouts/cta.rb +38 -0
- data/lib/warped/emails/components/layouts/main.rb +34 -0
- data/lib/warped/emails/components/link.rb +36 -0
- data/lib/warped/emails/components/spacer.rb +15 -0
- data/lib/warped/emails/components/stepper.rb +104 -0
- data/lib/warped/emails/components/table.rb +37 -0
- data/lib/warped/emails/components/text.rb +67 -0
- data/lib/warped/emails/helpers.rb +26 -0
- data/lib/warped/emails/slottable.rb +61 -0
- data/lib/warped/emails/styleable.rb +160 -0
- data/lib/warped/engine.rb +19 -0
- data/lib/warped/queries/filter.rb +32 -12
- data/lib/warped/table/action.rb +33 -0
- data/lib/warped/table/column.rb +34 -0
- data/lib/warped/version.rb +1 -1
- data/lib/warped.rb +2 -0
- data/warped.gemspec +1 -1
- metadata +73 -7
- data/lib/warped/emails/.keep +0 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class FilterController extends Controller {
|
4
|
+
static targets = ["relation", "relationInput", "value", "valueInput", "panel", "badgeValue"]
|
5
|
+
static outlets = ["filter"]
|
6
|
+
static classes = ["empty", "collapsed"]
|
7
|
+
|
8
|
+
|
9
|
+
clickOutside(event) {
|
10
|
+
if (!this.element.contains(event.target)) {
|
11
|
+
this.close();
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
toggle() {
|
16
|
+
this.collapsedClasses.forEach(c => this.panelTarget.classList.toggle(c))
|
17
|
+
|
18
|
+
this.filterOutlets.forEach(outlet => {
|
19
|
+
if (this != outlet) {
|
20
|
+
outlet.close();
|
21
|
+
}
|
22
|
+
})
|
23
|
+
}
|
24
|
+
|
25
|
+
close() {
|
26
|
+
this.panelTarget.classList.add(...this.collapsedClasses)
|
27
|
+
}
|
28
|
+
|
29
|
+
collapsePanel() {
|
30
|
+
this.panelTarget.classList.add(...this.collapsedClasses)
|
31
|
+
}
|
32
|
+
|
33
|
+
uncollapsePanel() {
|
34
|
+
this.panelTarget.classList.remove(...this.collapsedClasses)
|
35
|
+
}
|
36
|
+
|
37
|
+
changeRelation() {
|
38
|
+
if (this.valueInputTarget.value) {
|
39
|
+
this.relationTarget.textContent = `${this.relationInputTarget.value}:`
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
changeValue() {
|
44
|
+
const currentFilterValue = this.valueInputTarget.value.trim()
|
45
|
+
|
46
|
+
this.valueTarget.textContent = currentFilterValue
|
47
|
+
this.changeRelation()
|
48
|
+
|
49
|
+
if (currentFilterValue) {
|
50
|
+
this.badgeValueTarget.classList.remove(...this.collapsedClasses)
|
51
|
+
this.element.classList.remove(this.emptyClass)
|
52
|
+
} else {
|
53
|
+
this.relationTarget.textContent = "";
|
54
|
+
this.badgeValueTarget.classList.add(...this.collapsedClasses)
|
55
|
+
this.element.classList.add(this.emptyClass)
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
clear(submit = true) {
|
60
|
+
this.valueTarget.textContent = ""
|
61
|
+
this.valueInputTarget.value = ""
|
62
|
+
this.relationInputTarget.value = ""
|
63
|
+
this.badgeValueTarget.classList.add("hidden")
|
64
|
+
this.element.classList.add(this.emptyClass)
|
65
|
+
|
66
|
+
if (submit) {
|
67
|
+
this.form.requestSubmit();
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
get form() {
|
72
|
+
return this.element.closest("form")
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
export { FilterController }
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class FiltersController extends Controller {
|
4
|
+
static outlets = ["filter"]
|
5
|
+
|
6
|
+
clearAll(event) {
|
7
|
+
event.preventDefault();
|
8
|
+
|
9
|
+
this.filterOutlets.forEach(outlet => {
|
10
|
+
outlet.clear(false);
|
11
|
+
})
|
12
|
+
|
13
|
+
this.form.requestSubmit();
|
14
|
+
}
|
15
|
+
|
16
|
+
get form() {
|
17
|
+
return this.element;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
export { FiltersController }
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,23 @@
|
|
1
|
+
:root {
|
2
|
+
/* colors */
|
3
|
+
--warped-base: white;
|
4
|
+
--warped-base-rgb: 255, 255, 255;
|
5
|
+
|
6
|
+
--warped-neutral: #1F2937;
|
7
|
+
--warped-neutral-rgb: 31, 41, 55;
|
8
|
+
|
9
|
+
--warped-neutral-content: #fbfbfb;
|
10
|
+
--warped-neutral-content-rgb: 251, 251, 251;
|
11
|
+
|
12
|
+
--warped-primary: #2563EB;
|
13
|
+
--warped-primary-rgb: 37, 99, 235;
|
14
|
+
|
15
|
+
--warped-primary-content: #fbfbfb;
|
16
|
+
--warped-primary-content-rgb: 251, 251, 251;
|
17
|
+
|
18
|
+
--warped-danger: #EF4444;
|
19
|
+
--warped-danger-rgb: 239, 68, 68;
|
20
|
+
|
21
|
+
/* roundness */
|
22
|
+
--warped-roundness: 0.5rem;
|
23
|
+
}
|
@@ -0,0 +1,115 @@
|
|
1
|
+
.warped-filters {
|
2
|
+
width: 100%;
|
3
|
+
display: flex;
|
4
|
+
gap: 0.5rem;
|
5
|
+
background-color: var(--warped-base);
|
6
|
+
border-radius: var(--warped-roundness);
|
7
|
+
flex-wrap: wrap
|
8
|
+
}
|
9
|
+
|
10
|
+
.warped-filters--submit {
|
11
|
+
background-color: var(--warped-primary);
|
12
|
+
color: var(--warped-primary-content);
|
13
|
+
padding: 0.5rem;
|
14
|
+
border-radius: var(--warped-roundness);
|
15
|
+
font-size: 0.875rem;
|
16
|
+
cursor: pointer;
|
17
|
+
}
|
18
|
+
|
19
|
+
.warped-filters--clear {
|
20
|
+
background-color: var(--warped-neutral);
|
21
|
+
color: var(--warped-neutral-content);
|
22
|
+
padding: 0.5rem;
|
23
|
+
border-radius: var(--warped-roundness);
|
24
|
+
font-size: 0.875rem;
|
25
|
+
cursor: pointer;
|
26
|
+
}
|
27
|
+
|
28
|
+
.warped-filters--filter {
|
29
|
+
display: flex;
|
30
|
+
gap: 0.25rem;
|
31
|
+
height: 100%;
|
32
|
+
border-radius: var(--warped-roundness);
|
33
|
+
background-color: var(--warped-base);
|
34
|
+
padding-left: 0.5rem;
|
35
|
+
padding-right: 0.5rem;
|
36
|
+
padding-top: 0.25rem;
|
37
|
+
padding-bottom: 0.25rem;
|
38
|
+
position: relative;
|
39
|
+
border: 1px solid var(--warped-neutral);
|
40
|
+
align-items: center;
|
41
|
+
}
|
42
|
+
|
43
|
+
.warped-filters--filter-inactive {
|
44
|
+
border: 1px dashed var(--warped-neutral);
|
45
|
+
}
|
46
|
+
|
47
|
+
.warped-filters--filter--label {
|
48
|
+
font-size: 0.875rem;
|
49
|
+
color: var(--warped-neutral);
|
50
|
+
font-weight: 500;
|
51
|
+
}
|
52
|
+
|
53
|
+
.warped-filters--filter--icon {
|
54
|
+
height: 1.5rem;
|
55
|
+
width: 1.5rem;
|
56
|
+
color: var(--warped-neutral);
|
57
|
+
cursor: pointer;
|
58
|
+
}
|
59
|
+
|
60
|
+
.warped-filters--filter--value {
|
61
|
+
display: flex;
|
62
|
+
transition: all 200ms;
|
63
|
+
color: var(--warped-neutral);
|
64
|
+
}
|
65
|
+
|
66
|
+
.warped-filters--filter--panel-collapsed {
|
67
|
+
visibility: hidden;
|
68
|
+
opacity: 0;
|
69
|
+
}
|
70
|
+
|
71
|
+
.warped-filters--filter--value--values {
|
72
|
+
font-size: 0.875rem;
|
73
|
+
color: var(--warped-neutral);
|
74
|
+
font-weight: 600;
|
75
|
+
}
|
76
|
+
|
77
|
+
.warped-filters--filter--panel {
|
78
|
+
transition: all 200ms;
|
79
|
+
width: max-content;
|
80
|
+
position: absolute;
|
81
|
+
top: 2.5rem;
|
82
|
+
left: 0;
|
83
|
+
background-color: var(--warped-base);
|
84
|
+
border-radius: var(--warped-roundness);
|
85
|
+
padding: 0.5rem;
|
86
|
+
display: flex;
|
87
|
+
z-index: 40;
|
88
|
+
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
|
89
|
+
}
|
90
|
+
|
91
|
+
.warped-filters--filter--panel--remove {
|
92
|
+
cursor: pointer;
|
93
|
+
color: var(--warped-danger);
|
94
|
+
width: 2rem;
|
95
|
+
stroke-width: 2;
|
96
|
+
}
|
97
|
+
|
98
|
+
.warped-filters--filter--panel--select {
|
99
|
+
width: max-content;
|
100
|
+
padding-left: 0.5rem;
|
101
|
+
padding-top: 0.25rem;
|
102
|
+
padding-bottom: 0.25rem;
|
103
|
+
border-top-left-radius: var(--warped-roundness);
|
104
|
+
border-bottom-left-radius: var(--warped-roundness);
|
105
|
+
border-right: 1px solid var(--warped-neutral);
|
106
|
+
}
|
107
|
+
|
108
|
+
.warped-filters--filter--panel--input {
|
109
|
+
width: max-content;
|
110
|
+
padding-top: 0.25rem;
|
111
|
+
padding-bottom: 0.25rem;
|
112
|
+
border-top-right-radius: var(--warped-roundness);
|
113
|
+
border-bottom-right-radius: var(--warped-roundness);
|
114
|
+
border-left: 0;
|
115
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
.warped--pagination {
|
2
|
+
display: flex;
|
3
|
+
flex-wrap: wrap;
|
4
|
+
justify-content: center;
|
5
|
+
width: 100%;
|
6
|
+
height: 2.5rem;
|
7
|
+
}
|
8
|
+
|
9
|
+
.warped--pagination--btn {
|
10
|
+
background-color: var(--warped-neutral);
|
11
|
+
color: var(--warped-neutral-content);
|
12
|
+
padding: 0.25rem 0.5rem;
|
13
|
+
display: flex;
|
14
|
+
justify-content: center;
|
15
|
+
align-items: center;
|
16
|
+
min-width: 2.5rem;
|
17
|
+
}
|
18
|
+
|
19
|
+
.warped--pagination--btn button {
|
20
|
+
height: 100%;
|
21
|
+
width: 100%;
|
22
|
+
}
|
23
|
+
|
24
|
+
.warped--pagination--btn:not(:last-child) {
|
25
|
+
border-right: 1px solid var(--warped-neutral-content);
|
26
|
+
}
|
27
|
+
|
28
|
+
.warped--pagination--btn:first-child {
|
29
|
+
border-top-left-radius: var(--warped-roundness);
|
30
|
+
border-bottom-left-radius: var(--warped-roundness);
|
31
|
+
width: 7rem;
|
32
|
+
}
|
33
|
+
|
34
|
+
.warped--pagination--btn:last-child {
|
35
|
+
border-top-right-radius: var(--warped-roundness);
|
36
|
+
border-bottom-right-radius: var(--warped-roundness);
|
37
|
+
width: 7rem;
|
38
|
+
}
|
39
|
+
|
40
|
+
.warped--pagination--btn:hover {
|
41
|
+
background-color: var(--warped-primary);
|
42
|
+
color: var(--warped-primary-content);
|
43
|
+
}
|
44
|
+
|
45
|
+
.warped--pagination--btn-disabled {
|
46
|
+
background-color: var(--warped-neutral);
|
47
|
+
color: var(--warped-neutral-content);
|
48
|
+
padding: 0.25rem 0.5rem;
|
49
|
+
cursor: not-allowed;
|
50
|
+
}
|
51
|
+
|
52
|
+
.warped--pagination--btn-disabled:hover {
|
53
|
+
background-color: var(--warped-neutral);
|
54
|
+
}
|
55
|
+
|
56
|
+
.warped--pagination--btn-active {
|
57
|
+
background-color: var(--warped-primary);
|
58
|
+
color: var(--warped-primary-content);
|
59
|
+
padding: 0.25rem 0.5rem;
|
60
|
+
cursor: pointer;
|
61
|
+
}
|
62
|
+
|
63
|
+
.warped--pagination--btn-inactive {
|
64
|
+
background-color: var(--warped-neutral);
|
65
|
+
color: var(--warped-neutral-content);
|
66
|
+
padding: 0.25rem 0.5rem;
|
67
|
+
cursor: pointer;
|
68
|
+
}
|
69
|
+
|
70
|
+
.warped--pagination--btn-gap:hover {
|
71
|
+
background-color: var(--warped-neutral);
|
72
|
+
color: var(--warped-neutral-content);
|
73
|
+
cursor: not-allowed;
|
74
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
.warped-searchbar {
|
2
|
+
display: flex;
|
3
|
+
width: 100%;
|
4
|
+
background-color: white;
|
5
|
+
border-radius: var(--warped-roundness);
|
6
|
+
}
|
7
|
+
|
8
|
+
.warped-searchbar--button {
|
9
|
+
background-color: var(--warped-neutral);
|
10
|
+
color: var(--warped-neutral-content);
|
11
|
+
stroke: var(--warped-neutral-content);
|
12
|
+
padding-left: 1rem;
|
13
|
+
padding-right: 1rem;
|
14
|
+
padding-top: 0.5rem;
|
15
|
+
padding-bottom: 0.5rem;
|
16
|
+
border-top-left-radius: var(--warped-roundness);
|
17
|
+
border-bottom-left-radius: var(--warped-roundness);
|
18
|
+
}
|
19
|
+
|
20
|
+
.warped-searchbar--button svg {
|
21
|
+
height: 1.25rem;
|
22
|
+
width: 1.25rem;
|
23
|
+
}
|
24
|
+
|
25
|
+
.warped-searchbar--input {
|
26
|
+
flex-grow: 1;
|
27
|
+
border-top: 1px solid var(--warped-neutral);
|
28
|
+
border-right: 1px solid var(--warped-neutral);
|
29
|
+
border-bottom: 1px solid var(--warped-neutral);
|
30
|
+
border-top-right-radius: var(--warped-roundness);
|
31
|
+
border-bottom-right-radius: var(--warped-roundness);
|
32
|
+
padding-left: 0.5rem;
|
33
|
+
}
|
@@ -0,0 +1,114 @@
|
|
1
|
+
/* This file contains all the styles necessary for Warped::Table to work */
|
2
|
+
.warped-table {
|
3
|
+
display: flex;
|
4
|
+
flex-direction: column;
|
5
|
+
width: 100%;
|
6
|
+
row-gap: 0.5rem;
|
7
|
+
background-color: var(--warped-base);
|
8
|
+
border-radius: var(--warped-roundness);
|
9
|
+
padding: 0.5rem;
|
10
|
+
}
|
11
|
+
|
12
|
+
.warped-table--container {
|
13
|
+
overflow-x: auto;
|
14
|
+
}
|
15
|
+
|
16
|
+
.warped-table--controls {
|
17
|
+
display: flex;
|
18
|
+
flex-direction: column;
|
19
|
+
row-gap: 0.5rem;
|
20
|
+
}
|
21
|
+
|
22
|
+
.warped-table--table {
|
23
|
+
width: 100%;
|
24
|
+
border-collapse: collapse;
|
25
|
+
border-spacing: 0;
|
26
|
+
display: table;
|
27
|
+
}
|
28
|
+
|
29
|
+
.warped-table--table--header {
|
30
|
+
display: table-header-group;
|
31
|
+
background-color: var(--warped-neutral);
|
32
|
+
}
|
33
|
+
|
34
|
+
.warped-table--table--header .warped-table--table--row .warped-table--table--cell {
|
35
|
+
font-weight: 500;
|
36
|
+
color: var(--warped-neutral-content);
|
37
|
+
border-right: 1px solid var(--warped-neutral-content);
|
38
|
+
padding: 0 0.25rem;
|
39
|
+
stroke: var(--warped-neutral-content);
|
40
|
+
stroke-width: 0.5;
|
41
|
+
}
|
42
|
+
|
43
|
+
.warped-table--table--header .warped-table--table--row .warped-table--table--cell form {
|
44
|
+
width: 100%;
|
45
|
+
}
|
46
|
+
|
47
|
+
.warped-table--table--header .warped-table--table--row .warped-table--table--cell form button {
|
48
|
+
display: flex;
|
49
|
+
gap: 0.25rem;
|
50
|
+
width: 100%;
|
51
|
+
}
|
52
|
+
|
53
|
+
.warped-table--table--header .warped-table--table--row .warped-table--table--cell form button svg {
|
54
|
+
width: 1.25rem;
|
55
|
+
height: 1.25rem;
|
56
|
+
margin-top: auto;
|
57
|
+
margin-bottom: auto;
|
58
|
+
}
|
59
|
+
|
60
|
+
.warped-table--table--header .warped-table--table--row .warped-table--table--cell:last-child {
|
61
|
+
border-right: none;
|
62
|
+
}
|
63
|
+
|
64
|
+
.warped-table--table--row {
|
65
|
+
display: table-row;
|
66
|
+
}
|
67
|
+
|
68
|
+
.warped-table--table--row:not(:last-child) {
|
69
|
+
border-bottom: 1px solid var(--warped-neutral);
|
70
|
+
}
|
71
|
+
|
72
|
+
.warped-table--table--cell {
|
73
|
+
display: table-cell;
|
74
|
+
padding: 0.25rem;
|
75
|
+
vertical-align: middle;
|
76
|
+
}
|
77
|
+
|
78
|
+
.warped-table--table--row-group {
|
79
|
+
display: table-row-group;
|
80
|
+
}
|
81
|
+
|
82
|
+
.warped-table--table--row-group>*+* {
|
83
|
+
border-top: 1px solid var(--warped-neutral);
|
84
|
+
}
|
85
|
+
|
86
|
+
.warped-table--table--row-group .warped-table--table--empty-row:only-child {
|
87
|
+
display: table-row;
|
88
|
+
}
|
89
|
+
|
90
|
+
.warped-table--table--row-group .warped-table--table--row:nth-child(odd) {
|
91
|
+
background-color: rgba(var(--warped-neutral-rgb), 0.1);
|
92
|
+
}
|
93
|
+
|
94
|
+
.warped-table--table--row-group .warped-table--table--empty-row {
|
95
|
+
display: none;
|
96
|
+
position: relative;
|
97
|
+
height: 3rem;
|
98
|
+
}
|
99
|
+
|
100
|
+
.warped-table--table--row-group .warped-table--table--empty-row .warped-table--table--cell {
|
101
|
+
position: absolute;
|
102
|
+
width: 100%;
|
103
|
+
height: 100%;
|
104
|
+
text-align: center;
|
105
|
+
font-weight: 500;
|
106
|
+
padding-top: 0.5rem;
|
107
|
+
}
|
108
|
+
|
109
|
+
.warped-table--action {
|
110
|
+
padding: 0.25rem 0.5rem;
|
111
|
+
border-radius: var(--warped-roundness);
|
112
|
+
background-color: var(--warped-neutral);
|
113
|
+
color: var(--warped-neutral-content);
|
114
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<%# locals: (resource:, actions:[])%>
|
2
|
+
|
3
|
+
<div class="warped-table--table--cell">
|
4
|
+
<% actions.each do |action| %>
|
5
|
+
<% opts = action.options.deep_dup %>
|
6
|
+
<% action_class = "warped-table--action #{opts.delete(:class)}" %>
|
7
|
+
<%= link_to (action.name(resource)), action.path(resource), class: action_class, **opts %>
|
8
|
+
<% end %>
|
9
|
+
</div>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<%# locals: (path:, column:, turbo_action:) %>
|
2
|
+
|
3
|
+
<div class="warped-table--table--cell">
|
4
|
+
<% if controller.class.include?(Warped::Controllers::Sortable::Ui) && sorted? && sortable_field?(column.parameter_name) %>
|
5
|
+
<% html_form_options = {}.tap do |hash| %>
|
6
|
+
<% hash.merge!(filter_url_params) if try(:filtered?) %>
|
7
|
+
<% hash.merge!(paginate_url_params) if try(:sorted?) %>
|
8
|
+
<% hash.merge!(search_url_params) if try(:searched?) %>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<% column_sorted = sorted_field?(column.parameter_name) %>
|
12
|
+
<% sort_direction = column_sorted ? current_action_sort_value.opposite_direction : default_sort_direction %>
|
13
|
+
|
14
|
+
<%= button_to(path, { "data-turbo-action" => turbo_action, method: :get, params: html_form_options.merge(sort_key: column.parameter_name, sort_direction: sort_direction) }) do %>
|
15
|
+
<% if column_sorted %>
|
16
|
+
<% if current_action_sort_value.asc? %>
|
17
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
18
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 15.75 7.5-7.5 7.5 7.5" />
|
19
|
+
</svg>
|
20
|
+
<% else %>
|
21
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
22
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
23
|
+
</svg>
|
24
|
+
<% end %>
|
25
|
+
<% else %>
|
26
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
27
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 15 12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />
|
28
|
+
</svg>
|
29
|
+
<% end %>
|
30
|
+
<span> <%= column.display_name %> </span>
|
31
|
+
<% end %>
|
32
|
+
<% else %>
|
33
|
+
<%= column.display_name %>
|
34
|
+
<% end %>
|
35
|
+
</div>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%# locals: (path:, turbo_action:, **options) %>
|
2
|
+
|
3
|
+
<% opts = options.deep_dup %>
|
4
|
+
|
5
|
+
<% data = opts.delete(:data) { {} } %>
|
6
|
+
<% data.merge!(controller: "filters #{data[:controller]}", filters_filter_outlet: ".warped-filters--filter", turbo_action:) %>
|
7
|
+
|
8
|
+
<% html = opts.extract!(:html) %>
|
9
|
+
<% html_class = opts.delete(:class) %>
|
10
|
+
<% html.merge!(class: "warped-filters #{html_class}") %>
|
11
|
+
|
12
|
+
<%= form_with url: path, method: :get, html:, data:, **opts do |f| %>
|
13
|
+
<%= f.submit "Filter", class: "warped-filters--submit" %>
|
14
|
+
<%= f.button "Clear", type: :reset, class: "warped-filters--clear", data: { action: "filters#clearAll" } %>
|
15
|
+
|
16
|
+
<% current_action_filters.each do |filter| %>
|
17
|
+
<%= render "warped/filters/filter", form: f, filter: filter %>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<%= render "warped/hidden_fields", form: f, modules: %i[sortable searchable] %>
|
21
|
+
<% end %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<%# locals: (form:, modules:) %>
|
2
|
+
|
3
|
+
<% Array.wrap(modules).each do |module_name| %>
|
4
|
+
<% if module_name.to_sym == :searchable && try(:searched?) %>
|
5
|
+
<%= form.hidden_field search_param, value: search_term %>
|
6
|
+
<% elsif module_name.to_sym == :filterable && try(:filtered?) %>
|
7
|
+
<% filter_url_params.each do |key, value| %>
|
8
|
+
<%= form.hidden_field key, value: %>
|
9
|
+
<% end %>
|
10
|
+
<% elsif module_name.to_sym == :sortable && try(:sorted?) %>
|
11
|
+
<% sort_url_params.each do |key, value| %>
|
12
|
+
<%= form.hidden_field key, value: %>
|
13
|
+
<% end %>
|
14
|
+
<% elsif module_name.to_sym == :pageable && try(:paginated?) %>
|
15
|
+
<% paginate_url_params.each do |key, value| %>
|
16
|
+
<%= form.hidden_field key, value: %>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<%# locals: (path:, turbo_action:, **options) %>
|
2
|
+
|
3
|
+
<% opts = options.deep_dup %>
|
4
|
+
<% pagination_class = "warped--pagination #{opts.delete(:class)}" %>
|
5
|
+
|
6
|
+
<% uri = URI(path) %>
|
7
|
+
|
8
|
+
<% html_form_options = {}.tap do |hash| %>
|
9
|
+
<% hash.merge!(sort_url_params) if try(:sorted?) %>
|
10
|
+
<% hash.merge!(filter_url_params) if try(:filtered?) %>
|
11
|
+
<% hash.merge!(search_url_params) if try(:searched?) %>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<%= tag.nav(class: pagination_class, role: "navigation", **opts) do %>
|
15
|
+
<% if pagination[:prev_page] -%> <%= button_to("Previous", path, { "data-turbo-action" => turbo_action, method: :get, form_class: "warped--pagination--btn", params: html_form_options.merge(page: pagination[:prev_page]) }) %>
|
16
|
+
<% else -%> <span class="warped--pagination--btn warped--pagination--btn-disabled" disabled>Previous</span>
|
17
|
+
<% end -%>
|
18
|
+
|
19
|
+
<% pagination[:series].each do |item| -%>
|
20
|
+
<% if item.is_a?(Integer) -%> <%= button_to(item, path, { "data-turbo-action" => turbo_action, method: :get, form_class: "warped--pagination--btn warped--pagination--btn-inactive", params: html_form_options.merge(page: item) }) %>
|
21
|
+
<% elsif item.is_a?(String) -%> <span class="warped--pagination--btn warped--pagination--btn-active"><%= item %></span>
|
22
|
+
<% elsif item == :gap %>
|
23
|
+
<span class="warped--pagination--btn warped--pagination--btn-gap">
|
24
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
25
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM12.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM18.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z" />
|
26
|
+
</svg>
|
27
|
+
</span>
|
28
|
+
<% end -%>
|
29
|
+
<% end -%>
|
30
|
+
|
31
|
+
<% if pagination[:next_page] -%> <%= button_to("Next", path, { "data-turbo-action" => turbo_action, method: :get, form_class: "warped--pagination--btn", params: html_form_options.merge(page: pagination[:next_page]) }) %>
|
32
|
+
<% else -%> <span class=" warped--pagination--btn warped--pagination--btn-disabled" disabled>Next</span>
|
33
|
+
<% end -%>
|
34
|
+
<% end %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<%# locals: (resource:, columns:, path: nil, actions: nil) -%>
|
2
|
+
|
3
|
+
<% element_tag = path.present? ? :a : :div %>
|
4
|
+
|
5
|
+
<%= content_tag element_tag, **{ class: "warped-table--table--row" }.merge!(href: path).compact_blank do %>
|
6
|
+
<% if (block = yield).present? %>
|
7
|
+
<%= block %>
|
8
|
+
<% else %>
|
9
|
+
<% columns.each do |column| %>
|
10
|
+
<%= render "warped/cell" do %>
|
11
|
+
<%= column.content_for(resource) %>
|
12
|
+
<% end %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<% if actions.present? %>
|
16
|
+
<%= render "warped/actions", actions:, resource: %>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%# locals: (path:, turbo_action:, **options) %>
|
2
|
+
|
3
|
+
<% opts = options.deep_dup %>
|
4
|
+
|
5
|
+
<% html = opts.extract!(:html) %>
|
6
|
+
<% html.merge!(class: "warped-searchbar #{opts.delete(:class)}") %>
|
7
|
+
|
8
|
+
<% data = opts.delete(:data) { {} } %>
|
9
|
+
<% data.merge!(turbo_action:) %>
|
10
|
+
|
11
|
+
<%= form_with url: path, method: :get, data:, html:, **opts do |f| %>
|
12
|
+
<%= f.button type: :submit, class: "warped-searchbar--button", name: nil do %>
|
13
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
14
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
15
|
+
</svg>
|
16
|
+
<% end %>
|
17
|
+
|
18
|
+
<%= f.text_field search_param, autocomplete: "off", value: search_term, class: "warped-searchbar--input" %>
|
19
|
+
|
20
|
+
<%= render "warped/hidden_fields", form: f, modules: %i[pageable sortable filterable] %>
|
21
|
+
<% end %>
|