Skip to content

Commit a7b6d77

Browse files
committed
chore: wip
1 parent 1a7616f commit a7b6d77

File tree

2 files changed

+110
-29
lines changed

2 files changed

+110
-29
lines changed

storage/framework/defaults/components/Dashboard/Sidebar.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ const sectionContent: Record<string, SectionContent> = {
276276
{{ item.letter }}
277277
</span>
278278
</template>
279-
<span class="truncate">{{ item.text }}</span>
279+
<span class="truncate" :class="{ 'ml-[4px]': item.icon }">{{ item.text }}</span>
280280
<div
281281
v-if="item.children"
282282
class="i-heroicons-chevron-right h-4 w-4 text-gray-300 transition-transform duration-150 ease-in-out dark:text-gray-200 group-hover:text-gray-700 ml-auto"

storage/framework/defaults/views/dashboard/models/index.vue

Lines changed: 109 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -226,28 +226,98 @@ const erdLinks: ERDLink[] = [
226226
const diagramContainer = ref<HTMLElement | null>(null)
227227
let simulation: d3.Simulation<ModelNode, undefined>
228228
229-
// Add download function
230-
const downloadDiagram = () => {
231-
if (!diagramContainer.value) return
229+
// Add format state
230+
const downloadFormat = ref<'svg' | 'png'>('svg')
231+
const isDownloading = ref(false)
232+
233+
// Update download function to support both formats
234+
const downloadDiagram = async () => {
235+
if (!diagramContainer.value) {
236+
console.error('No diagram container found')
237+
return
238+
}
232239
233240
const svg = diagramContainer.value.querySelector('svg')
234-
if (!svg) return
235-
236-
// Get SVG content
237-
const svgData = svg.outerHTML
238-
const blob = new Blob([svgData], { type: 'image/svg+xml' })
239-
const url = URL.createObjectURL(blob)
240-
241-
// Create download link
242-
const link = document.createElement('a')
243-
link.href = url
244-
link.download = 'model-relationships.svg'
245-
document.body.appendChild(link)
246-
link.click()
247-
248-
// Clean up
249-
document.body.removeChild(link)
250-
URL.revokeObjectURL(url)
241+
if (!svg) {
242+
console.error('No SVG element found')
243+
return
244+
}
245+
246+
isDownloading.value = true
247+
248+
try {
249+
if (downloadFormat.value === 'svg') {
250+
// SVG download
251+
const svgData = new XMLSerializer().serializeToString(svg)
252+
const blob = new Blob([svgData], { type: 'image/svg+xml' })
253+
const url = URL.createObjectURL(blob)
254+
255+
const link = document.createElement('a')
256+
link.href = url
257+
link.download = 'model-relationships.svg'
258+
document.body.appendChild(link)
259+
link.click()
260+
document.body.removeChild(link)
261+
URL.revokeObjectURL(url)
262+
} else {
263+
// PNG download
264+
const svgData = new XMLSerializer().serializeToString(svg)
265+
const blob = new Blob([svgData], { type: 'image/svg+xml' })
266+
const url = URL.createObjectURL(blob)
267+
268+
const img = new Image()
269+
const canvas = document.createElement('canvas')
270+
const ctx = canvas.getContext('2d')
271+
272+
if (!ctx) {
273+
throw new Error('Could not get canvas context')
274+
}
275+
276+
// Set canvas size to match SVG
277+
const svgSize = svg.getBoundingClientRect()
278+
const scale = 2 // For better resolution
279+
canvas.width = svgSize.width * scale
280+
canvas.height = svgSize.height * scale
281+
282+
// Set white background
283+
ctx.fillStyle = '#ffffff'
284+
ctx.fillRect(0, 0, canvas.width, canvas.height)
285+
286+
// Scale for better resolution
287+
ctx.scale(scale, scale)
288+
289+
return new Promise((resolve, reject) => {
290+
img.onload = () => {
291+
try {
292+
ctx.drawImage(img, 0, 0)
293+
const pngUrl = canvas.toDataURL('image/png')
294+
295+
const link = document.createElement('a')
296+
link.href = pngUrl
297+
link.download = 'model-relationships.png'
298+
document.body.appendChild(link)
299+
link.click()
300+
document.body.removeChild(link)
301+
302+
URL.revokeObjectURL(url)
303+
resolve(true)
304+
} catch (error) {
305+
reject(error)
306+
}
307+
}
308+
309+
img.onerror = () => {
310+
reject(new Error('Failed to load SVG into image'))
311+
}
312+
313+
img.src = url
314+
})
315+
}
316+
} catch (error) {
317+
console.error('Error downloading diagram:', error)
318+
} finally {
319+
isDownloading.value = false
320+
}
251321
}
252322
253323
// Create model diagram
@@ -469,18 +539,29 @@ onUnmounted(() => {
469539
<div class="p-6">
470540
<div class="flex items-center justify-between mb-4">
471541
<div class="flex items-center gap-2">
472-
<h4 class="text-base font-medium text-gray-900 dark:text-gray-100">Model Relationships</h4>
542+
<h4 class="text-base font-medium text-gray-900 dark:text-gray-100">Entity Relationship Diagram</h4>
473543
<span class="text-sm text-gray-500 dark:text-gray-400">
474544
(Drag nodes to rearrange)
475545
</span>
476546
</div>
477-
<button
478-
@click="downloadDiagram"
479-
class="inline-flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-blue-gray-600 rounded-md shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-gray-600 hover:bg-gray-50 dark:hover:bg-blue-gray-500 transition-colors duration-200"
480-
>
481-
<div class="i-heroicons-arrow-down-tray w-5 h-5" />
482-
Download SVG
483-
</button>
547+
<div class="inline-flex rounded-md shadow-sm">
548+
<select
549+
v-model="downloadFormat"
550+
class="h-9 text-sm border-0 rounded-l-md bg-white dark:bg-blue-gray-600 py-1.5 pl-3 pr-7 text-gray-700 dark:text-gray-200 ring-1 ring-inset ring-gray-300 dark:ring-gray-600 hover:bg-gray-50 dark:hover:bg-blue-gray-500 focus:ring-2 focus:ring-blue-600 transition-colors duration-200"
551+
>
552+
<option value="svg">SVG</option>
553+
<option value="png">PNG</option>
554+
</select>
555+
<button
556+
@click="downloadDiagram"
557+
:disabled="isDownloading"
558+
class="relative inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-r-md shadow-sm hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200"
559+
>
560+
<div v-if="isDownloading" class="i-heroicons-arrow-path w-4 h-4 animate-spin" />
561+
<div v-else class="i-heroicons-arrow-down-tray w-4 h-4" />
562+
Download
563+
</button>
564+
</div>
484565
</div>
485566
<div ref="diagramContainer" class="w-full h-[800px] bg-gray-50 dark:bg-blue-gray-800 rounded-lg"></div>
486567
</div>

0 commit comments

Comments
 (0)