copy_tuner_client 2.0.0 → 2.1.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/CLAUDE.md +4 -1
- data/README.md +6 -2
- data/app/assets/javascripts/copytuner.js +162 -255
- data/biome.json +39 -0
- data/index.html +9 -11
- data/lib/copy_tuner_client/copyray_middleware.rb +0 -6
- data/lib/copy_tuner_client/engine.rb +1 -1
- data/lib/copy_tuner_client/version.rb +1 -1
- data/mise.toml +3 -0
- data/package.json +9 -13
- data/pnpm-lock.yaml +600 -0
- data/skills/copy-tuner-to-t-migrate/SKILL.md +57 -8
- data/skills/copy-tuner-to-t-migrate/scripts/migrate_tt.rb +29 -2
- data/spec/copy_tuner_client/copyray_middleware_spec.rb +1 -2
- data/src/copyray-overlay.ts +125 -0
- data/src/copytuner-bar.ts +153 -0
- data/src/main.ts +29 -25
- data/src/{copyray.css → styles.ts} +104 -139
- data/src/util.ts +9 -1
- data/tsconfig.json +5 -10
- data/vite.config.ts +0 -1
- metadata +7 -9
- data/.babelrc +0 -18
- data/.eslintrc.js +0 -12
- data/app/assets/stylesheets/copytuner.css +0 -1
- data/src/copyray.ts +0 -111
- data/src/copytuner_bar.ts +0 -129
- data/src/specimen.ts +0 -94
- data/yarn.lock +0 -2540
|
@@ -1,118 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/* selector for element and children */
|
|
4
|
-
#copyray-overlay,
|
|
5
|
-
#copyray-overlay *,
|
|
6
|
-
#copyray-overlay a:hover,
|
|
7
|
-
#copyray-overlay a:visited,
|
|
8
|
-
#copyray-overlay a:active {
|
|
9
|
-
background: none;
|
|
10
|
-
border: none;
|
|
11
|
-
bottom: auto;
|
|
12
|
-
clear: none;
|
|
13
|
-
cursor: default;
|
|
14
|
-
float: none;
|
|
15
|
-
font-family: Arial, Helvetica, sans-serif;
|
|
16
|
-
font-size: medium;
|
|
17
|
-
font-style: normal;
|
|
18
|
-
font-weight: normal;
|
|
19
|
-
height: auto;
|
|
20
|
-
left: auto;
|
|
21
|
-
letter-spacing: normal;
|
|
22
|
-
line-height: normal;
|
|
23
|
-
max-height: none;
|
|
24
|
-
max-width: none;
|
|
25
|
-
min-height: 0;
|
|
26
|
-
min-width: 0;
|
|
27
|
-
overflow: visible;
|
|
28
|
-
position: static;
|
|
29
|
-
right: auto;
|
|
30
|
-
text-align: left;
|
|
31
|
-
text-decoration: none;
|
|
32
|
-
text-indent: 0;
|
|
33
|
-
text-transform: none;
|
|
34
|
-
top: auto;
|
|
35
|
-
visibility: visible;
|
|
36
|
-
white-space: normal;
|
|
37
|
-
width: auto;
|
|
38
|
-
z-index: auto;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
#copyray-overlay {
|
|
42
|
-
position: fixed;
|
|
43
|
-
left: 0;
|
|
44
|
-
top: 0;
|
|
45
|
-
bottom: 0;
|
|
46
|
-
right: 0;
|
|
47
|
-
background-image: radial-gradient(
|
|
48
|
-
ellipse farthest-corner at center,
|
|
49
|
-
rgba(0, 0, 0, 0.4) 10%,
|
|
50
|
-
rgba(0, 0, 0, 0.8) 100%
|
|
51
|
-
);
|
|
52
|
-
z-index: 9000;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.copyray-specimen {
|
|
56
|
-
position: absolute;
|
|
57
|
-
background: rgba(255, 255, 255, 0.15);
|
|
58
|
-
outline: 1px solid rgba(255, 255, 255, 0.8);
|
|
59
|
-
outline-offset: -1px;
|
|
60
|
-
color: #666;
|
|
61
|
-
font-family: 'Helvetica Neue', sans-serif;
|
|
62
|
-
font-size: 13px;
|
|
63
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.copyray-specimen:hover {
|
|
67
|
-
cursor: pointer;
|
|
68
|
-
background: rgba(255, 255, 255, 0.4);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.copyray-specimen.Specimen {
|
|
72
|
-
outline: 1px solid rgba(255, 50, 50, 0.8);
|
|
73
|
-
background: rgba(255, 50, 50, 0.1);
|
|
74
|
-
}
|
|
1
|
+
// 各 custom element の Shadow root に <style> として注入する CSS。
|
|
2
|
+
// Shadow DOM のスタイル隔離が効くため、旧 copyray.css にあった #copyray-overlay * のグローバルリセットは不要。
|
|
75
3
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
.copyray-specimen-handle {
|
|
81
|
-
float: left;
|
|
82
|
-
margin: 0 2px 2px 0;
|
|
83
|
-
background: #fff;
|
|
84
|
-
padding: 0 3px;
|
|
85
|
-
color: #333;
|
|
86
|
-
font-size: 10px;
|
|
87
|
-
cursor: pointer;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.copyray-specimen-handle.Specimen {
|
|
91
|
-
background: rgba(255, 50, 50, 0.8);
|
|
92
|
-
color: #fff;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
a.copyray-toggle-button {
|
|
96
|
-
display: block;
|
|
97
|
-
position: fixed;
|
|
98
|
-
left: 0;
|
|
99
|
-
bottom: 0;
|
|
100
|
-
color: white;
|
|
101
|
-
background: black;
|
|
102
|
-
padding: 12px 16px;
|
|
103
|
-
border-radius: 0 10px 0 0;
|
|
104
|
-
opacity: 0;
|
|
105
|
-
transition: opacity 0.6s ease-in-out;
|
|
106
|
-
z-index: 10000;
|
|
107
|
-
font-size: 12px;
|
|
108
|
-
cursor: pointer;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
a.copyray-toggle-button:hover {
|
|
112
|
-
opacity: 1;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
#copy-tuner-bar {
|
|
4
|
+
// ツールバー(<copytuner-bar>)のスタイル。:host にバー本体のレイアウトを定義する。
|
|
5
|
+
export const BAR_STYLES = `
|
|
6
|
+
:host {
|
|
116
7
|
position: fixed;
|
|
117
8
|
left: 0;
|
|
118
9
|
right: 0;
|
|
@@ -126,44 +17,45 @@ a.copyray-toggle-button:hover {
|
|
|
126
17
|
z-index: 2147483647;
|
|
127
18
|
box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.1), inset 0 2px 6px rgba(0, 0, 0, 0.8);
|
|
128
19
|
background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.3));
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:host([hidden]) {
|
|
24
|
+
display: none;
|
|
129
25
|
}
|
|
130
26
|
|
|
131
|
-
|
|
27
|
+
.log-menu {
|
|
132
28
|
position: fixed;
|
|
133
29
|
left: 0;
|
|
134
30
|
right: 0;
|
|
135
31
|
bottom: 40px;
|
|
136
32
|
max-height: calc(100vh - 40px);
|
|
137
33
|
background: #222;
|
|
138
|
-
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
139
34
|
color: #fff;
|
|
140
|
-
z-index: 2147483647;
|
|
141
35
|
overflow-y: auto;
|
|
142
36
|
}
|
|
143
37
|
|
|
144
|
-
|
|
38
|
+
.log-menu[hidden] {
|
|
39
|
+
display: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.log-menu tbody td {
|
|
145
43
|
padding: 2px 8px;
|
|
146
44
|
}
|
|
147
45
|
|
|
148
|
-
|
|
46
|
+
.log-menu tbody tr {
|
|
149
47
|
cursor: pointer;
|
|
150
48
|
}
|
|
151
49
|
|
|
152
|
-
|
|
50
|
+
.log-menu tbody tr:hover {
|
|
153
51
|
background: #444;
|
|
154
52
|
}
|
|
155
53
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
#copy-tuner-bar-log-menu tbody a:hover,
|
|
161
|
-
#copy-tuner-bar-log-menu tbody a:focus {
|
|
162
|
-
color: #fff;
|
|
163
|
-
text-decoration: underline;
|
|
54
|
+
.log-menu tbody tr[hidden] {
|
|
55
|
+
display: none;
|
|
164
56
|
}
|
|
165
57
|
|
|
166
|
-
.
|
|
58
|
+
.button {
|
|
167
59
|
position: relative;
|
|
168
60
|
display: inline-block;
|
|
169
61
|
color: #fff;
|
|
@@ -180,16 +72,17 @@ a.copyray-toggle-button:hover {
|
|
|
180
72
|
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.2),
|
|
181
73
|
inset 0 0 2px rgba(255, 255, 255, 0.2);
|
|
182
74
|
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.4);
|
|
75
|
+
text-decoration: none;
|
|
183
76
|
}
|
|
184
77
|
|
|
185
|
-
.
|
|
186
|
-
.
|
|
78
|
+
.button:hover,
|
|
79
|
+
.button:focus {
|
|
187
80
|
color: #fff;
|
|
188
81
|
text-decoration: none;
|
|
189
82
|
background-color: #555;
|
|
190
83
|
}
|
|
191
84
|
|
|
192
|
-
.
|
|
85
|
+
.notice {
|
|
193
86
|
display: inline-block;
|
|
194
87
|
margin: 8px;
|
|
195
88
|
font-size: 13px;
|
|
@@ -198,9 +91,7 @@ a.copyray-toggle-button:hover {
|
|
|
198
91
|
color: #ffd24d;
|
|
199
92
|
}
|
|
200
93
|
|
|
201
|
-
|
|
202
|
-
-webkit-appearance: none;
|
|
203
|
-
-moz-appearance: none;
|
|
94
|
+
.search {
|
|
204
95
|
appearance: none;
|
|
205
96
|
border: none;
|
|
206
97
|
border-radius: 2px;
|
|
@@ -215,13 +106,87 @@ input[type='text'].copy-tuner-bar__search {
|
|
|
215
106
|
height: auto;
|
|
216
107
|
font-size: 14px;
|
|
217
108
|
}
|
|
109
|
+
`
|
|
110
|
+
|
|
111
|
+
// オーバーレイ(<copyray-overlay>)のスタイル。
|
|
112
|
+
// :host はドキュメント原点基準(position: absolute; top/left: 0)にして、
|
|
113
|
+
// 子の specimen を computeBoundingBox のページ座標で absolute 配置できるようにする。
|
|
114
|
+
// 背景の暗転(.backdrop)だけは viewport 固定(fixed)にする。
|
|
115
|
+
export const OVERLAY_STYLES = `
|
|
116
|
+
:host {
|
|
117
|
+
position: absolute;
|
|
118
|
+
top: 0;
|
|
119
|
+
left: 0;
|
|
120
|
+
width: 0;
|
|
121
|
+
height: 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
:host([hidden]) {
|
|
125
|
+
display: none;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.backdrop {
|
|
129
|
+
position: fixed;
|
|
130
|
+
inset: 0;
|
|
131
|
+
background-image: radial-gradient(
|
|
132
|
+
ellipse farthest-corner at center,
|
|
133
|
+
rgba(0, 0, 0, 0.4) 10%,
|
|
134
|
+
rgba(0, 0, 0, 0.8) 100%
|
|
135
|
+
);
|
|
136
|
+
z-index: 9000;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.specimen {
|
|
140
|
+
position: absolute;
|
|
141
|
+
background: rgba(255, 50, 50, 0.1);
|
|
142
|
+
outline: 1px solid rgba(255, 50, 50, 0.8);
|
|
143
|
+
outline-offset: -1px;
|
|
144
|
+
color: #666;
|
|
145
|
+
font-family: 'Helvetica Neue', sans-serif;
|
|
146
|
+
font-size: 13px;
|
|
147
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
|
|
148
|
+
z-index: 2000000000;
|
|
149
|
+
}
|
|
218
150
|
|
|
219
|
-
.
|
|
220
|
-
|
|
151
|
+
.specimen:hover {
|
|
152
|
+
cursor: pointer;
|
|
153
|
+
background: rgba(255, 50, 50, 0.4);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.specimen-handle {
|
|
157
|
+
float: left;
|
|
158
|
+
margin: 0 2px 2px 0;
|
|
159
|
+
background: rgba(255, 50, 50, 0.8);
|
|
160
|
+
padding: 0 3px;
|
|
161
|
+
color: #fff;
|
|
162
|
+
font-size: 10px;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.toggle-button {
|
|
167
|
+
display: block;
|
|
168
|
+
position: fixed;
|
|
169
|
+
left: 0;
|
|
170
|
+
bottom: 0;
|
|
171
|
+
color: white;
|
|
172
|
+
background: black;
|
|
173
|
+
padding: 12px 16px;
|
|
174
|
+
border-radius: 0 10px 0 0;
|
|
175
|
+
opacity: 0;
|
|
176
|
+
transition: opacity 0.6s ease-in-out;
|
|
177
|
+
z-index: 10000;
|
|
178
|
+
font-size: 12px;
|
|
179
|
+
cursor: pointer;
|
|
180
|
+
text-decoration: none;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.toggle-button:hover {
|
|
184
|
+
opacity: 1;
|
|
221
185
|
}
|
|
222
186
|
|
|
223
187
|
@media screen and (max-width: 480px) {
|
|
224
|
-
.
|
|
225
|
-
display: none
|
|
188
|
+
.toggle-button {
|
|
189
|
+
display: none;
|
|
226
190
|
}
|
|
227
191
|
}
|
|
192
|
+
`
|
data/src/util.ts
CHANGED
|
@@ -35,4 +35,12 @@ const computeBoundingBox = (element) => {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
const debounce = <A extends unknown[]>(fn: (...args: A) => void, wait: number) => {
|
|
39
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
40
|
+
return (...args: A) => {
|
|
41
|
+
clearTimeout(timer)
|
|
42
|
+
timer = setTimeout(() => fn(...args), wait)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { computeBoundingBox, debounce, getOffset, isMac, isVisible }
|
data/tsconfig.json
CHANGED
|
@@ -3,11 +3,9 @@
|
|
|
3
3
|
"target": "ESNext",
|
|
4
4
|
"useDefineForClassFields": true,
|
|
5
5
|
"module": "ESNext",
|
|
6
|
-
"lib": [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
],
|
|
10
|
-
"moduleResolution": "Node",
|
|
6
|
+
"lib": ["ESNext", "DOM"],
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"verbatimModuleSyntax": true,
|
|
11
9
|
"strict": true,
|
|
12
10
|
"sourceMap": true,
|
|
13
11
|
"resolveJsonModule": true,
|
|
@@ -17,10 +15,7 @@
|
|
|
17
15
|
"noUnusedLocals": true,
|
|
18
16
|
"noUnusedParameters": true,
|
|
19
17
|
"noImplicitReturns": true,
|
|
20
|
-
"skipLibCheck": true
|
|
18
|
+
"skipLibCheck": true
|
|
21
19
|
},
|
|
22
|
-
"include": [
|
|
23
|
-
"client",
|
|
24
|
-
"src",
|
|
25
|
-
]
|
|
20
|
+
"include": ["src"]
|
|
26
21
|
}
|
data/vite.config.ts
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: copy_tuner_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- SonicGarden
|
|
@@ -182,8 +182,6 @@ executables: []
|
|
|
182
182
|
extensions: []
|
|
183
183
|
extra_rdoc_files: []
|
|
184
184
|
files:
|
|
185
|
-
- ".babelrc"
|
|
186
|
-
- ".eslintrc.js"
|
|
187
185
|
- ".gitattributes"
|
|
188
186
|
- ".github/dependabot.yml"
|
|
189
187
|
- ".github/workflows/rspec.yml"
|
|
@@ -200,7 +198,7 @@ files:
|
|
|
200
198
|
- Rakefile
|
|
201
199
|
- UPGRADING.md
|
|
202
200
|
- app/assets/javascripts/copytuner.js
|
|
203
|
-
-
|
|
201
|
+
- biome.json
|
|
204
202
|
- copy_tuner_client.gemspec
|
|
205
203
|
- gemfiles/8.0.gemfile
|
|
206
204
|
- gemfiles/8.1.gemfile
|
|
@@ -230,7 +228,9 @@ files:
|
|
|
230
228
|
- lib/copy_tuner_client/translation_log.rb
|
|
231
229
|
- lib/copy_tuner_client/version.rb
|
|
232
230
|
- lib/tasks/copy_tuner_client_tasks.rake
|
|
231
|
+
- mise.toml
|
|
233
232
|
- package.json
|
|
233
|
+
- pnpm-lock.yaml
|
|
234
234
|
- skills/copy-tuner-to-locales-cleanup/SKILL.md
|
|
235
235
|
- skills/copy-tuner-to-locales-cleanup/references/example-touchpoints.md
|
|
236
236
|
- skills/copy-tuner-to-locales-cleanup/references/verification-final.md
|
|
@@ -270,18 +270,16 @@ files:
|
|
|
270
270
|
- spec/support/fake_unicorn.rb
|
|
271
271
|
- spec/support/middleware_stack.rb
|
|
272
272
|
- spec/support/writing_cache.rb
|
|
273
|
-
- src/copyray.
|
|
274
|
-
- src/
|
|
275
|
-
- src/copytuner_bar.ts
|
|
273
|
+
- src/copyray-overlay.ts
|
|
274
|
+
- src/copytuner-bar.ts
|
|
276
275
|
- src/main.ts
|
|
277
|
-
- src/
|
|
276
|
+
- src/styles.ts
|
|
278
277
|
- src/util.ts
|
|
279
278
|
- src/vite-env.d.ts
|
|
280
279
|
- tsconfig.json
|
|
281
280
|
- ui/views/copytuner/index.html.erb
|
|
282
281
|
- ui/views/layouts/copytuner_default.html.erb
|
|
283
282
|
- vite.config.ts
|
|
284
|
-
- yarn.lock
|
|
285
283
|
homepage: https://github.com/SonicGarden/copy-tuner-ruby-client
|
|
286
284
|
licenses: []
|
|
287
285
|
metadata:
|
data/.babelrc
DELETED
data/.eslintrc.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
plugins: ['@sonicgarden'],
|
|
3
|
-
extends: [
|
|
4
|
-
'plugin:@sonicgarden/browser',
|
|
5
|
-
'plugin:@sonicgarden/recommended',
|
|
6
|
-
'plugin:@sonicgarden/typescript',
|
|
7
|
-
'plugin:@sonicgarden/prettier',
|
|
8
|
-
],
|
|
9
|
-
settings: {
|
|
10
|
-
'import/internal-regex': '^@/',
|
|
11
|
-
},
|
|
12
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@charset "UTF-8";#copyray-overlay,#copyray-overlay *,#copyray-overlay a:hover,#copyray-overlay a:visited,#copyray-overlay a:active{background:none;border:none;bottom:auto;clear:none;cursor:default;float:none;font-family:Arial,Helvetica,sans-serif;font-size:medium;font-style:normal;font-weight:400;height:auto;left:auto;letter-spacing:normal;line-height:normal;max-height:none;max-width:none;min-height:0;min-width:0;overflow:visible;position:static;right:auto;text-align:left;text-decoration:none;text-indent:0;text-transform:none;top:auto;visibility:visible;white-space:normal;width:auto;z-index:auto}#copyray-overlay{position:fixed;left:0;top:0;bottom:0;right:0;background-image:radial-gradient(ellipse farthest-corner at center,rgba(0,0,0,.4) 10%,rgba(0,0,0,.8) 100%);z-index:9000}.copyray-specimen{position:absolute;background:rgba(255,255,255,.15);outline:1px solid rgba(255,255,255,.8);outline-offset:-1px;color:#666;font-family:Helvetica Neue,sans-serif;font-size:13px;box-shadow:0 1px 3px #000000b3}.copyray-specimen:hover{cursor:pointer;background:rgba(255,255,255,.4)}.copyray-specimen.Specimen{outline:1px solid rgba(255,50,50,.8);background:rgba(255,50,50,.1)}.copyray-specimen.Specimen:hover{background:rgba(255,50,50,.4)}.copyray-specimen-handle{float:left;margin:0 2px 2px 0;background:#fff;padding:0 3px;color:#333;font-size:10px;cursor:pointer}.copyray-specimen-handle.Specimen{background:rgba(255,50,50,.8);color:#fff}a.copyray-toggle-button{display:block;position:fixed;left:0;bottom:0;color:#fff;background:black;padding:12px 16px;border-radius:0 10px 0 0;opacity:0;transition:opacity .6s ease-in-out;z-index:10000;font-size:12px;cursor:pointer}a.copyray-toggle-button:hover{opacity:1}#copy-tuner-bar{position:fixed;left:0;right:0;bottom:0;height:40px;padding:0 8px;background:#222;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-weight:200;color:#fff;z-index:2147483647;box-shadow:0 -1px #ffffff1a,inset 0 2px 6px #000c;background-image:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.3))}#copy-tuner-bar-log-menu{position:fixed;left:0;right:0;bottom:40px;max-height:calc(100vh - 40px);background:#222;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;color:#fff;z-index:2147483647;overflow-y:auto}#copy-tuner-bar-log-menu tbody td{padding:2px 8px}#copy-tuner-bar-log-menu tbody tr{cursor:pointer}#copy-tuner-bar-log-menu tbody tr:hover{background:#444}#copy-tuner-bar-log-menu tbody a{color:#fff}#copy-tuner-bar-log-menu tbody a:hover,#copy-tuner-bar-log-menu tbody a:focus{color:#fff;text-decoration:underline}.copy-tuner-bar-button{position:relative;display:inline-block;color:#fff;margin:8px 1px;height:24px;line-height:24px;padding:0 8px;font-size:14px;cursor:pointer;vertical-align:middle;background-color:#444;background-image:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.2));border-radius:2px;box-shadow:1px 1px 1px #00000080,inset 0 1px #fff3,inset 0 0 2px #fff3;text-shadow:0 -1px 0 rgba(0,0,0,.4)}.copy-tuner-bar-button:hover,.copy-tuner-bar-button:focus{color:#fff;text-decoration:none;background-color:#555}.copy-tuner-bar__notice{display:inline-block;margin:8px;font-size:13px;line-height:24px;vertical-align:middle;color:#ffd24d}input[type=text].copy-tuner-bar__search{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;border-radius:2px;background-image:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,0));box-shadow:inset 0 1px #0003,inset 0 0 2px #0003;padding:2px 8px;margin:0;line-height:20px;vertical-align:middle;color:#000;width:auto;height:auto;font-size:14px}.copy-tuner-hidden{display:none!important}@media screen and (max-width: 480px){.hidden-on-mobile{display:none!important}}
|
data/src/copyray.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import CopyTunerBar from './copytuner_bar'
|
|
2
|
-
import Specimen from './specimen'
|
|
3
|
-
|
|
4
|
-
const findBlurbs = () =>
|
|
5
|
-
Array.from(document.querySelectorAll('[data-copyray-key]')).map((element) => ({
|
|
6
|
-
// 1 要素に複数キーがカンマ区切りで入りうる(同一テキストノードに複数訳文が連結された場合)
|
|
7
|
-
keys: (element.getAttribute('data-copyray-key') ?? '').split(',').filter(Boolean),
|
|
8
|
-
element,
|
|
9
|
-
}))
|
|
10
|
-
|
|
11
|
-
export default class Copyray {
|
|
12
|
-
// @ts-expect-error TS7006
|
|
13
|
-
constructor(baseUrl, data, keysSkipped = false) {
|
|
14
|
-
// @ts-expect-error TS2339
|
|
15
|
-
this.baseUrl = baseUrl
|
|
16
|
-
// @ts-expect-error TS2339
|
|
17
|
-
this.data = data
|
|
18
|
-
// @ts-expect-error TS2339
|
|
19
|
-
this.isShowing = false
|
|
20
|
-
// @ts-expect-error TS2339
|
|
21
|
-
this.specimens = []
|
|
22
|
-
// @ts-expect-error TS2339
|
|
23
|
-
this.overlay = this.makeOverlay()
|
|
24
|
-
// @ts-expect-error TS2339
|
|
25
|
-
this.toggleButton = this.makeToggleButton()
|
|
26
|
-
// @ts-expect-error TS2339
|
|
27
|
-
this.boundOpen = this.open.bind(this)
|
|
28
|
-
|
|
29
|
-
// @ts-expect-error TS2339
|
|
30
|
-
this.copyTunerBar = new CopyTunerBar(document.querySelector('#copy-tuner-bar'), this.data, this.boundOpen, keysSkipped)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
show() {
|
|
34
|
-
this.reset()
|
|
35
|
-
|
|
36
|
-
// @ts-expect-error TS2339
|
|
37
|
-
document.body.append(this.overlay)
|
|
38
|
-
this.makeSpecimens()
|
|
39
|
-
|
|
40
|
-
// @ts-expect-error TS2339
|
|
41
|
-
for (const specimen of this.specimens) {
|
|
42
|
-
specimen.show()
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// @ts-expect-error TS2339
|
|
46
|
-
this.copyTunerBar.show()
|
|
47
|
-
// @ts-expect-error TS2339
|
|
48
|
-
this.isShowing = true
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
hide() {
|
|
52
|
-
// @ts-expect-error TS2339
|
|
53
|
-
this.overlay.remove()
|
|
54
|
-
this.reset()
|
|
55
|
-
// @ts-expect-error TS2339
|
|
56
|
-
this.copyTunerBar.hide()
|
|
57
|
-
// @ts-expect-error TS2339
|
|
58
|
-
this.isShowing = false
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
toggle() {
|
|
62
|
-
// @ts-expect-error TS2339
|
|
63
|
-
if (this.isShowing) {
|
|
64
|
-
this.hide()
|
|
65
|
-
} else {
|
|
66
|
-
this.show()
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// @ts-expect-error TS7006
|
|
71
|
-
open(key) {
|
|
72
|
-
// @ts-expect-error TS2339
|
|
73
|
-
window.open(`${this.baseUrl}/blurbs/${key}/edit`)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
makeSpecimens() {
|
|
77
|
-
for (const { element, keys } of findBlurbs()) {
|
|
78
|
-
// @ts-expect-error TS2339
|
|
79
|
-
this.specimens.push(new Specimen(element, keys, this.boundOpen))
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
makeToggleButton() {
|
|
84
|
-
const element = document.createElement('a')
|
|
85
|
-
|
|
86
|
-
element.addEventListener('click', () => {
|
|
87
|
-
this.show()
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
element.classList.add('copyray-toggle-button')
|
|
91
|
-
element.classList.add('hidden-on-mobile')
|
|
92
|
-
element.textContent = 'Open CopyTuner'
|
|
93
|
-
document.body.append(element)
|
|
94
|
-
|
|
95
|
-
return element
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
makeOverlay() {
|
|
99
|
-
const div = document.createElement('div')
|
|
100
|
-
div.setAttribute('id', 'copyray-overlay')
|
|
101
|
-
div.addEventListener('click', () => this.hide())
|
|
102
|
-
return div
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
reset() {
|
|
106
|
-
// @ts-expect-error TS2339
|
|
107
|
-
for (const specimen of this.specimens) {
|
|
108
|
-
specimen.remove()
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
data/src/copytuner_bar.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
// @ts-expect-error TS7016
|
|
2
|
-
import debounce from 'lodash.debounce'
|
|
3
|
-
|
|
4
|
-
const HIDDEN_CLASS = 'copy-tuner-hidden'
|
|
5
|
-
|
|
6
|
-
export default class CopytunerBar {
|
|
7
|
-
// @ts-expect-error TS7006
|
|
8
|
-
constructor(element, data, callback, keysSkipped = false) {
|
|
9
|
-
// @ts-expect-error TS2339
|
|
10
|
-
this.element = element
|
|
11
|
-
// @ts-expect-error TS2339
|
|
12
|
-
this.data = data
|
|
13
|
-
// @ts-expect-error TS2339
|
|
14
|
-
this.callback = callback
|
|
15
|
-
// @ts-expect-error TS2339
|
|
16
|
-
this.searchBoxElement = element.querySelector('.js-copy-tuner-bar-search')
|
|
17
|
-
// @ts-expect-error TS2339
|
|
18
|
-
this.logMenuElement = this.makeLogMenu()
|
|
19
|
-
// @ts-expect-error TS2339
|
|
20
|
-
this.element.append(this.logMenuElement)
|
|
21
|
-
|
|
22
|
-
// 巨大DOM/Nokogiri例外でキー付与がスキップされた場合は、オーバーレイが使えないので
|
|
23
|
-
// ツールバー(Translations in this page)から編集する旨を案内する。
|
|
24
|
-
if (keysSkipped) {
|
|
25
|
-
this.appendSkippedNotice()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
this.addHandler()
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
appendSkippedNotice() {
|
|
32
|
-
const notice = document.createElement('span')
|
|
33
|
-
notice.classList.add('copy-tuner-bar__notice')
|
|
34
|
-
notice.textContent = '⚠ This page is too large for the overlay. Use "Translations in this page" to edit.'
|
|
35
|
-
// @ts-expect-error TS2339
|
|
36
|
-
this.element.append(notice)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
addHandler() {
|
|
40
|
-
// @ts-expect-error TS2339
|
|
41
|
-
const openLogButton = this.element.querySelector('.js-copy-tuner-bar-open-log')
|
|
42
|
-
// @ts-expect-error TS7006
|
|
43
|
-
openLogButton.addEventListener('click', (event) => {
|
|
44
|
-
event.preventDefault()
|
|
45
|
-
this.toggleLogMenu()
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
// @ts-expect-error TS2339
|
|
49
|
-
this.searchBoxElement.addEventListener('input', debounce(this.onKeyup.bind(this), 250))
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
show() {
|
|
53
|
-
// @ts-expect-error TS2339
|
|
54
|
-
this.element.classList.remove(HIDDEN_CLASS)
|
|
55
|
-
// @ts-expect-error TS2339
|
|
56
|
-
this.searchBoxElement.focus()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
hide() {
|
|
60
|
-
// @ts-expect-error TS2339
|
|
61
|
-
this.element.classList.add(HIDDEN_CLASS)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
showLogMenu() {
|
|
65
|
-
// @ts-expect-error TS2339
|
|
66
|
-
this.logMenuElement.classList.remove(HIDDEN_CLASS)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
toggleLogMenu() {
|
|
70
|
-
// @ts-expect-error TS2339
|
|
71
|
-
this.logMenuElement.classList.toggle(HIDDEN_CLASS)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
makeLogMenu() {
|
|
75
|
-
const div = document.createElement('div')
|
|
76
|
-
div.setAttribute('id', 'copy-tuner-bar-log-menu')
|
|
77
|
-
div.classList.add(HIDDEN_CLASS)
|
|
78
|
-
|
|
79
|
-
const table = document.createElement('table')
|
|
80
|
-
const tbody = document.createElement('tbody')
|
|
81
|
-
tbody.classList.remove('is-not-initialized')
|
|
82
|
-
|
|
83
|
-
// @ts-expect-error TS2339
|
|
84
|
-
for (const key of Object.keys(this.data).sort()) {
|
|
85
|
-
// @ts-expect-error TS2339
|
|
86
|
-
const value = this.data[key]
|
|
87
|
-
|
|
88
|
-
if (value === '') {
|
|
89
|
-
continue
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const td1 = document.createElement('td')
|
|
93
|
-
td1.textContent = key
|
|
94
|
-
const td2 = document.createElement('td')
|
|
95
|
-
td2.textContent = value
|
|
96
|
-
const tr = document.createElement('tr')
|
|
97
|
-
tr.classList.add('copy-tuner-bar-log-menu__row')
|
|
98
|
-
tr.dataset.key = key
|
|
99
|
-
|
|
100
|
-
tr.addEventListener('click', ({ currentTarget }) => {
|
|
101
|
-
// @ts-expect-error TS2339
|
|
102
|
-
this.callback(currentTarget.dataset.key)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
tr.append(td1)
|
|
106
|
-
tr.append(td2)
|
|
107
|
-
tbody.append(tr)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
table.append(tbody)
|
|
111
|
-
div.append(table)
|
|
112
|
-
|
|
113
|
-
return div
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// @ts-expect-error TS7031
|
|
117
|
-
onKeyup({ target }) {
|
|
118
|
-
const keyword = target.value.trim()
|
|
119
|
-
this.showLogMenu()
|
|
120
|
-
|
|
121
|
-
// @ts-expect-error TS2339
|
|
122
|
-
const rows = [...this.logMenuElement.querySelectorAll('tr')]
|
|
123
|
-
|
|
124
|
-
for (const row of rows) {
|
|
125
|
-
const isShow = keyword === '' || [...row.querySelectorAll('td')].some((td) => td.textContent.includes(keyword))
|
|
126
|
-
row.classList.toggle(HIDDEN_CLASS, !isShow)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|