rails-mermaid_erd 0.5.0 → 0.6.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 +11 -1
- data/lib/rails-mermaid_erd/version.rb +1 -1
- data/lib/templates/index.html.erb +204 -3
- metadata +3 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f3cfe23f8fa1343b2bd8a3ac5d47c1967613ce7a832d65de858b363402db0b1
|
4
|
+
data.tar.gz: 146d83e00452b8c56cbf8c4c6e0aebd62f99b3224e6b7e3062b4889b55bf0723
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c68987537096806829a9709f477dd8cc8a0108291387ff670796d2c41c4a900fe0f1a55902381b12d582d4e66d77f2b0421d929dfc72060a10d5b9ed020c4a6
|
7
|
+
data.tar.gz: 04cbecd36399c810f0846e1d4c4275922acfeb1ec2bcf426440f08902db6b4b051368f57ec57a0f8259108d9f727b77d0760ee0f817aee8122e4f3952dcfcc58
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ The editor is a single HTML file, so the entire editor can be shared.
|
|
21
21
|
Add this line to your application's Gemfile:
|
22
22
|
|
23
23
|
```ruby
|
24
|
-
gem "rails-mermaid_erd", group: :development
|
24
|
+
gem "rails-mermaid_erd", group: :development, require: false
|
25
25
|
```
|
26
26
|
|
27
27
|
And then execute:
|
@@ -30,6 +30,16 @@ And then execute:
|
|
30
30
|
$ bundle install
|
31
31
|
```
|
32
32
|
|
33
|
+
Add this line to your application's Rakefile:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
begin
|
37
|
+
require "rails-mermaid_erd"
|
38
|
+
rescue LoadError
|
39
|
+
# Do nothing.
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
33
43
|
## Usage
|
34
44
|
|
35
45
|
Run rake task `mermaid_erd` will generate `<app_root>/mermaid_erd/index.html`.
|
@@ -230,7 +230,20 @@
|
|
230
230
|
</div>
|
231
231
|
<div v-show="tab === 'erd'" class="px-4 w-full min-h-[calc(100vh-56px-32px-56px)] relative overflow-hidden">
|
232
232
|
<div class="absolute inset-0" :style="zoomStyle" ref="zoomArea">
|
233
|
-
<div id="preview"></div>
|
233
|
+
<div id="preview" :class="{ 'cursor-grab': isSpacePressed, 'cursor-grabbing': isDragging }"></div>
|
234
|
+
</div>
|
235
|
+
|
236
|
+
<div class="absolute bottom-0 left-1/2 -translate-x-1/2 p-4">
|
237
|
+
<div class="bg-gray-800 text-white text-[10px] px-3 py-1.5 rounded inline-flex items-center space-x-6">
|
238
|
+
<div class="inline-flex items-center">
|
239
|
+
<span class="font-medium">{{i18n[language]["controls"]["movement"]}}:</span>
|
240
|
+
<span class="ml-1 text-white/60">{{i18n[language]["controls"]["space_drag"]}} / {{i18n[language]["controls"]["middle_drag"]}}</span>
|
241
|
+
</div>
|
242
|
+
<div class="inline-flex items-center">
|
243
|
+
<span class="font-medium">{{i18n[language]["controls"]["zoom"]}}:</span>
|
244
|
+
<span class="ml-1 text-white/60">{{i18n[language]["controls"]["mouse_wheel"]}} / {{i18n[language]["controls"]["pinch"]}}</span>
|
245
|
+
</div>
|
246
|
+
</div>
|
234
247
|
</div>
|
235
248
|
|
236
249
|
<div class="absolute bottom-0 right-0 p-4 space-x-4 flex">
|
@@ -247,7 +260,6 @@
|
|
247
260
|
<button class="text-xs py-1 px-2 rounded hover:bg-white focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-900 bg-gray-400 text-gray-900" @click="moveRight">→</button>
|
248
261
|
</div>
|
249
262
|
</div>
|
250
|
-
|
251
263
|
</div>
|
252
264
|
<textarea v-show="tab === 'code'" class="px-4 bg-gray-900 text-gray-300 font-mono w-full text-xs min-h-[calc(100vh-56px-32px-56px)] border-0 focus:ring-0" readonly v-model="mermaidErd"></textarea>
|
253
265
|
</div>
|
@@ -302,6 +314,14 @@
|
|
302
314
|
erd: 'ERD',
|
303
315
|
code: 'Code',
|
304
316
|
},
|
317
|
+
controls: {
|
318
|
+
movement: 'Movement',
|
319
|
+
zoom: 'Zoom',
|
320
|
+
space_drag: 'Space + Mouse Drag',
|
321
|
+
middle_drag: 'Middle Click + Drag',
|
322
|
+
mouse_wheel: 'Mouse Wheel',
|
323
|
+
pinch: 'Pinch In/Out',
|
324
|
+
}
|
305
325
|
},
|
306
326
|
ja: {
|
307
327
|
actions: {
|
@@ -336,6 +356,14 @@
|
|
336
356
|
erd: 'ER図',
|
337
357
|
code: 'コード',
|
338
358
|
},
|
359
|
+
controls: {
|
360
|
+
movement: '移動方法',
|
361
|
+
zoom: '拡大/縮小',
|
362
|
+
space_drag: 'スペースキー + マウスドラッグ',
|
363
|
+
middle_drag: '中クリック + ドラッグ',
|
364
|
+
mouse_wheel: 'マウスホイール',
|
365
|
+
pinch: 'ピンチイン/アウト',
|
366
|
+
}
|
339
367
|
}
|
340
368
|
}
|
341
369
|
</script>
|
@@ -362,6 +390,155 @@
|
|
362
390
|
const posX = Vue.ref(0)
|
363
391
|
const posY = Vue.ref(0)
|
364
392
|
const zoomArea = Vue.ref(null)
|
393
|
+
// Manage space key press state
|
394
|
+
const isSpacePressed = Vue.ref(false)
|
395
|
+
// Manage dragging state
|
396
|
+
const isDragging = Vue.ref(false)
|
397
|
+
let startX = 0
|
398
|
+
let startY = 0
|
399
|
+
// Record distance between two touch points
|
400
|
+
let lastTouchDistance = 0
|
401
|
+
// Record mouse position
|
402
|
+
let lastMouseX = 0
|
403
|
+
let lastMouseY = 0
|
404
|
+
|
405
|
+
// Calculate distance between two touch points
|
406
|
+
const getDistance = (touches) => {
|
407
|
+
return Math.hypot(
|
408
|
+
touches[0].clientX - touches[1].clientX,
|
409
|
+
touches[0].clientY - touches[1].clientY
|
410
|
+
)
|
411
|
+
}
|
412
|
+
|
413
|
+
// Calculate center point of two touch positions
|
414
|
+
const getTouchCenter = (touches) => {
|
415
|
+
return {
|
416
|
+
x: (touches[0].clientX + touches[1].clientX) / 2,
|
417
|
+
y: (touches[0].clientY + touches[1].clientY) / 2
|
418
|
+
}
|
419
|
+
}
|
420
|
+
|
421
|
+
// Handle touch start
|
422
|
+
const handleTouchStart = (e) => {
|
423
|
+
if (e.touches.length === 2) {
|
424
|
+
e.preventDefault()
|
425
|
+
lastTouchDistance = getDistance(e.touches)
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
// Handle touch move (pinch in/out for zoom)
|
430
|
+
const handleTouchMove = (e) => {
|
431
|
+
if (e.touches.length === 2) {
|
432
|
+
e.preventDefault()
|
433
|
+
const preview = document.getElementById('preview')
|
434
|
+
if (!preview.contains(e.target)) {
|
435
|
+
return
|
436
|
+
}
|
437
|
+
|
438
|
+
const newDistance = getDistance(e.touches)
|
439
|
+
const delta = (newDistance - lastTouchDistance) * 0.01
|
440
|
+
lastTouchDistance = newDistance
|
441
|
+
|
442
|
+
const center = getTouchCenter(e.touches)
|
443
|
+
const rect = preview.getBoundingClientRect()
|
444
|
+
const touchX = center.x - rect.left
|
445
|
+
const touchY = center.y - rect.top
|
446
|
+
|
447
|
+
const x = touchX / scale.value - posX.value
|
448
|
+
const y = touchY / scale.value - posY.value
|
449
|
+
|
450
|
+
const newScale = Math.min(Math.max(scale.value + delta, 0.5), 3)
|
451
|
+
if (newScale === scale.value) return
|
452
|
+
|
453
|
+
posX.value = touchX / newScale - x
|
454
|
+
posY.value = touchY / newScale - y
|
455
|
+
scale.value = newScale
|
456
|
+
}
|
457
|
+
}
|
458
|
+
|
459
|
+
// Handle touch end
|
460
|
+
const handleTouchEnd = (e) => {
|
461
|
+
if (e.touches.length < 2) {
|
462
|
+
lastTouchDistance = 0
|
463
|
+
}
|
464
|
+
}
|
465
|
+
|
466
|
+
// Handle key down (space key for drag mode toggle)
|
467
|
+
const handleKeyDown = (e) => {
|
468
|
+
if (e.code === 'Space' && !isSpacePressed.value) {
|
469
|
+
if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
|
470
|
+
return
|
471
|
+
}
|
472
|
+
isSpacePressed.value = true
|
473
|
+
e.preventDefault()
|
474
|
+
}
|
475
|
+
}
|
476
|
+
|
477
|
+
// Handle key up
|
478
|
+
const handleKeyUp = (e) => {
|
479
|
+
if (e.code === 'Space') {
|
480
|
+
isSpacePressed.value = false
|
481
|
+
isDragging.value = false
|
482
|
+
}
|
483
|
+
}
|
484
|
+
|
485
|
+
// Handle mouse down (start dragging)
|
486
|
+
const handleMouseDown = (e) => {
|
487
|
+
if (isSpacePressed.value || e.button === 1) {
|
488
|
+
isDragging.value = true
|
489
|
+
lastMouseX = e.clientX
|
490
|
+
lastMouseY = e.clientY
|
491
|
+
e.preventDefault()
|
492
|
+
}
|
493
|
+
}
|
494
|
+
|
495
|
+
// Handle mouse move (movement while dragging)
|
496
|
+
const handleMouseMove = (e) => {
|
497
|
+
if (isDragging.value) {
|
498
|
+
const dx = (e.clientX - lastMouseX) / scale.value
|
499
|
+
const dy = (e.clientY - lastMouseY) / scale.value
|
500
|
+
posX.value += dx
|
501
|
+
posY.value += dy
|
502
|
+
lastMouseX = e.clientX
|
503
|
+
lastMouseY = e.clientY
|
504
|
+
e.preventDefault()
|
505
|
+
}
|
506
|
+
}
|
507
|
+
|
508
|
+
// Handle mouse up (end dragging)
|
509
|
+
const handleMouseUp = (e) => {
|
510
|
+
if (e.button === 1) {
|
511
|
+
e.preventDefault()
|
512
|
+
}
|
513
|
+
isDragging.value = false
|
514
|
+
}
|
515
|
+
|
516
|
+
// Handle mouse wheel (zoom)
|
517
|
+
const handleWheel = (e) => {
|
518
|
+
const preview = document.getElementById('preview')
|
519
|
+
if (!preview.contains(e.target)) {
|
520
|
+
return
|
521
|
+
}
|
522
|
+
|
523
|
+
e.preventDefault()
|
524
|
+
|
525
|
+
const rect = preview.getBoundingClientRect()
|
526
|
+
const mouseX = e.clientX - rect.left
|
527
|
+
const mouseY = e.clientY - rect.top
|
528
|
+
|
529
|
+
// Calculate relative coordinates based on mouse position
|
530
|
+
const x = mouseX / scale.value - posX.value
|
531
|
+
const y = mouseY / scale.value - posY.value
|
532
|
+
|
533
|
+
// Change scale
|
534
|
+
const delta = e.deltaY < 0 ? 0.1 : -0.1
|
535
|
+
const newScale = Math.min(Math.max(scale.value + delta, 0.5), 3)
|
536
|
+
|
537
|
+
// Calculate new position with new scale
|
538
|
+
posX.value = mouseX / newScale - x
|
539
|
+
posY.value = mouseY / newScale - y
|
540
|
+
scale.value = newScale
|
541
|
+
}
|
365
542
|
|
366
543
|
const zoomStyle = Vue.computed(() => {
|
367
544
|
return {
|
@@ -613,6 +790,28 @@
|
|
613
790
|
setLanguage(window.navigator.language)
|
614
791
|
restoreFromHash()
|
615
792
|
reRender()
|
793
|
+
|
794
|
+
window.addEventListener('keydown', handleKeyDown)
|
795
|
+
window.addEventListener('keyup', handleKeyUp)
|
796
|
+
window.addEventListener('mousedown', handleMouseDown)
|
797
|
+
window.addEventListener('mousemove', handleMouseMove)
|
798
|
+
window.addEventListener('mouseup', handleMouseUp)
|
799
|
+
window.addEventListener('wheel', handleWheel, { passive: false })
|
800
|
+
window.addEventListener('touchstart', handleTouchStart, { passive: false })
|
801
|
+
window.addEventListener('touchmove', handleTouchMove, { passive: false })
|
802
|
+
window.addEventListener('touchend', handleTouchEnd)
|
803
|
+
})
|
804
|
+
|
805
|
+
Vue.onUnmounted(() => {
|
806
|
+
window.removeEventListener('keydown', handleKeyDown)
|
807
|
+
window.removeEventListener('keyup', handleKeyUp)
|
808
|
+
window.removeEventListener('mousedown', handleMouseDown)
|
809
|
+
window.removeEventListener('mousemove', handleMouseMove)
|
810
|
+
window.removeEventListener('mouseup', handleMouseUp)
|
811
|
+
window.removeEventListener('wheel', handleWheel)
|
812
|
+
window.removeEventListener('touchstart', handleTouchStart)
|
813
|
+
window.removeEventListener('touchmove', handleTouchMove)
|
814
|
+
window.removeEventListener('touchend', handleTouchEnd)
|
616
815
|
})
|
617
816
|
|
618
817
|
window.addEventListener('hashchange', () => {
|
@@ -656,7 +855,9 @@
|
|
656
855
|
moveUp,
|
657
856
|
moveDown,
|
658
857
|
moveLeft,
|
659
|
-
moveRight
|
858
|
+
moveRight,
|
859
|
+
isSpacePressed,
|
860
|
+
isDragging
|
660
861
|
}
|
661
862
|
}
|
662
863
|
}
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-mermaid_erd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 肥溜め
|
8
8
|
- "\U0001F4A9"
|
9
|
-
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2024-
|
11
|
+
date: 2024-12-28 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rails
|
@@ -95,7 +94,6 @@ dependencies:
|
|
95
94
|
- - ">="
|
96
95
|
- !ruby/object:Gem::Version
|
97
96
|
version: '0'
|
98
|
-
description:
|
99
97
|
email: []
|
100
98
|
executables: []
|
101
99
|
extensions: []
|
@@ -116,7 +114,6 @@ licenses:
|
|
116
114
|
metadata:
|
117
115
|
homepage_uri: https://github.com/koedame/rails-mermaid_erd
|
118
116
|
source_code_uri: https://github.com/koedame/rails-mermaid_erd
|
119
|
-
post_install_message:
|
120
117
|
rdoc_options: []
|
121
118
|
require_paths:
|
122
119
|
- lib
|
@@ -131,8 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
128
|
- !ruby/object:Gem::Version
|
132
129
|
version: '0'
|
133
130
|
requirements: []
|
134
|
-
rubygems_version: 3.
|
135
|
-
signing_key:
|
131
|
+
rubygems_version: 3.6.2
|
136
132
|
specification_version: 4
|
137
133
|
summary: Generate Mermaid ERD for Ruby on Rails
|
138
134
|
test_files: []
|