Kurze Zusammenfassung: Ergänzt Feature-001-Artefakte: QA-Checkliste, Quickstart, Design-Entscheidung, Scheduler-Dokumentation. Ergänzt Projekt-ignores: .dockerignore, .eslintignore, .npmignore. Führte pint aus (Formatierungsfixes). Fügte/aktualisierte Backend-/Frontend-Skizzen und Tests für den Public Grid Viewer (Reservations, Selection mapping, Payment scaffold, Composite job). Branch: 001-public-grid-viewer Wichtige Dateien (Auswahl): Docs & specs: qa.md quickstart.md 001-public-grid-viewer.md SCHEDULER.md Config / infra: pixel_grid.php .dockerignore, .eslintignore, .npmignore compose.yaml Backend (skizzen / implementation): SchedulerServiceProvider.php providers.php ExpireReservations.php Reservation.php 2026_01_03_000002_create_reservations_table.php SelectionMapper.php CompositeImage.php PaymentController.php Frontend (scaffold): Index.vue GridCanvas.vue Tests: PublicGridMetaTest.php ReserveSelectionTest.php PriceCalculationTest.php SelectionMathTest.php Was ich lokal geprüft habe pint ausgeführt (Formatierungsfixes angewendet). Vollständige Test-Suite ausgeführt: 52 passed (164 assertions). Branch gepusht: cloudarix/001-public-grid-viewer. Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local> Reviewed-on: #1
57 lines
1.3 KiB
Vue
57 lines
1.3 KiB
Vue
<template>
|
|
<div class="upload-modal">
|
|
<div class="backdrop" @click="$emit('close')"></div>
|
|
<div class="dialog">
|
|
<h3>Upload Preview</h3>
|
|
<input type="file" accept="image/*" @change="onFile" />
|
|
<div v-if="preview" class="preview">
|
|
<img :src="preview" alt="preview" />
|
|
</div>
|
|
<div class="actions">
|
|
<button @click="$emit('close')">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue';
|
|
defineProps({ selection: { type: Object, default: null } });
|
|
const preview = ref<string | null>(null);
|
|
|
|
function onFile(e: Event) {
|
|
const input = e.target as HTMLInputElement | null;
|
|
const file = input && input.files ? input.files[0] : null;
|
|
if (!file) return;
|
|
const reader = new FileReader();
|
|
reader.onload = (ev) => {
|
|
preview.value = ev.target && (ev.target as FileReader).result as string | null;
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.upload-modal .backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0,0,0,0.4);
|
|
}
|
|
.upload-modal .dialog {
|
|
position: fixed;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: white;
|
|
padding: 1rem;
|
|
border-radius: 8px;
|
|
width: 90%;
|
|
max-width: 560px;
|
|
}
|
|
.preview img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
display: block;
|
|
}
|
|
</style>
|