yummy-guide-generic-administrate 0.1.0 → 0.2.0
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/README.md +103 -0
- data/app/assets/images/yummy_guide_administrate/icon-copy.svg +4 -0
- data/app/assets/javascripts/yummy_guide_administrate/clipboards.js +81 -0
- data/app/assets/javascripts/yummy_guide_administrate/sticky_left_columns.js +21 -2
- data/app/assets/javascripts/yummy_guide_administrate/sticky_table_headers.js +576 -0
- data/app/assets/stylesheets/yummy_guide_administrate/components.scss +354 -6
- data/app/helpers/yummy_guide/administrate/collection_helper.rb +183 -3
- data/app/views/fields/yummy_guide_administrate/area/picture/_show.html.erb +1 -2
- data/app/views/fields/yummy_guide_administrate/version_item_field/_show.html.erb +1 -2
- data/app/views/fields/yummy_guide_administrate/version_whodunnit_field/_show.html.erb +1 -2
- data/app/views/yummy_guide/administrate/administrate/application/_collection.html.erb +14 -5
- data/app/views/yummy_guide/administrate/administrate/application/_fixed_table_header.html.erb +1 -0
- data/lib/yummy_guide/administrate/engine.rb +2 -1
- data/lib/yummy_guide/administrate/version.rb +1 -1
- data/spec/yummy_guide/administrate/collection_helper_spec.rb +161 -8
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1094484e89c98a0f68d56b6536786231e367755b9c3d260340180c688cff1b89
|
|
4
|
+
data.tar.gz: 46974073ea46232ca7482666c6ca8d1cbfedbee943b95783e0d7ad4d5c56ef77
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 56fe590e3c211b91e7235a98e389700d8eed1fd2c636bf6a654f4f84696429ebf4c4fb81a7cddd752f20c1bbad21bb4a463de23b535a47c84be201daccbfb6a6
|
|
7
|
+
data.tar.gz: af71f0ebb0e6f825f59ead48d3d0b4292313740aa58ea244b875f7cff2c3957a4d12329000fc5e95f8c2e3fe065e4fecde0e8e75aa19ca1ca3532410a15bdf00
|
data/README.md
CHANGED
|
@@ -43,9 +43,12 @@ bundle install
|
|
|
43
43
|
- datetime フィルターや checkbox group の組み立てを補助する helper
|
|
44
44
|
- 共通 partial / assets
|
|
45
45
|
- collection partial
|
|
46
|
+
- fixed table header partial
|
|
46
47
|
- filter form partial
|
|
48
|
+
- `clipboards.js`
|
|
47
49
|
- `filter_form.js`
|
|
48
50
|
- `sticky_left_columns.js`
|
|
51
|
+
- `sticky_table_headers.js`
|
|
49
52
|
- `components.css`
|
|
50
53
|
- 共通 field
|
|
51
54
|
- `YummyGuide::Administrate::Fields::JsonPrettyField`
|
|
@@ -113,6 +116,104 @@ engine の共通 partial に委譲します。
|
|
|
113
116
|
collection_field_name: collection_field_name %>
|
|
114
117
|
```
|
|
115
118
|
|
|
119
|
+
### 固定ヘッダーの設定
|
|
120
|
+
|
|
121
|
+
#### 1. 最小構成
|
|
122
|
+
|
|
123
|
+
gem 付属の collection partial をそのまま使う場合、table wrapper と table 本体に
|
|
124
|
+
必要な `data-*` 属性はすでに入っています。そのため、JS / CSS を読み込めば固定
|
|
125
|
+
ヘッダーは自動で有効になります。
|
|
126
|
+
|
|
127
|
+
内部的には以下のような構造になります。
|
|
128
|
+
|
|
129
|
+
```erb
|
|
130
|
+
<div class="scroll-table" data-fixed-header-scroll>
|
|
131
|
+
<table
|
|
132
|
+
aria-labelledby="<%= table_title %>"
|
|
133
|
+
data-fixed-columns-count="<%= yummy_guide_administrate_collection_table_fixed_columns_count(page: page, collection_presenter: collection_presenter) %>"
|
|
134
|
+
data-fixed-header-source
|
|
135
|
+
>
|
|
136
|
+
...
|
|
137
|
+
</table>
|
|
138
|
+
</div>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### 2. ヘッダー位置を明示したい場合
|
|
142
|
+
|
|
143
|
+
固定ヘッダーの表示位置をページ上部の特定箇所に合わせたい場合は、
|
|
144
|
+
`data-fixed-table-header` を持つ slot を `.main-content` 配下に置きます。
|
|
145
|
+
gem には専用 partial があります。
|
|
146
|
+
|
|
147
|
+
```erb
|
|
148
|
+
<header class="main-content__header">
|
|
149
|
+
<h1 id="page-title">Articles</h1>
|
|
150
|
+
<%= render "yummy_guide/administrate/administrate/application/fixed_table_header" %>
|
|
151
|
+
</header>
|
|
152
|
+
|
|
153
|
+
<section class="main-content__body">
|
|
154
|
+
<%= render "yummy_guide/administrate/administrate/application/collection",
|
|
155
|
+
collection_presenter: collection_presenter,
|
|
156
|
+
page: page,
|
|
157
|
+
resources: resources,
|
|
158
|
+
table_title: "page-title",
|
|
159
|
+
namespace: :admin,
|
|
160
|
+
resource_class: resource_class,
|
|
161
|
+
collection_field_name: resource_name %>
|
|
162
|
+
</section>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`fixed_table_header` partial 自体は以下の 1 行です。
|
|
166
|
+
|
|
167
|
+
```erb
|
|
168
|
+
<div data-fixed-table-header hidden></div>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
この slot を置かない場合でも、JS が table の直前に自動生成します。配置を制御
|
|
172
|
+
したいときだけ明示してください。
|
|
173
|
+
|
|
174
|
+
#### 3. 自前の table partial を使う場合
|
|
175
|
+
|
|
176
|
+
独自の collection partial を書く場合は、少なくとも以下を満たしてください。
|
|
177
|
+
|
|
178
|
+
- 横スクロール wrapper に `data-fixed-header-scroll` を付ける
|
|
179
|
+
- table に `data-fixed-header-source` を付ける
|
|
180
|
+
- table に `data-fixed-columns-count` を付ける
|
|
181
|
+
- header の `aria-labelledby` がページタイトルと対応している
|
|
182
|
+
|
|
183
|
+
```erb
|
|
184
|
+
<%= render "yummy_guide/administrate/administrate/application/fixed_table_header" %>
|
|
185
|
+
|
|
186
|
+
<div class="scroll-table" data-fixed-header-scroll>
|
|
187
|
+
<table
|
|
188
|
+
aria-labelledby="page-title"
|
|
189
|
+
data-fixed-header-source
|
|
190
|
+
data-fixed-columns-count="<%= yummy_guide_administrate_collection_table_fixed_columns_count(page: page, collection_presenter: collection_presenter) %>"
|
|
191
|
+
>
|
|
192
|
+
<thead>
|
|
193
|
+
<tr>
|
|
194
|
+
<th>ID</th>
|
|
195
|
+
<th>Name</th>
|
|
196
|
+
<th class="sticky actions-column">Actions</th>
|
|
197
|
+
</tr>
|
|
198
|
+
</thead>
|
|
199
|
+
<tbody>
|
|
200
|
+
<% resources.each do |resource| %>
|
|
201
|
+
<tr>
|
|
202
|
+
<td><%= resource.id %></td>
|
|
203
|
+
<td><%= resource.name %></td>
|
|
204
|
+
<td class="sticky actions-column">
|
|
205
|
+
<%= link_to "Show", [:admin, resource] %>
|
|
206
|
+
</td>
|
|
207
|
+
</tr>
|
|
208
|
+
<% end %>
|
|
209
|
+
</tbody>
|
|
210
|
+
</table>
|
|
211
|
+
</div>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`sticky actions-column` を action 列に付けると、右端列も固定できます。
|
|
215
|
+
左端の固定列数は dashboard 側の `INDEX_FIXED_COLUMNS_COUNT` で制御します。
|
|
216
|
+
|
|
116
217
|
### Datetime filter
|
|
117
218
|
|
|
118
219
|
filter form の枠と datetime 入力 partial を組み合わせて利用できます。
|
|
@@ -157,8 +258,10 @@ end
|
|
|
157
258
|
この engine の asset はホストアプリ側で明示的に読み込んでください。
|
|
158
259
|
|
|
159
260
|
```js
|
|
261
|
+
//= require yummy_guide_administrate/clipboards
|
|
160
262
|
//= require yummy_guide_administrate/filter_form
|
|
161
263
|
//= require yummy_guide_administrate/sticky_left_columns
|
|
264
|
+
//= require yummy_guide_administrate/sticky_table_headers
|
|
162
265
|
```
|
|
163
266
|
|
|
164
267
|
```scss
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none">
|
|
2
|
+
<rect x="5.25" y="2.25" width="8.5" height="10.5" rx="1.5" stroke="currentColor" stroke-width="1.25"/>
|
|
3
|
+
<path d="M3.75 5.25H3A1.75 1.75 0 0 0 1.25 7v6A1.75 1.75 0 0 0 3 14.75h5A1.75 1.75 0 0 0 9.75 13v-.75" stroke="currentColor" stroke-width="1.25" stroke-linecap="round"/>
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
function dispatchCopyEvent(name, detail) {
|
|
3
|
+
document.dispatchEvent(new CustomEvent(name, { detail: detail }));
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function showCopiedFeedback(trigger) {
|
|
7
|
+
var container = trigger.closest(".admin-copy-cell");
|
|
8
|
+
if (!container) return;
|
|
9
|
+
|
|
10
|
+
var feedback = container.querySelector("[data-role='copy-feedback']");
|
|
11
|
+
if (!feedback) return;
|
|
12
|
+
|
|
13
|
+
feedback.textContent = "Copied";
|
|
14
|
+
container.classList.add("is-copied");
|
|
15
|
+
|
|
16
|
+
if (container.copyFeedbackTimer) {
|
|
17
|
+
clearTimeout(container.copyFeedbackTimer);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
container.copyFeedbackTimer = setTimeout(function() {
|
|
21
|
+
container.classList.remove("is-copied");
|
|
22
|
+
feedback.textContent = "";
|
|
23
|
+
container.copyFeedbackTimer = null;
|
|
24
|
+
}, 1600);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function copyText(text) {
|
|
28
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
29
|
+
return navigator.clipboard.writeText(text);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return new Promise(function(resolve, reject) {
|
|
33
|
+
try {
|
|
34
|
+
var input = document.createElement("textarea");
|
|
35
|
+
input.value = text;
|
|
36
|
+
input.setAttribute("readonly", "");
|
|
37
|
+
input.style.position = "absolute";
|
|
38
|
+
input.style.left = "-9999px";
|
|
39
|
+
document.body.appendChild(input);
|
|
40
|
+
input.select();
|
|
41
|
+
document.execCommand("copy");
|
|
42
|
+
document.body.removeChild(input);
|
|
43
|
+
resolve();
|
|
44
|
+
} catch (error) {
|
|
45
|
+
reject(error);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function copyCell(trigger) {
|
|
51
|
+
var text = trigger.getAttribute("data-copy-text");
|
|
52
|
+
if (!text) return;
|
|
53
|
+
|
|
54
|
+
copyText(text).then(function() {
|
|
55
|
+
showCopiedFeedback(trigger);
|
|
56
|
+
dispatchCopyEvent("yummy-guide-administrate:copied", {
|
|
57
|
+
text: text,
|
|
58
|
+
trigger: trigger
|
|
59
|
+
});
|
|
60
|
+
}).catch(function(error) {
|
|
61
|
+
dispatchCopyEvent("yummy-guide-administrate:copy-error", {
|
|
62
|
+
text: text,
|
|
63
|
+
trigger: trigger,
|
|
64
|
+
error: error
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
document.addEventListener("click", function(event) {
|
|
70
|
+
var trigger = event.target.closest("[data-behavior='copy-cell']");
|
|
71
|
+
if (!trigger) return;
|
|
72
|
+
|
|
73
|
+
event.preventDefault();
|
|
74
|
+
event.stopPropagation();
|
|
75
|
+
if (typeof event.stopImmediatePropagation === "function") {
|
|
76
|
+
event.stopImmediatePropagation();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
copyCell(trigger);
|
|
80
|
+
}, true);
|
|
81
|
+
})();
|
|
@@ -130,12 +130,31 @@
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
if (document.readyState === "loading") {
|
|
133
|
-
document.addEventListener("DOMContentLoaded", initializeFromDocument
|
|
133
|
+
document.addEventListener("DOMContentLoaded", initializeFromDocument);
|
|
134
134
|
} else {
|
|
135
135
|
initializeFromDocument();
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
document.addEventListener("turbo:load", initializeFromDocument);
|
|
139
139
|
window.addEventListener("resize", initializeFromDocument);
|
|
140
|
-
})();
|
|
141
140
|
|
|
141
|
+
if (window.MutationObserver) {
|
|
142
|
+
var mutationObserver = new MutationObserver(function(mutations) {
|
|
143
|
+
mutations.forEach(function(mutation) {
|
|
144
|
+
mutation.addedNodes.forEach(function(node) {
|
|
145
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
146
|
+
initializeStickyColumns(node);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
mutationObserver.observe(document.documentElement, {
|
|
153
|
+
childList: true,
|
|
154
|
+
subtree: true
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
setTimeout(initializeFromDocument, 100);
|
|
159
|
+
setTimeout(initializeFromDocument, 300);
|
|
160
|
+
})();
|