initial commit
This commit is contained in:
244
frontend/public/pages/images.html
Normal file
244
frontend/public/pages/images.html
Normal file
@@ -0,0 +1,244 @@
|
||||
<div
|
||||
class="flex flex-col gap-4 pt-16 mx-auto px-4 md:px-6 max-w-6xl"
|
||||
x-data="imageGenerator()"
|
||||
>
|
||||
<div>
|
||||
<form @submit.prevent="generateImage" class="flex flex-col gap-4 w-full">
|
||||
<!-- Prompt -->
|
||||
<div class="flex-1">
|
||||
<label for="prompt" class="text-sm font-medium text-primary-700"
|
||||
>Prompt</label
|
||||
>
|
||||
<textarea
|
||||
id="prompt"
|
||||
name="prompt"
|
||||
class="mt-1 p-2 w-full rounded-md border-primary-400 shadow focus:border-secondary-500 focus:ring-secondary-500 sm:text-sm min-h-[100px] overflow-y-auto text-primary-900 resize-none"
|
||||
required
|
||||
x-model="prompt"
|
||||
placeholder="Enter your image generation prompt here..."
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Parameters -->
|
||||
<div class="flex flex-col gap-3">
|
||||
<div>
|
||||
<label
|
||||
for="nav-model"
|
||||
class="block text-sm font-medium text-primary-700"
|
||||
>Model</label
|
||||
>
|
||||
<select
|
||||
id="nav-model"
|
||||
name="model"
|
||||
x-model="selectedModel"
|
||||
class="mt-1 p-2 block w-full rounded-md border-primary-400 shadow focus:border-secondary-500 focus:ring-secondary-500 sm:text-sm text-primary-900"
|
||||
required
|
||||
>
|
||||
<option value="">Select Model</option>
|
||||
<template x-for="model in models" :key="model.id">
|
||||
<option :value="model.id" x-text="model.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="size" class="text-sm font-medium text-primary-700"
|
||||
>Size</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="size"
|
||||
name="size"
|
||||
x-model="size"
|
||||
class="mt-1 p-2 block w-full rounded-md border-primary-400 shadow focus:border-secondary-500 focus:ring-secondary-500 sm:text-sm text-primary-900"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<div class="flex-1">
|
||||
<label
|
||||
for="nav-n"
|
||||
class="block text-sm font-medium text-primary-700"
|
||||
>Count</label
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
id="nav-n"
|
||||
name="n"
|
||||
min="1"
|
||||
max="10"
|
||||
x-model="n"
|
||||
class="mt-1 p-2 block w-full rounded-md border-primary-400 shadow focus:border-secondary-500 focus:ring-secondary-500 sm:text-sm text-primary-900"
|
||||
value="1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex-1">
|
||||
<label
|
||||
for="nav-seed"
|
||||
class="block text-sm font-medium text-primary-700"
|
||||
>Seed</label
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
id="nav-seed"
|
||||
name="seed"
|
||||
x-model="seed"
|
||||
class="mt-1 p-2 block w-full rounded-md border-primary-400 shadow focus:border-secondary-500 focus:ring-secondary-500 sm:text-sm text-primary-900"
|
||||
value="-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="image-upload" class="text-sm font-medium text-primary-700"
|
||||
>Upload Image to Edit</label
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
id="image-upload"
|
||||
accept="image/*"
|
||||
@change="startEdit"
|
||||
class="mt-1 p-2 block w-full rounded-md border-primary-400 shadow text-primary-900"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Edit Panel -->
|
||||
<div
|
||||
id="edit-panel"
|
||||
x-show="editMode"
|
||||
class="mt-2 bg-primary-50 p-4 rounded shadow"
|
||||
>
|
||||
<div
|
||||
:class="['flex gap-4', isLandscape ? 'flex-col' : 'flex-col lg:flex-row']"
|
||||
>
|
||||
<!-- Image Preview -->
|
||||
<div class="flex justify-center relative">
|
||||
<img
|
||||
id="editing-image"
|
||||
:src="editingImage?.url"
|
||||
alt="Original image for editing"
|
||||
class="max-h-[75vh] rounded-lg shadow-md"
|
||||
/>
|
||||
<canvas
|
||||
id="mask"
|
||||
class="absolute top-0 left-0 w-full h-full rounded-lg cursor-crosshair"
|
||||
></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Mask Options -->
|
||||
<div class="flex-1 flex flex-col gap-2 mt-auto justify-end">
|
||||
<div class="mt-2">
|
||||
<label
|
||||
for="lineWidthSlider"
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Line Width: <span x-text="lineWidth"></span>
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
id="lineWidthSlider"
|
||||
x-model="lineWidth"
|
||||
min="1"
|
||||
max="100"
|
||||
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
@click="clearMask"
|
||||
class="mt-2 px-3 py-1 cursor-pointer bg-primary-200 text-primary-700 rounded hover:bg-primary-600 hover:text-white text-center transition-colors"
|
||||
>
|
||||
Clear Mask
|
||||
</span>
|
||||
<span
|
||||
@click="cancelEdit"
|
||||
class="mt-2 px-3 py-1 cursor-pointer bg-primary-200 text-primary-700 rounded hover:bg-primary-600 hover:text-white text-center transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
x-bind:disabled="loading || !selectedModel"
|
||||
:class="loading || !selectedModel ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
class="inline-flex justify-center items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-primary-50 bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 disabled:opacity-50 gap-2 transition-colors"
|
||||
>
|
||||
<span
|
||||
x-text="loading ? '' : editMode ? 'Edit Image' : 'Generate Image'"
|
||||
></span>
|
||||
<div
|
||||
x-show="loading"
|
||||
class="h-5 w-5 animate-spin rounded-full border-2 border-white border-t-transparent"
|
||||
></div>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-primary-900 mb-2">Generated Images</h3>
|
||||
|
||||
<div
|
||||
x-show="error"
|
||||
class="bg-tertiary-50 border border-tertiary-200 rounded-md p-4 mb-4"
|
||||
>
|
||||
<p class="text-tertiary-700" x-text="error"></p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
x-show="!generatedImages.length"
|
||||
class="text-center py-8 text-primary-500"
|
||||
>
|
||||
No Images Found
|
||||
</div>
|
||||
|
||||
<div
|
||||
x-show="generatedImages.length"
|
||||
class="columns-2 md:columns-3 lg:columns-4 gap-2"
|
||||
>
|
||||
<template x-for="(image, index) in generatedImages" :key="index">
|
||||
<div
|
||||
class="flex flex-col gap-2 break-inside-avoid border border-primary-200 rounded-lg p-2 mb-2 h-full bg-primary-100 hover:border-primary-300 transition-colors shadow"
|
||||
>
|
||||
<button
|
||||
@click="deleteImage(image.name)"
|
||||
class="text-white hover:text-white text-sm justify-center cursor-pointer p-1 rounded bg-red-600 hover:bg-red-700 flex items-center h-full transition-colors"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<img
|
||||
:src="image.path"
|
||||
:alt="image.prompt"
|
||||
@click="openLightbox(image.path)"
|
||||
class="rounded-lg shadow-sm max-w-full h-auto cursor-pointer hover:opacity-90 transition-opacity"
|
||||
/>
|
||||
<span
|
||||
class="text-xs text-primary-500 bg-primary-200 px-2 py-1 rounded flex justify-center"
|
||||
x-text="image.date"
|
||||
></span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lightbox -->
|
||||
<div
|
||||
x-show="lightbox.open"
|
||||
x-cloak
|
||||
@click="closeLightbox"
|
||||
@keydown.escape.window="closeLightbox"
|
||||
@keydown.arrow-left.window="prevImage"
|
||||
@keydown.arrow-right.window="nextImage"
|
||||
@touchstart="handleTouchStart"
|
||||
@touchend="handleTouchEnd"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/75 p-4 backdrop-blur-sm"
|
||||
>
|
||||
<img
|
||||
:src="lightbox.imageSrc"
|
||||
@click.stop
|
||||
class="max-w-[90vw] max-h-[90vh] object-contain rounded-lg shadow-2xl"
|
||||
alt="Full size preview"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user