copy_tuner_client 0.10.0 → 0.13.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/.eslintrc.js +12 -0
- data/.gitattributes +2 -0
- data/.github/workflows/rspec.yml +22 -30
- data/.ruby-version +1 -1
- data/.vscode/settings.json +7 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +168 -145
- data/README.md +8 -10
- data/app/assets/javascripts/main.js +388 -0
- data/app/assets/stylesheets/style.css +1 -0
- data/copy_tuner_client.gemspec +3 -3
- data/gemfiles/6.1.gemfile +5 -0
- data/gemfiles/7.0.gemfile +5 -0
- data/gemfiles/main.gemfile +5 -0
- data/index.html +34 -0
- data/lib/copy_tuner_client/configuration.rb +9 -1
- data/lib/copy_tuner_client/copyray_middleware.rb +15 -29
- data/lib/copy_tuner_client/engine.rb +6 -31
- data/lib/copy_tuner_client/errors.rb +3 -0
- data/lib/copy_tuner_client/helper_extension.rb +34 -0
- data/lib/copy_tuner_client/i18n_backend.rb +6 -0
- data/lib/copy_tuner_client/version.rb +1 -1
- data/package.json +14 -15
- data/spec/copy_tuner_client/helper_extension_spec.rb +40 -0
- data/spec/copy_tuner_client/i18n_backend_spec.rb +2 -0
- data/{app/assets/stylesheets → src}/copyray.css +0 -0
- data/src/copyray.ts +130 -0
- data/src/copytuner_bar.ts +115 -0
- data/src/main.ts +58 -0
- data/src/specimen.ts +84 -0
- data/src/util.ts +38 -0
- data/src/vite-env.d.ts +1 -0
- data/tsconfig.json +26 -0
- data/vite.config.ts +18 -0
- data/yarn.lock +2251 -0
- metadata +36 -27
- data/.eslintrc +0 -4
- data/app/assets/javascripts/copyray.js +0 -1069
- data/app/views/_copy_tuner_bar.html.erb +0 -6
- data/gemfiles/5.2.gemfile +0 -7
- data/gemfiles/6.0.gemfile +0 -7
- data/package-lock.json +0 -4341
- data/rollup.config.js +0 -16
- data/src/copyray.js +0 -112
- data/src/copytuner_bar.js +0 -96
- data/src/main.js +0 -42
- data/src/specimen.js +0 -63
- data/src/util.js +0 -32
data/package.json
CHANGED
@@ -5,26 +5,25 @@
|
|
5
5
|
"author": "SonicGarden",
|
6
6
|
"license": "MIT",
|
7
7
|
"engines": {
|
8
|
-
"node": "
|
8
|
+
"node": "16.x"
|
9
9
|
},
|
10
10
|
"scripts": {
|
11
|
-
"
|
12
|
-
"
|
11
|
+
"dev": "vite",
|
12
|
+
"build": "tsc && vite build",
|
13
|
+
"preview": "vite preview"
|
13
14
|
},
|
14
15
|
"dependencies": {},
|
15
16
|
"devDependencies": {
|
16
|
-
"
|
17
|
-
"
|
18
|
-
"
|
19
|
-
"eslint": "^4.19.1",
|
20
|
-
"eslint-config-airbnb-base": "^13.0.0",
|
21
|
-
"eslint-plugin-import": "^2.13.0",
|
22
|
-
"keycode-js": "^1.0.0",
|
17
|
+
"@sonicgarden/eslint-plugin": "^0.4.11",
|
18
|
+
"@sonicgarden/prettier-config": "^0.0.1",
|
19
|
+
"eslint": "^8.16.0",
|
23
20
|
"lodash.debounce": "^4.0.8",
|
24
|
-
"
|
25
|
-
"
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
"typescript": "^4.7.2",
|
22
|
+
"vite": "^2.9.9"
|
23
|
+
},
|
24
|
+
"prettier": "@sonicgarden/prettier-config",
|
25
|
+
"volta": {
|
26
|
+
"node": "16.15.0",
|
27
|
+
"yarn": "1.22.18"
|
29
28
|
}
|
30
29
|
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'copy_tuner_client/helper_extension'
|
3
|
+
require 'copy_tuner_client/copyray'
|
4
|
+
|
5
|
+
describe CopyTunerClient::HelperExtension do
|
6
|
+
# rails <= 6.0.x
|
7
|
+
module HashArgumentHelper
|
8
|
+
def translate(key, options = {})
|
9
|
+
"Hello, #{options[:name]}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# rails >= 6.1.x
|
14
|
+
module KeywordArgumentsHelper
|
15
|
+
def translate(key, **options)
|
16
|
+
"Hello, #{options[:name]}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class HashArgumentView
|
21
|
+
include HashArgumentHelper
|
22
|
+
end
|
23
|
+
|
24
|
+
class KeywordArgumentsView
|
25
|
+
include KeywordArgumentsHelper
|
26
|
+
end
|
27
|
+
|
28
|
+
CopyTunerClient::HelperExtension.hook_translation_helper(HashArgumentHelper, middleware_enabled: true)
|
29
|
+
CopyTunerClient::HelperExtension.hook_translation_helper(KeywordArgumentsHelper, middleware_enabled: true)
|
30
|
+
|
31
|
+
it 'works with hash argument method' do
|
32
|
+
view = HashArgumentView.new
|
33
|
+
expect(view.translate('some.key', name: 'World')).to eq '<!--COPYRAY some.key-->Hello, World'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'works with keyword argument method' do
|
37
|
+
view = KeywordArgumentsView.new
|
38
|
+
expect(view.translate('some.key', name: 'World')).to eq '<!--COPYRAY some.key-->Hello, World'
|
39
|
+
end
|
40
|
+
end
|
@@ -39,7 +39,9 @@ describe CopyTunerClient::I18nBackend do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
it "finds available locales from locale files and cache" do
|
42
|
+
# TODO: ruby@2.7サポート終わったらこっちは不要
|
42
43
|
allow(YAML).to receive(:load_file).and_return({ 'es' => { 'key' => 'value' } })
|
44
|
+
allow(YAML).to receive(:unsafe_load_file).and_return({ 'es' => { 'key' => 'value' } })
|
43
45
|
allow(I18n).to receive(:load_path).and_return(["test.yml"])
|
44
46
|
|
45
47
|
cache['en.key'] = ''
|
File without changes
|
data/src/copyray.ts
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
import CopyTunerBar from './copytuner_bar'
|
2
|
+
import Specimen from './specimen'
|
3
|
+
|
4
|
+
const findBlurbs = () => {
|
5
|
+
const filterNone = () => NodeFilter.FILTER_ACCEPT
|
6
|
+
|
7
|
+
// @ts-expect-error TS2554
|
8
|
+
const iterator = document.createNodeIterator(document.body, NodeFilter.SHOW_COMMENT, filterNone, false)
|
9
|
+
|
10
|
+
const comments = []
|
11
|
+
let curNode
|
12
|
+
|
13
|
+
while ((curNode = iterator.nextNode())) {
|
14
|
+
comments.push(curNode)
|
15
|
+
}
|
16
|
+
|
17
|
+
return (
|
18
|
+
comments
|
19
|
+
// @ts-expect-error TS2531
|
20
|
+
.filter((comment) => comment.nodeValue.startsWith('COPYRAY'))
|
21
|
+
.map((comment) => {
|
22
|
+
// @ts-expect-error TS2488
|
23
|
+
const [, key] = comment.nodeValue.match(/^COPYRAY (\S*)$/)
|
24
|
+
const element = comment.parentNode
|
25
|
+
return { key, element }
|
26
|
+
})
|
27
|
+
)
|
28
|
+
}
|
29
|
+
|
30
|
+
export default class Copyray {
|
31
|
+
// @ts-expect-error TS7006
|
32
|
+
constructor(baseUrl, data) {
|
33
|
+
// @ts-expect-error TS2339
|
34
|
+
this.baseUrl = baseUrl
|
35
|
+
// @ts-expect-error TS2339
|
36
|
+
this.data = data
|
37
|
+
// @ts-expect-error TS2339
|
38
|
+
this.isShowing = false
|
39
|
+
// @ts-expect-error TS2339
|
40
|
+
this.specimens = []
|
41
|
+
// @ts-expect-error TS2339
|
42
|
+
this.overlay = this.makeOverlay()
|
43
|
+
// @ts-expect-error TS2339
|
44
|
+
this.toggleButton = this.makeToggleButton()
|
45
|
+
// @ts-expect-error TS2339
|
46
|
+
this.boundOpen = this.open.bind(this)
|
47
|
+
|
48
|
+
// @ts-expect-error TS2339
|
49
|
+
this.copyTunerBar = new CopyTunerBar(document.querySelector('#copy-tuner-bar'), this.data, this.boundOpen)
|
50
|
+
}
|
51
|
+
|
52
|
+
show() {
|
53
|
+
this.reset()
|
54
|
+
|
55
|
+
// @ts-expect-error TS2339
|
56
|
+
document.body.append(this.overlay)
|
57
|
+
this.makeSpecimens()
|
58
|
+
|
59
|
+
// @ts-expect-error TS2339
|
60
|
+
for (const specimen of this.specimens) {
|
61
|
+
specimen.show()
|
62
|
+
}
|
63
|
+
|
64
|
+
// @ts-expect-error TS2339
|
65
|
+
this.copyTunerBar.show()
|
66
|
+
// @ts-expect-error TS2339
|
67
|
+
this.isShowing = true
|
68
|
+
}
|
69
|
+
|
70
|
+
hide() {
|
71
|
+
// @ts-expect-error TS2339
|
72
|
+
this.overlay.remove()
|
73
|
+
this.reset()
|
74
|
+
// @ts-expect-error TS2339
|
75
|
+
this.copyTunerBar.hide()
|
76
|
+
// @ts-expect-error TS2339
|
77
|
+
this.isShowing = false
|
78
|
+
}
|
79
|
+
|
80
|
+
toggle() {
|
81
|
+
// @ts-expect-error TS2339
|
82
|
+
if (this.isShowing) {
|
83
|
+
this.hide()
|
84
|
+
} else {
|
85
|
+
this.show()
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
// @ts-expect-error TS7006
|
90
|
+
open(key) {
|
91
|
+
// @ts-expect-error TS2339
|
92
|
+
window.open(`${this.baseUrl}/blurbs/${key}/edit`)
|
93
|
+
}
|
94
|
+
|
95
|
+
makeSpecimens() {
|
96
|
+
for (const { element, key } of findBlurbs()) {
|
97
|
+
// @ts-expect-error TS2339
|
98
|
+
this.specimens.push(new Specimen(element, key, this.boundOpen))
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
makeToggleButton() {
|
103
|
+
const element = document.createElement('a')
|
104
|
+
|
105
|
+
element.addEventListener('click', () => {
|
106
|
+
this.show()
|
107
|
+
})
|
108
|
+
|
109
|
+
element.classList.add('copyray-toggle-button')
|
110
|
+
element.classList.add('hidden-on-mobile')
|
111
|
+
element.textContent = 'Open CopyTuner'
|
112
|
+
document.body.append(element)
|
113
|
+
|
114
|
+
return element
|
115
|
+
}
|
116
|
+
|
117
|
+
makeOverlay() {
|
118
|
+
const div = document.createElement('div')
|
119
|
+
div.setAttribute('id', 'copyray-overlay')
|
120
|
+
div.addEventListener('click', () => this.hide())
|
121
|
+
return div
|
122
|
+
}
|
123
|
+
|
124
|
+
reset() {
|
125
|
+
// @ts-expect-error TS2339
|
126
|
+
for (const specimen of this.specimens) {
|
127
|
+
specimen.remove()
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
@@ -0,0 +1,115 @@
|
|
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) {
|
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
|
+
this.addHandler()
|
23
|
+
}
|
24
|
+
|
25
|
+
addHandler() {
|
26
|
+
// @ts-expect-error TS2339
|
27
|
+
const openLogButton = this.element.querySelector('.js-copy-tuner-bar-open-log')
|
28
|
+
// @ts-expect-error TS7006
|
29
|
+
openLogButton.addEventListener('click', (event) => {
|
30
|
+
event.preventDefault()
|
31
|
+
this.toggleLogMenu()
|
32
|
+
})
|
33
|
+
|
34
|
+
// @ts-expect-error TS2339
|
35
|
+
this.searchBoxElement.addEventListener('input', debounce(this.onKeyup.bind(this), 250))
|
36
|
+
}
|
37
|
+
|
38
|
+
show() {
|
39
|
+
// @ts-expect-error TS2339
|
40
|
+
this.element.classList.remove(HIDDEN_CLASS)
|
41
|
+
// @ts-expect-error TS2339
|
42
|
+
this.searchBoxElement.focus()
|
43
|
+
}
|
44
|
+
|
45
|
+
hide() {
|
46
|
+
// @ts-expect-error TS2339
|
47
|
+
this.element.classList.add(HIDDEN_CLASS)
|
48
|
+
}
|
49
|
+
|
50
|
+
showLogMenu() {
|
51
|
+
// @ts-expect-error TS2339
|
52
|
+
this.logMenuElement.classList.remove(HIDDEN_CLASS)
|
53
|
+
}
|
54
|
+
|
55
|
+
toggleLogMenu() {
|
56
|
+
// @ts-expect-error TS2339
|
57
|
+
this.logMenuElement.classList.toggle(HIDDEN_CLASS)
|
58
|
+
}
|
59
|
+
|
60
|
+
makeLogMenu() {
|
61
|
+
const div = document.createElement('div')
|
62
|
+
div.setAttribute('id', 'copy-tuner-bar-log-menu')
|
63
|
+
div.classList.add(HIDDEN_CLASS)
|
64
|
+
|
65
|
+
const table = document.createElement('table')
|
66
|
+
const tbody = document.createElement('tbody')
|
67
|
+
tbody.classList.remove('is-not-initialized')
|
68
|
+
|
69
|
+
// @ts-expect-error TS2339
|
70
|
+
for (const key of Object.keys(this.data).sort()) {
|
71
|
+
// @ts-expect-error TS2339
|
72
|
+
const value = this.data[key]
|
73
|
+
|
74
|
+
if (value === '') {
|
75
|
+
continue
|
76
|
+
}
|
77
|
+
|
78
|
+
const td1 = document.createElement('td')
|
79
|
+
td1.textContent = key
|
80
|
+
const td2 = document.createElement('td')
|
81
|
+
td2.textContent = value
|
82
|
+
const tr = document.createElement('tr')
|
83
|
+
tr.classList.add('copy-tuner-bar-log-menu__row')
|
84
|
+
tr.dataset.key = key
|
85
|
+
|
86
|
+
tr.addEventListener('click', ({ currentTarget }) => {
|
87
|
+
// @ts-expect-error TS2339
|
88
|
+
this.callback(currentTarget.dataset.key)
|
89
|
+
})
|
90
|
+
|
91
|
+
tr.append(td1)
|
92
|
+
tr.append(td2)
|
93
|
+
tbody.append(tr)
|
94
|
+
}
|
95
|
+
|
96
|
+
table.append(tbody)
|
97
|
+
div.append(table)
|
98
|
+
|
99
|
+
return div
|
100
|
+
}
|
101
|
+
|
102
|
+
// @ts-expect-error TS7031
|
103
|
+
onKeyup({ target }) {
|
104
|
+
const keyword = target.value.trim()
|
105
|
+
this.showLogMenu()
|
106
|
+
|
107
|
+
// @ts-expect-error TS2339
|
108
|
+
const rows = [...this.logMenuElement.querySelectorAll('tr')]
|
109
|
+
|
110
|
+
for (const row of rows) {
|
111
|
+
const isShow = keyword === '' || [...row.querySelectorAll('td')].some((td) => td.textContent.includes(keyword))
|
112
|
+
row.classList.toggle(HIDDEN_CLASS, !isShow)
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
data/src/main.ts
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
/* eslint-disable no-console */
|
2
|
+
import Copyray from './copyray'
|
3
|
+
import { isMac } from './util'
|
4
|
+
|
5
|
+
declare global {
|
6
|
+
interface Window {
|
7
|
+
CopyTuner: {
|
8
|
+
url: string
|
9
|
+
// TODO: type
|
10
|
+
data: object
|
11
|
+
}
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
import './copyray.css'
|
16
|
+
|
17
|
+
// NOTE: 元々railsから出力されいてたマークアップに合わせてひとまず、、
|
18
|
+
const appendCopyTunerBar = (url: string) => {
|
19
|
+
const bar = document.createElement('div')
|
20
|
+
bar.id = 'copy-tuner-bar'
|
21
|
+
bar.classList.add('copy-tuner-hidden')
|
22
|
+
bar.innerHTML = `
|
23
|
+
<a class="copy-tuner-bar-button" target="_blank" href="${url}">CopyTuner</a>
|
24
|
+
<a href="/copytuner" target="_blank" class="copy-tuner-bar-button">Sync</a>
|
25
|
+
<a href="javascript:void(0)" class="copy-tuner-bar-open-log copy-tuner-bar-button js-copy-tuner-bar-open-log">Translations in this page</a>
|
26
|
+
<input type="text" class="copy-tuner-bar__search js-copy-tuner-bar-search" placeholder="search">
|
27
|
+
`
|
28
|
+
document.body.append(bar)
|
29
|
+
}
|
30
|
+
|
31
|
+
const start = () => {
|
32
|
+
const { url, data } = window.CopyTuner
|
33
|
+
|
34
|
+
appendCopyTunerBar(url)
|
35
|
+
const copyray = new Copyray(url, data)
|
36
|
+
|
37
|
+
document.addEventListener('keydown', (event) => {
|
38
|
+
// @ts-expect-error TS2339
|
39
|
+
if (copyray.isShowing && ['Escape', 'Esc'].includes(event.key)) {
|
40
|
+
copyray.hide()
|
41
|
+
return
|
42
|
+
}
|
43
|
+
|
44
|
+
if (((isMac && event.metaKey) || (!isMac && event.ctrlKey)) && event.shiftKey && event.key === 'k') {
|
45
|
+
copyray.toggle()
|
46
|
+
}
|
47
|
+
})
|
48
|
+
|
49
|
+
if (console) {
|
50
|
+
console.log(`Ready to Copyray. Press ${isMac ? 'cmd+shift+k' : 'ctrl+shift+k'} to scan your UI.`)
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
if (document.readyState === 'complete' || document.readyState !== 'loading') {
|
55
|
+
start()
|
56
|
+
} else {
|
57
|
+
document.addEventListener('DOMContentLoaded', () => start())
|
58
|
+
}
|
data/src/specimen.ts
ADDED
@@ -0,0 +1,84 @@
|
|
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, key, callback) {
|
8
|
+
// @ts-expect-error TS2339
|
9
|
+
this.element = element
|
10
|
+
// @ts-expect-error TS2339
|
11
|
+
this.key = key
|
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
|
+
// @ts-expect-error TS2339
|
23
|
+
this.box.addEventListener('click', () => {
|
24
|
+
// @ts-expect-error TS2339
|
25
|
+
this.callback(this.key)
|
26
|
+
})
|
27
|
+
|
28
|
+
// @ts-expect-error TS2339
|
29
|
+
document.body.append(this.box)
|
30
|
+
}
|
31
|
+
|
32
|
+
remove() {
|
33
|
+
// @ts-expect-error TS2339
|
34
|
+
if (!this.box) {
|
35
|
+
return
|
36
|
+
}
|
37
|
+
// @ts-expect-error TS2339
|
38
|
+
this.box.remove()
|
39
|
+
// @ts-expect-error TS2339
|
40
|
+
this.box = null
|
41
|
+
}
|
42
|
+
|
43
|
+
makeBox() {
|
44
|
+
const box = document.createElement('div')
|
45
|
+
box.classList.add('copyray-specimen')
|
46
|
+
box.classList.add('Specimen')
|
47
|
+
|
48
|
+
// @ts-expect-error TS2339
|
49
|
+
const bounds = computeBoundingBox(this.element)
|
50
|
+
if (bounds === null) return null
|
51
|
+
|
52
|
+
for (const key of Object.keys(bounds)) {
|
53
|
+
// @ts-expect-error TS7053
|
54
|
+
const value = bounds[key]
|
55
|
+
// @ts-expect-error TS7015
|
56
|
+
box.style[key] = `${value}px`
|
57
|
+
}
|
58
|
+
// @ts-expect-error TS2322
|
59
|
+
box.style.zIndex = ZINDEX
|
60
|
+
|
61
|
+
// @ts-expect-error TS2339
|
62
|
+
const { position, top, left } = getComputedStyle(this.element)
|
63
|
+
if (position === 'fixed') {
|
64
|
+
// @ts-expect-error TS2339
|
65
|
+
this.box.style.position = 'fixed'
|
66
|
+
// @ts-expect-error TS2339
|
67
|
+
this.box.style.top = `${top}px`
|
68
|
+
// @ts-expect-error TS2339
|
69
|
+
this.box.style.left = `${left}px`
|
70
|
+
}
|
71
|
+
|
72
|
+
box.append(this.makeLabel())
|
73
|
+
return box
|
74
|
+
}
|
75
|
+
|
76
|
+
makeLabel() {
|
77
|
+
const div = document.createElement('div')
|
78
|
+
div.classList.add('copyray-specimen-handle')
|
79
|
+
div.classList.add('Specimen')
|
80
|
+
// @ts-expect-error TS2339
|
81
|
+
div.textContent = this.key
|
82
|
+
return div
|
83
|
+
}
|
84
|
+
}
|
data/src/util.ts
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
const isMac = navigator.platform.toUpperCase().includes('MAC')
|
2
|
+
|
3
|
+
// @ts-expect-error TS7006
|
4
|
+
const isVisible = (element) => !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length > 0)
|
5
|
+
|
6
|
+
// @ts-expect-error TS7006
|
7
|
+
const getOffset = (elment) => {
|
8
|
+
const box = elment.getBoundingClientRect()
|
9
|
+
|
10
|
+
return {
|
11
|
+
top: box.top + (window.pageYOffset - document.documentElement.clientTop),
|
12
|
+
left: box.left + (window.pageXOffset - document.documentElement.clientLeft),
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
// @ts-expect-error TS7006
|
17
|
+
const computeBoundingBox = (element) => {
|
18
|
+
if (!isVisible(element)) {
|
19
|
+
return null
|
20
|
+
}
|
21
|
+
|
22
|
+
const boxFrame = getOffset(element)
|
23
|
+
// @ts-expect-error TS2339
|
24
|
+
boxFrame.right = boxFrame.left + element.offsetWidth
|
25
|
+
// @ts-expect-error TS2339
|
26
|
+
boxFrame.bottom = boxFrame.top + element.offsetHeight
|
27
|
+
|
28
|
+
return {
|
29
|
+
left: boxFrame.left,
|
30
|
+
top: boxFrame.top,
|
31
|
+
// @ts-expect-error TS2339
|
32
|
+
width: boxFrame.right - boxFrame.left,
|
33
|
+
// @ts-expect-error TS2339
|
34
|
+
height: boxFrame.bottom - boxFrame.top,
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
export { isMac, isVisible, getOffset, computeBoundingBox }
|
data/src/vite-env.d.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/// <reference types="vite/client" />
|
data/tsconfig.json
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"target": "ESNext",
|
4
|
+
"useDefineForClassFields": true,
|
5
|
+
"module": "ESNext",
|
6
|
+
"lib": [
|
7
|
+
"ESNext",
|
8
|
+
"DOM"
|
9
|
+
],
|
10
|
+
"moduleResolution": "Node",
|
11
|
+
"strict": true,
|
12
|
+
"sourceMap": true,
|
13
|
+
"resolveJsonModule": true,
|
14
|
+
"isolatedModules": true,
|
15
|
+
"esModuleInterop": true,
|
16
|
+
"noEmit": true,
|
17
|
+
"noUnusedLocals": true,
|
18
|
+
"noUnusedParameters": true,
|
19
|
+
"noImplicitReturns": true,
|
20
|
+
"skipLibCheck": true,
|
21
|
+
},
|
22
|
+
"include": [
|
23
|
+
"client",
|
24
|
+
"src",
|
25
|
+
]
|
26
|
+
}
|
data/vite.config.ts
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
import { defineConfig } from 'vite'
|
2
|
+
|
3
|
+
// https://vitejs.dev/config/
|
4
|
+
export default defineConfig({
|
5
|
+
build: {
|
6
|
+
outDir: './app/assets',
|
7
|
+
lib: {
|
8
|
+
entry: 'src/main.ts',
|
9
|
+
formats: ['es'],
|
10
|
+
},
|
11
|
+
rollupOptions: {
|
12
|
+
output: {
|
13
|
+
entryFileNames: `javascripts/[name].js`,
|
14
|
+
assetFileNames: `stylesheets/[name].[ext]`,
|
15
|
+
}
|
16
|
+
}
|
17
|
+
},
|
18
|
+
})
|