mirror of
https://github.com/duhanbalci/dreport.git
synced 2026-07-02 02:49:16 +00:00
faz 1 & 2
This commit is contained in:
80
frontend/src/composables/useTypstCompiler.ts
Normal file
80
frontend/src/composables/useTypstCompiler.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { ref, watch, type Ref } from 'vue'
|
||||
import type { ElementLayout } from '../core/template-to-typst'
|
||||
|
||||
export function useTypstCompiler(markup: Ref<string>) {
|
||||
const svg = ref<string | null>(null)
|
||||
const error = ref<string | null>(null)
|
||||
const compiling = ref(false)
|
||||
const layout = ref<Record<string, ElementLayout>>({})
|
||||
|
||||
let worker: Worker | null = null
|
||||
let requestId = 0
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
function initWorker() {
|
||||
worker = new Worker(new URL('../workers/typst.worker.ts', import.meta.url), {
|
||||
type: 'module',
|
||||
})
|
||||
|
||||
worker.onmessage = (e: MessageEvent<{
|
||||
type: string
|
||||
svg?: string
|
||||
layout?: Record<string, ElementLayout>
|
||||
error?: string
|
||||
id: number
|
||||
}>) => {
|
||||
const data = e.data
|
||||
if (data.id !== requestId) return
|
||||
|
||||
compiling.value = false
|
||||
if (data.type === 'result') {
|
||||
svg.value = data.svg ?? null
|
||||
layout.value = data.layout ?? {}
|
||||
error.value = null
|
||||
} else if (data.type === 'error') {
|
||||
error.value = data.error ?? 'Bilinmeyen derleme hatası'
|
||||
}
|
||||
}
|
||||
|
||||
worker.onerror = () => {
|
||||
compiling.value = false
|
||||
error.value = 'Worker hatası — yeniden başlatılıyor'
|
||||
worker?.terminate()
|
||||
worker = null
|
||||
setTimeout(initWorker, 500)
|
||||
}
|
||||
}
|
||||
|
||||
function compile(typstMarkup: string) {
|
||||
if (!worker) initWorker()
|
||||
requestId++
|
||||
compiling.value = true
|
||||
worker!.postMessage({ type: 'compile', markup: typstMarkup, id: requestId })
|
||||
}
|
||||
|
||||
watch(
|
||||
markup,
|
||||
(newMarkup) => {
|
||||
if (debounceTimer) clearTimeout(debounceTimer)
|
||||
debounceTimer = setTimeout(() => {
|
||||
compile(newMarkup)
|
||||
}, 200)
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
function dispose() {
|
||||
worker?.terminate()
|
||||
worker = null
|
||||
if (debounceTimer) clearTimeout(debounceTimer)
|
||||
}
|
||||
|
||||
return {
|
||||
svg,
|
||||
error,
|
||||
compiling,
|
||||
layout,
|
||||
compile: () => compile(markup.value),
|
||||
dispose,
|
||||
}
|
||||
}
|
||||
60
frontend/src/composables/useUndoRedo.ts
Normal file
60
frontend/src/composables/useUndoRedo.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { ref, watch, type Ref } from 'vue'
|
||||
|
||||
export function useUndoRedo<T>(source: Ref<T>, maxHistory = 50) {
|
||||
const undoStack = ref<string[]>([]) as Ref<string[]>
|
||||
const redoStack = ref<string[]>([]) as Ref<string[]>
|
||||
|
||||
let skipWatch = false
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
// Başlangıç snapshot'ı
|
||||
undoStack.value.push(JSON.stringify(source.value))
|
||||
|
||||
watch(
|
||||
source,
|
||||
() => {
|
||||
if (skipWatch) return
|
||||
|
||||
// Debounce: hızlı ardışık değişiklikleri birleştir
|
||||
if (debounceTimer) clearTimeout(debounceTimer)
|
||||
debounceTimer = setTimeout(() => {
|
||||
const snap = JSON.stringify(source.value)
|
||||
const last = undoStack.value[undoStack.value.length - 1]
|
||||
if (snap === last) return
|
||||
|
||||
undoStack.value.push(snap)
|
||||
if (undoStack.value.length > maxHistory) {
|
||||
undoStack.value.shift()
|
||||
}
|
||||
redoStack.value = []
|
||||
}, 300)
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
function undo() {
|
||||
if (undoStack.value.length <= 1) return
|
||||
const current = undoStack.value.pop()!
|
||||
redoStack.value.push(current)
|
||||
const prev = undoStack.value[undoStack.value.length - 1]
|
||||
applySnapshot(prev)
|
||||
}
|
||||
|
||||
function redo() {
|
||||
if (redoStack.value.length === 0) return
|
||||
const next = redoStack.value.pop()!
|
||||
undoStack.value.push(next)
|
||||
applySnapshot(next)
|
||||
}
|
||||
|
||||
function applySnapshot(snap: string) {
|
||||
skipWatch = true
|
||||
Object.assign(source.value as object, JSON.parse(snap))
|
||||
skipWatch = false
|
||||
}
|
||||
|
||||
const canUndo = () => undoStack.value.length > 1
|
||||
const canRedo = () => redoStack.value.length > 0
|
||||
|
||||
return { undo, redo, canUndo, canRedo }
|
||||
}
|
||||
Reference in New Issue
Block a user