fixes
Some checks failed
CI / rust (push) Failing after 36s
CI / frontend (push) Failing after 1m53s
CI / wasm (push) Successful in 1m46s
CI / publish-crates (push) Has been skipped
CI / publish-npm (push) Has been skipped

This commit is contained in:
2026-04-09 02:16:27 +03:00
parent 58a59f2609
commit 92583141c9
24 changed files with 586 additions and 40 deletions

View File

@@ -32,6 +32,7 @@ import RichTextProperties from '../properties/RichTextProperties.vue'
import ContainerProperties from '../properties/ContainerProperties.vue'
import RepeatingTableProperties from '../properties/RepeatingTableProperties.vue'
import ChartProperties from '../properties/ChartProperties.vue'
import PropCondition from '../properties/shared/PropCondition.vue'
import '../../styles/properties.css'
const templateStore = useTemplateStore()
@@ -233,6 +234,13 @@ function deleteSelected() {
</div>
</div>
<!-- Condition -->
<PropCondition
v-if="selectedElement.id !== 'root'"
:condition="selectedElement.condition"
@update:condition="(v) => templateStore.updateElement(selectedElement!.id, { condition: v } as any)"
/>
<!-- Delete -->
<div v-if="selectedElement.id !== 'root'" class="prop-section">
<button class="prop-delete-btn" @click="deleteElement">Sil</button>

View File

@@ -3,6 +3,7 @@ import { useEditorStore } from '../../stores/editor'
import { useSchemaStore } from '../../stores/schema'
import type {
TemplateElement,
TextElement,
RepeatingTableElement,
TableColumn,
ImageElement,
@@ -46,6 +47,18 @@ const tools: ToolItem[] = [
content: 'Yeni metin',
}),
},
{
label: 'Veri Metni',
icon: 'D',
create: (): TextElement => ({
id: nextId('dtxt'),
type: 'text',
position: { type: 'flow' },
size: { width: sz.auto(), height: sz.auto() },
style: { fontSize: 11, color: '#000000' },
binding: { type: 'scalar', path: '' },
}),
},
{
label: 'Zengin Metin',
icon: 'R',

View File

@@ -42,10 +42,12 @@ const formatOptions = [
<PropTextStyleGroup
:font-size="style().fontSize ?? 11"
:font-weight="style().fontWeight ?? 'normal'"
:font-family="style().fontFamily"
:color="style().color ?? '#000000'"
:align="style().align ?? 'left'"
@update:font-size="(v) => updateStyle('fontSize', v)"
@update:font-weight="(v) => updateStyle('fontWeight', v)"
@update:font-family="(v) => updateStyle('fontFamily', v)"
@update:color="(v) => updateStyle('color', v)"
@update:align="(v) => updateStyle('align', v)"
/>

View File

@@ -247,6 +247,19 @@ function removeColor(index: number) {
:model-value="element.axis?.gridColor ?? '#E5E7EB'"
@update:model-value="(v) => updateNested('axis', 'gridColor', v, {})"
/>
<template v-if="element.chartType === 'line'">
<PropCheckbox
label="Dikey Izgara"
:model-value="element.axis?.showVerticalGrid ?? true"
@update:model-value="(v) => updateNested('axis', 'showVerticalGrid', v, {})"
/>
<PropColorInput
v-if="element.axis?.showVerticalGrid !== false"
label="Dikey Izgara Renk"
:model-value="element.axis?.verticalGridColor ?? '#E5E7EB'"
@update:model-value="(v) => updateNested('axis', 'verticalGridColor', v, {})"
/>
</template>
</PropSection>
<!-- Stil -->
@@ -292,6 +305,12 @@ function removeColor(index: number) {
:min="0.1"
@update:model-value="(v) => updateStyle('lineWidth', v)"
/>
<PropSelect
label="Egri Tipi"
:model-value="element.style.curveType ?? 'linear'"
:options="[{ value: 'linear', label: 'Duz' }, { value: 'smooth', label: 'Yumusak' }]"
@update:model-value="(v) => updateStyle('curveType', v)"
/>
<PropCheckbox
label="Noktalar"
:model-value="element.style.showPoints ?? true"

View File

@@ -1,18 +1,41 @@
<script setup lang="ts">
import { computed } from 'vue'
import { usePropertyUpdate } from '../../composables/usePropertyUpdate'
import { useSchemaStore } from '../../stores/schema'
import PropSection from './shared/PropSection.vue'
import PropNumberInput from './shared/PropNumberInput.vue'
import PropColorInput from './shared/PropColorInput.vue'
import PropCheckbox from './shared/PropCheckbox.vue'
import PropFieldSelect from './shared/PropFieldSelect.vue'
import type { CheckboxElement } from '../../core/types'
import '../../styles/properties.css'
const props = defineProps<{ element: CheckboxElement }>()
const { update, updateStyle } = usePropertyUpdate(() => props.element)
const schemaStore = useSchemaStore()
const booleanFields = computed(() =>
schemaStore.scalarFields.filter((f) => f.type === 'boolean' || f.type === 'string'),
)
</script>
<template>
<PropSection title="Onay Kutusu">
<PropFieldSelect
label="Veri Alani"
:model-value="element.binding?.path ?? ''"
:fields="booleanFields"
:allow-empty="true"
empty-label="Yok (statik)"
data-tip="Onay durumunun gelecegi veri alani"
@update:model-value="
(v) =>
update({
binding: v ? { type: 'scalar', path: v } : undefined,
checked: v ? undefined : element.checked ?? false,
} as any)
"
/>
<PropCheckbox
v-if="!element.binding"
label="Isaretli"
@@ -40,5 +63,13 @@ const { update, updateStyle } = usePropertyUpdate(() => props.element)
data-tip="Kutu kenarlik rengi"
@update:model-value="(v) => updateStyle('borderColor', v)"
/>
<PropNumberInput
label="Kenar Kalinligi"
:model-value="element.style.borderWidth ?? 0.3"
:step="0.1"
:min="0"
data-tip="Kutu kenarlik kalinligi (mm)"
@update:model-value="(v) => updateStyle('borderWidth', v)"
/>
</PropSection>
</template>

View File

@@ -29,10 +29,13 @@ const formatOptions = [
/>
<PropTextStyleGroup
:font-size="style().fontSize ?? 10"
:font-weight="style().fontWeight ?? 'normal'"
:font-family="style().fontFamily"
:color="style().color ?? '#666666'"
:align="style().align ?? 'left'"
:show-weight="false"
@update:font-size="(v) => updateStyle('fontSize', v)"
@update:font-weight="(v) => updateStyle('fontWeight', v)"
@update:font-family="(v) => updateStyle('fontFamily', v)"
@update:color="(v) => updateStyle('color', v)"
@update:align="(v) => updateStyle('align', v)"
/>

View File

@@ -29,10 +29,13 @@ const formatOptions = [
/>
<PropTextStyleGroup
:font-size="style().fontSize ?? 10"
:font-weight="style().fontWeight ?? 'normal'"
:font-family="style().fontFamily"
:color="style().color ?? '#666666'"
:align="style().align ?? 'center'"
:show-weight="false"
@update:font-size="(v) => updateStyle('fontSize', v)"
@update:font-weight="(v) => updateStyle('fontWeight', v)"
@update:font-family="(v) => updateStyle('fontFamily', v)"
@update:color="(v) => updateStyle('color', v)"
@update:align="(v) => updateStyle('align', v)"
/>

View File

@@ -1,14 +1,17 @@
<script setup lang="ts">
import { usePropertyUpdate } from '../../composables/usePropertyUpdate'
import { useSchemaStore } from '../../stores/schema'
import PropSection from './shared/PropSection.vue'
import PropColorInput from './shared/PropColorInput.vue'
import PropSelect from './shared/PropSelect.vue'
import PropFieldSelect from './shared/PropFieldSelect.vue'
import PropTextStyleGroup from './shared/PropTextStyleGroup.vue'
import type { RichTextElement, RichTextSpan, TextStyle } from '../../core/types'
import '../../styles/properties.css'
const props = defineProps<{ element: RichTextElement }>()
const { update, updateStyle } = usePropertyUpdate(() => props.element)
const schemaStore = useSchemaStore()
function updateSpan(index: number, updates: Partial<RichTextSpan>) {
const content = [...props.element.content]
@@ -43,10 +46,13 @@ const weightOptions = [
<PropSection title="Varsayilan Stil">
<PropTextStyleGroup
:font-size="element.style.fontSize ?? 11"
:font-weight="element.style.fontWeight ?? 'normal'"
:font-family="element.style.fontFamily"
:color="element.style.color ?? '#000000'"
:align="element.style.align ?? 'left'"
:show-weight="false"
@update:font-size="(v) => updateStyle('fontSize', v)"
@update:font-weight="(v) => updateStyle('fontWeight', v)"
@update:font-family="(v) => updateStyle('fontFamily', v)"
@update:color="(v) => updateStyle('color', v)"
@update:align="(v) => updateStyle('align', v)"
/>
@@ -79,6 +85,15 @@ const weightOptions = [
@input="(e) => updateSpan(idx, { text: (e.target as HTMLInputElement).value })"
/>
</div>
<PropFieldSelect
label="Binding"
:model-value="span.binding?.path ?? ''"
:fields="schemaStore.scalarFields"
:allow-empty="true"
empty-label="Yok (statik)"
data-tip="Span'in baglanacagi veri alani"
@update:model-value="(v) => updateSpan(idx, { binding: v ? { type: 'scalar', path: v } : undefined })"
/>
<div class="prop-row" data-tip="Span yazi boyutu bos birakilirsa varsayilan kullanilir">
<label class="prop-label">Boyut</label>
<input
@@ -109,6 +124,13 @@ const weightOptions = [
data-tip="Span metin rengi"
@update:model-value="(v) => updateSpanStyle(idx, 'color', v)"
/>
<PropSelect
label="Hizalama"
:model-value="(span.style as TextStyle).align ?? ''"
:options="[{ value: '', label: 'Varsayilan' }, { value: 'left', label: 'Sol' }, { value: 'center', label: 'Orta' }, { value: 'right', label: 'Sag' }]"
data-tip="Span hizalamasi"
@update:model-value="(v) => updateSpanStyle(idx, 'align', v || undefined)"
/>
</div>
</PropSection>
</template>

View File

@@ -15,6 +15,12 @@ const shapeOptions = [
{ value: 'rounded_rectangle', label: 'Yuvarlak Dikdortgen' },
{ value: 'ellipse', label: 'Elips' },
]
const borderStyleOptions = [
{ value: 'solid', label: 'Duz' },
{ value: 'dashed', label: 'Kesikli' },
{ value: 'dotted', label: 'Noktali' },
]
</script>
<template>
@@ -46,6 +52,13 @@ const shapeOptions = [
data-tip="Kenarlik cizgi kalinligi (mm)"
@update:model-value="(v) => updateStyle('borderWidth', v)"
/>
<PropSelect
label="Kenar Stili"
:model-value="element.style.borderStyle ?? 'solid'"
:options="borderStyleOptions"
data-tip="Kenarlik cizgi stili"
@update:model-value="(v) => updateStyle('borderStyle', v)"
/>
<PropNumberInput
v-if="element.shapeType === 'rounded_rectangle'"
label="Kose Yuvarlakligi"

View File

@@ -18,6 +18,10 @@ function updateSize(axis: 'width' | 'height', sv: SizeValue) {
templateStore.updateElementSize(props.element.id, { [axis]: sv })
}
function updateSizeConstraint(key: string, value: number | undefined) {
templateStore.updateElementSize(props.element.id, { [key]: value })
}
function onTypeChange(axis: 'width' | 'height', type: string) {
if (type === 'auto') updateSize(axis, { type: 'auto' })
else if (type === 'fr') updateSize(axis, { type: 'fr', value: 1 })
@@ -79,5 +83,49 @@ function onTypeChange(axis: 'width' | 'height', type: string) {
data-tip="Sabit yukseklik degeri (mm)"
@update:model-value="(v) => updateSize('height', { type: 'fixed', value: v })"
/>
<PropNumberInput
v-if="element.size.height.type === 'fr'"
label="fr"
:model-value="(element.size.height as any).value"
:step="1"
:min="1"
data-tip="Kalan alani oransal doldurma degeri"
@update:model-value="(v) => updateSize('height', { type: 'fr', value: v })"
/>
</PropSection>
<PropSection title="Min / Max">
<PropNumberInput
label="Min Gen."
:model-value="element.size.minWidth ?? 0"
:step="1"
:min="0"
data-tip="Minimum genislik (mm) 0 = sinir yok"
@update:model-value="(v) => updateSizeConstraint('minWidth', v > 0 ? v : undefined)"
/>
<PropNumberInput
label="Max Gen."
:model-value="element.size.maxWidth ?? 0"
:step="1"
:min="0"
data-tip="Maksimum genislik (mm) 0 = sinir yok"
@update:model-value="(v) => updateSizeConstraint('maxWidth', v > 0 ? v : undefined)"
/>
<PropNumberInput
label="Min Yuk."
:model-value="element.size.minHeight ?? 0"
:step="1"
:min="0"
data-tip="Minimum yukseklik (mm) 0 = sinir yok"
@update:model-value="(v) => updateSizeConstraint('minHeight', v > 0 ? v : undefined)"
/>
<PropNumberInput
label="Max Yuk."
:model-value="element.size.maxHeight ?? 0"
:step="1"
:min="0"
data-tip="Maksimum yukseklik (mm) 0 = sinir yok"
@update:model-value="(v) => updateSizeConstraint('maxHeight', v > 0 ? v : undefined)"
/>
</PropSection>
</template>

View File

@@ -1,17 +1,23 @@
<script setup lang="ts">
import { computed } from 'vue'
import { usePropertyUpdate } from '../../composables/usePropertyUpdate'
import { useSchemaStore } from '../../stores/schema'
import PropSection from './shared/PropSection.vue'
import PropFieldSelect from './shared/PropFieldSelect.vue'
import PropTextStyleGroup from './shared/PropTextStyleGroup.vue'
import type { StaticTextElement, TextStyle, TemplateElement } from '../../core/types'
import type { StaticTextElement, TextElement, TextStyle, TemplateElement } from '../../core/types'
import '../../styles/properties.css'
const props = defineProps<{ element: TemplateElement }>()
const { update, updateStyle } = usePropertyUpdate(() => props.element)
const schemaStore = useSchemaStore()
const style = () => props.element.style as TextStyle
const isText = computed(() => props.element.type === 'text')
</script>
<template>
<PropSection title="Metin Stili">
<PropSection title="Metin">
<div v-if="element.type === 'static_text'" class="prop-row" data-tip="Sabit metin icerigi">
<label class="prop-label">Metin</label>
<input
@@ -21,13 +27,38 @@ const style = () => props.element.style as TextStyle
@input="(e) => update({ content: (e.target as HTMLInputElement).value } as any)"
/>
</div>
<template v-if="isText">
<PropFieldSelect
label="Veri Alani"
:model-value="(element as TextElement).binding?.path ?? ''"
:fields="schemaStore.scalarFields"
data-tip="Metnin baglanacagi veri alani"
@update:model-value="(v) => update({ binding: { type: 'scalar', path: v } } as any)"
/>
<div class="prop-row" data-tip="Veri alaninin onune eklenecek sabit metin">
<label class="prop-label">Ön Ek</label>
<input
class="prop-input"
type="text"
:value="(element as TextElement).content ?? ''"
placeholder="ör: Fatura No: "
@input="(e) => update({ content: (e.target as HTMLInputElement).value || undefined } as any)"
/>
</div>
</template>
</PropSection>
<PropSection title="Metin Stili">
<PropTextStyleGroup
:font-size="style().fontSize ?? 11"
:font-weight="style().fontWeight ?? 'normal'"
:font-family="style().fontFamily"
:color="style().color ?? '#000000'"
:align="style().align ?? 'left'"
@update:font-size="(v) => updateStyle('fontSize', v)"
@update:font-weight="(v) => updateStyle('fontWeight', v)"
@update:font-family="(v) => updateStyle('fontFamily', v)"
@update:color="(v) => updateStyle('color', v)"
@update:align="(v) => updateStyle('align', v)"
/>

View File

@@ -0,0 +1,84 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useSchemaStore } from '../../../stores/schema'
import PropFieldSelect from './PropFieldSelect.vue'
import PropSelect from './PropSelect.vue'
import PropSection from './PropSection.vue'
import type { Condition } from '../../../core/types'
import '../../../styles/properties.css'
const props = defineProps<{
condition?: Condition
}>()
const emit = defineEmits<{
'update:condition': [value: Condition | undefined]
}>()
const schemaStore = useSchemaStore()
const enabled = computed(() => !!props.condition)
const operatorOptions = [
{ value: 'eq', label: '= Esit' },
{ value: 'neq', label: '≠ Esit Degil' },
{ value: 'gt', label: '> Buyuk' },
{ value: 'gte', label: '>= Buyuk Esit' },
{ value: 'lt', label: '< Kucuk' },
{ value: 'lte', label: '<= Kucuk Esit' },
{ value: 'truthy', label: 'Dolu (truthy)' },
{ value: 'falsy', label: 'Bos (falsy)' },
]
const needsValue = computed(() => {
const op = props.condition?.operator
return op && op !== 'truthy' && op !== 'falsy'
})
function toggle(on: boolean) {
if (on) {
emit('update:condition', { path: '', operator: 'truthy' })
} else {
emit('update:condition', undefined)
}
}
function updateField(key: keyof Condition, value: unknown) {
emit('update:condition', { ...props.condition!, [key]: value })
}
</script>
<template>
<PropSection title="Kosullu Gosterim">
<div class="prop-row" data-tip="Elemani belirli bir kosulla goster/gizle">
<label class="prop-label">Aktif</label>
<input type="checkbox" :checked="enabled" @change="toggle(($event.target as HTMLInputElement).checked)" />
</div>
<template v-if="enabled">
<PropFieldSelect
label="Alan"
:model-value="condition!.path"
:fields="schemaStore.scalarFields"
data-tip="Kosulun degerlendirilecegi veri alani"
@update:model-value="(v) => updateField('path', v)"
/>
<PropSelect
label="Operator"
:model-value="condition!.operator"
:options="operatorOptions"
data-tip="Karsilastirma operatoru"
@update:model-value="(v) => updateField('operator', v)"
/>
<div v-if="needsValue" class="prop-row" data-tip="Karsilastirilacak deger">
<label class="prop-label">Deger</label>
<input
class="prop-input"
type="text"
:value="condition!.value ?? ''"
@input="(e) => updateField('value', (e.target as HTMLInputElement).value)"
/>
</div>
</template>
</PropSection>
</template>

View File

@@ -1,26 +1,36 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useTemplateStore } from '../../../stores/template'
import PropNumberInput from './PropNumberInput.vue'
import PropColorInput from './PropColorInput.vue'
import PropSelect from './PropSelect.vue'
withDefaults(
const props = withDefaults(
defineProps<{
fontSize: number
fontWeight?: string
fontFamily?: string
color: string
align: string
showWeight?: boolean
}>(),
{ fontWeight: 'normal', showWeight: true },
{ fontWeight: 'normal', fontFamily: undefined, showWeight: true },
)
defineEmits<{
'update:fontSize': [value: number]
'update:fontWeight': [value: string]
'update:fontFamily': [value: string | undefined]
'update:color': [value: string]
'update:align': [value: string]
}>()
const templateStore = useTemplateStore()
const fontOptions = computed(() =>
templateStore.template.fonts.map((f) => ({ value: f, label: f })),
)
const weightOptions = [
{ value: 'normal', label: 'Normal' },
{ value: 'bold', label: 'Kalin' },
@@ -34,6 +44,14 @@ const alignOptions = [
</script>
<template>
<PropSelect
v-if="fontOptions.length > 1"
label="Font"
:model-value="fontFamily ?? fontOptions[0]?.value ?? ''"
:options="fontOptions"
data-tip="Yazi tipi ailesi"
@update:model-value="$emit('update:fontFamily', $event)"
/>
<PropNumberInput
label="Boyut (pt)"
:model-value="fontSize"

View File

@@ -81,7 +81,25 @@ const emit = defineEmits<{
&times;
</button>
</div>
<span class="ts-clbl">Zebra</span>
<span class="ts-clbl">Tek</span>
</div>
<div class="ts-color-item" data-tip="Zebra satir rengi cift satirlar">
<div class="ts-swatch-wrap">
<input
class="ts-swatch"
type="color"
:value="style.zebraEven ?? '#ffffff'"
@input="(e) => emit('update:style', 'zebraEven', (e.target as HTMLInputElement).value)"
/>
<button
v-if="style.zebraEven"
class="ts-swatch-clr"
@click="emit('update:style', 'zebraEven', undefined)"
>
&times;
</button>
</div>
<span class="ts-clbl">Cift</span>
</div>
</div>

View File

@@ -250,11 +250,22 @@ export interface ChartLabels {
color?: string
}
export interface ChartReferenceLine {
categoryIndex: number
color?: string
width?: number
label?: string
dash?: boolean
}
export interface ChartAxis {
xLabel?: string
yLabel?: string
showGrid?: boolean
gridColor?: string
showVerticalGrid?: boolean
verticalGridColor?: string
referenceLines?: ChartReferenceLine[]
}
export interface ChartStyle {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 25 KiB