mirror of
https://github.com/duhanbalci/dreport.git
synced 2026-07-02 02:49:16 +00:00
bug fixes & improvements & missing features & font loader
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useTemplateStore } from '../../stores/template'
|
||||
import { useEditorStore } from '../../stores/editor'
|
||||
import { useSchemaStore } from '../../stores/schema'
|
||||
import type { ImageElement, TemplateElement } from '../../core/types'
|
||||
import '../../styles/properties.css'
|
||||
|
||||
const props = defineProps<{ element: ImageElement }>()
|
||||
const templateStore = useTemplateStore()
|
||||
const editorStore = useEditorStore()
|
||||
const schemaStore = useSchemaStore()
|
||||
|
||||
/** Statik mi dinamik mi? */
|
||||
const isDynamic = computed(() => !!props.element.binding)
|
||||
|
||||
function update(updates: Partial<TemplateElement>) {
|
||||
const id = editorStore.selectedElementId
|
||||
@@ -24,30 +30,86 @@ function onImageFileSelect(e: Event) {
|
||||
if (!file) return
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => {
|
||||
update({ src: reader.result as string } as Partial<TemplateElement>)
|
||||
update({ src: reader.result as string, binding: undefined } as Partial<TemplateElement>)
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
|
||||
function setMode(mode: 'static' | 'dynamic') {
|
||||
if (mode === 'static') {
|
||||
update({ binding: undefined } as Partial<TemplateElement>)
|
||||
} else {
|
||||
// Dinamik moda geç — ilk uygun alanı seç veya boş bırak
|
||||
const imageFields = schemaStore.scalarFields.filter(f => f.format === 'image' || f.type === 'string')
|
||||
const path = imageFields.length > 0 ? imageFields[0].path : ''
|
||||
update({ src: undefined, binding: { type: 'scalar', path } } as Partial<TemplateElement>)
|
||||
}
|
||||
}
|
||||
|
||||
function setBindingPath(path: string) {
|
||||
update({ binding: { type: 'scalar', path } } as Partial<TemplateElement>)
|
||||
}
|
||||
|
||||
/** Schema'dan görsel olabilecek alanlar (format: image veya string) */
|
||||
const imageScalarFields = computed(() => {
|
||||
return schemaStore.scalarFields.filter(f => f.format === 'image' || f.type === 'string')
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Gorsel</div>
|
||||
<div class="prop-row" data-tip="Gorsel dosyasi secin (PNG, JPG, SVG)">
|
||||
<label class="prop-label">Kaynak</label>
|
||||
<label class="prop-file-btn">
|
||||
Dosya Sec
|
||||
<input type="file" accept="image/*" style="display: none" @change="onImageFileSelect" />
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="element.src" class="prop-row" data-tip="Yuklenen gorsel onizlemesi">
|
||||
<label class="prop-label">Onizleme</label>
|
||||
<img :src="element.src" class="prop-image-preview" />
|
||||
</div>
|
||||
<div v-if="element.src" class="prop-row" data-tip="Gorseli kaldirmak icin tiklayin">
|
||||
<label class="prop-label"></label>
|
||||
<button class="prop-clear" @click="update({ src: undefined } as any)">Gorseli kaldir</button>
|
||||
|
||||
<!-- Statik / Dinamik toggle -->
|
||||
<div class="prop-row" data-tip="Gorsel kaynagi: dosya veya veri alanından">
|
||||
<label class="prop-label">Mod</label>
|
||||
<div class="prop-toggle-group">
|
||||
<button class="prop-toggle-btn" :class="{ 'prop-toggle-btn--active': !isDynamic }" @click="setMode('static')">Statik</button>
|
||||
<button class="prop-toggle-btn" :class="{ 'prop-toggle-btn--active': isDynamic }" @click="setMode('dynamic')">Dinamik</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statik: dosya seçimi -->
|
||||
<template v-if="!isDynamic">
|
||||
<div class="prop-row" data-tip="Gorsel dosyasi secin (PNG, JPG, SVG)">
|
||||
<label class="prop-label">Kaynak</label>
|
||||
<label class="prop-file-btn">
|
||||
Dosya Sec
|
||||
<input type="file" accept="image/*" style="display: none" @change="onImageFileSelect" />
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="element.src" class="prop-row" data-tip="Yuklenen gorsel onizlemesi">
|
||||
<label class="prop-label">Onizleme</label>
|
||||
<img :src="element.src" class="prop-image-preview" />
|
||||
</div>
|
||||
<div v-if="element.src" class="prop-row" data-tip="Gorseli kaldirmak icin tiklayin">
|
||||
<label class="prop-label"></label>
|
||||
<button class="prop-clear" @click="update({ src: undefined } as any)">Gorseli kaldir</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Dinamik: schema alan seçimi -->
|
||||
<template v-else>
|
||||
<div class="prop-row" data-tip="Gorsel URL'sinin gelecegi veri alani">
|
||||
<label class="prop-label">Veri Alani</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.binding?.path ?? ''"
|
||||
@change="(e) => setBindingPath((e.target as HTMLSelectElement).value)">
|
||||
<option value="" disabled>Secin...</option>
|
||||
<option
|
||||
v-for="field in imageScalarFields"
|
||||
:key="field.path"
|
||||
:value="field.path"
|
||||
>{{ field.title }} ({{ field.path }})</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="element.binding?.path" class="prop-row">
|
||||
<label class="prop-label">Path</label>
|
||||
<span class="prop-info">{{ element.binding.path }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Sığdırma modu (ortak) -->
|
||||
<div class="prop-row" data-tip="Gorselin alana sigdirma modu">
|
||||
<label class="prop-label">Sigdirma</label>
|
||||
<select class="prop-input prop-select"
|
||||
@@ -60,3 +122,42 @@ function onImageFileSelect(e: Event) {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.prop-toggle-group {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.prop-toggle-btn {
|
||||
flex: 1;
|
||||
padding: 3px 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
background: white;
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
transition: background 0.1s, color 0.1s;
|
||||
}
|
||||
|
||||
.prop-toggle-btn:first-child {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.prop-toggle-btn:last-child {
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.prop-toggle-btn--active {
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
.prop-info {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user