copy_tuner_client 2.0.0 → 2.1.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.
data/vite.config.ts CHANGED
@@ -11,7 +11,6 @@ export default defineConfig({
11
11
  rollupOptions: {
12
12
  output: {
13
13
  entryFileNames: `javascripts/copytuner.js`,
14
- assetFileNames: `stylesheets/copytuner.[ext]`,
15
14
  },
16
15
  },
17
16
  },
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.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SonicGarden
@@ -183,7 +183,6 @@ extensions: []
183
183
  extra_rdoc_files: []
184
184
  files:
185
185
  - ".babelrc"
186
- - ".eslintrc.js"
187
186
  - ".gitattributes"
188
187
  - ".github/dependabot.yml"
189
188
  - ".github/workflows/rspec.yml"
@@ -200,7 +199,7 @@ files:
200
199
  - Rakefile
201
200
  - UPGRADING.md
202
201
  - app/assets/javascripts/copytuner.js
203
- - app/assets/stylesheets/copytuner.css
202
+ - biome.json
204
203
  - copy_tuner_client.gemspec
205
204
  - gemfiles/8.0.gemfile
206
205
  - gemfiles/8.1.gemfile
@@ -230,7 +229,9 @@ files:
230
229
  - lib/copy_tuner_client/translation_log.rb
231
230
  - lib/copy_tuner_client/version.rb
232
231
  - lib/tasks/copy_tuner_client_tasks.rake
232
+ - mise.toml
233
233
  - package.json
234
+ - pnpm-lock.yaml
234
235
  - skills/copy-tuner-to-locales-cleanup/SKILL.md
235
236
  - skills/copy-tuner-to-locales-cleanup/references/example-touchpoints.md
236
237
  - skills/copy-tuner-to-locales-cleanup/references/verification-final.md
@@ -270,18 +271,16 @@ files:
270
271
  - spec/support/fake_unicorn.rb
271
272
  - spec/support/middleware_stack.rb
272
273
  - spec/support/writing_cache.rb
273
- - src/copyray.css
274
- - src/copyray.ts
275
- - src/copytuner_bar.ts
274
+ - src/copyray-overlay.ts
275
+ - src/copytuner-bar.ts
276
276
  - src/main.ts
277
- - src/specimen.ts
277
+ - src/styles.ts
278
278
  - src/util.ts
279
279
  - src/vite-env.d.ts
280
280
  - tsconfig.json
281
281
  - ui/views/copytuner/index.html.erb
282
282
  - ui/views/layouts/copytuner_default.html.erb
283
283
  - vite.config.ts
284
- - yarn.lock
285
284
  homepage: https://github.com/SonicGarden/copy-tuner-ruby-client
286
285
  licenses: []
287
286
  metadata:
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
- }
data/src/specimen.ts DELETED
@@ -1,94 +0,0 @@
1
- import { computeBoundingBox } from './util'
2
-
3
- const ZINDEX = 2_000_000_000
4
-
5
- export default class Specimen {
6
- // @ts-expect-error TS7006
7
- constructor(element, keys, callback) {
8
- // @ts-expect-error TS2339
9
- this.element = element
10
- // @ts-expect-error TS2339
11
- this.keys = keys
12
- // @ts-expect-error TS2339
13
- this.callback = callback
14
- }
15
-
16
- show() {
17
- // @ts-expect-error TS2339
18
- this.box = this.makeBox()
19
- // @ts-expect-error TS2339
20
- if (this.box === null) return
21
-
22
- // box 全体のクリックは先頭キーを開く(広いクリック領域を維持)。複数キー時は各ラベルから個別に開ける
23
- // @ts-expect-error TS2339
24
- this.box.addEventListener('click', () => {
25
- // @ts-expect-error TS2339
26
- this.callback(this.keys[0])
27
- })
28
-
29
- // @ts-expect-error TS2339
30
- document.body.append(this.box)
31
- }
32
-
33
- remove() {
34
- // @ts-expect-error TS2339
35
- if (!this.box) {
36
- return
37
- }
38
- // @ts-expect-error TS2339
39
- this.box.remove()
40
- // @ts-expect-error TS2339
41
- this.box = null
42
- }
43
-
44
- makeBox() {
45
- const box = document.createElement('div')
46
- box.classList.add('copyray-specimen')
47
- box.classList.add('Specimen')
48
-
49
- // @ts-expect-error TS2339
50
- const bounds = computeBoundingBox(this.element)
51
- if (bounds === null) return null
52
-
53
- for (const key of Object.keys(bounds)) {
54
- // @ts-expect-error TS7053
55
- const value = bounds[key]
56
- // @ts-expect-error TS7015
57
- box.style[key] = `${value}px`
58
- }
59
- // @ts-expect-error TS2322
60
- box.style.zIndex = ZINDEX
61
-
62
- // @ts-expect-error TS2339
63
- const { position, top, left } = getComputedStyle(this.element)
64
- if (position === 'fixed') {
65
- // @ts-expect-error TS2339
66
- this.box.style.position = 'fixed'
67
- // @ts-expect-error TS2339
68
- this.box.style.top = `${top}px`
69
- // @ts-expect-error TS2339
70
- this.box.style.left = `${left}px`
71
- }
72
-
73
- // @ts-expect-error TS2339
74
- for (const key of this.keys) {
75
- box.append(this.makeLabel(key))
76
- }
77
- return box
78
- }
79
-
80
- // @ts-expect-error TS7006
81
- makeLabel(key) {
82
- const div = document.createElement('div')
83
- div.classList.add('copyray-specimen-handle')
84
- div.classList.add('Specimen')
85
- div.textContent = key
86
- // ラベルのクリックはそのキーを開く。box への伝播を止めて先頭キーとの二重発火を防ぐ
87
- div.addEventListener('click', (event) => {
88
- event.stopPropagation()
89
- // @ts-expect-error TS2339
90
- this.callback(key)
91
- })
92
- return div
93
- }
94
- }