improve page-create, service-worker and manifest
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { t, i18n } from '../../i18n.js';
|
||||
import { router } from '../../router.js';
|
||||
import { cryptoService } from '../../services/crypto.js';
|
||||
|
||||
class PageCreate extends HTMLElement {
|
||||
constructor() {
|
||||
@@ -9,8 +10,11 @@ class PageCreate extends HTMLElement {
|
||||
description: '',
|
||||
price: '',
|
||||
category: '',
|
||||
location: ''
|
||||
location: '',
|
||||
moneroAddress: ''
|
||||
};
|
||||
this.imageFiles = [];
|
||||
this.imagePreviews = [];
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -103,13 +107,30 @@ class PageCreate extends HTMLElement {
|
||||
<label class="label" data-i18n="create.images">${t('create.images')}</label>
|
||||
<div class="image-upload">
|
||||
<input type="file" id="images" name="images" accept="image/*" multiple hidden>
|
||||
<label for="images" class="upload-area">
|
||||
<label for="images" class="upload-area" id="upload-area">
|
||||
<span class="upload-icon">📷</span>
|
||||
<span data-i18n="create.uploadImages">${t('create.uploadImages')}</span>
|
||||
</label>
|
||||
<div class="image-previews" id="image-previews">
|
||||
${this.renderImagePreviews()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="label" for="moneroAddress">${t('create.moneroAddress')}</label>
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
id="moneroAddress"
|
||||
name="moneroAddress"
|
||||
value="${this.escapeHtml(this.formData.moneroAddress)}"
|
||||
required
|
||||
placeholder="${t('create.moneroPlaceholder')}"
|
||||
>
|
||||
<p class="field-hint">${t('create.moneroHint')}</p>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn btn-outline btn-lg" id="cancel-btn">
|
||||
${t('create.cancel')}
|
||||
@@ -128,13 +149,76 @@ class PageCreate extends HTMLElement {
|
||||
setupEventListeners() {
|
||||
const form = this.querySelector('#create-form');
|
||||
const cancelBtn = this.querySelector('#cancel-btn');
|
||||
const imageInput = this.querySelector('#images');
|
||||
|
||||
form.addEventListener('submit', (e) => this.handleSubmit(e));
|
||||
cancelBtn.addEventListener('click', () => router.back());
|
||||
|
||||
form.querySelectorAll('input, textarea, select').forEach(input => {
|
||||
input.addEventListener('input', (e) => {
|
||||
this.formData[e.target.name] = e.target.value;
|
||||
if (e.target.name) {
|
||||
this.formData[e.target.name] = e.target.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
imageInput?.addEventListener('change', (e) => this.handleImageSelect(e));
|
||||
}
|
||||
|
||||
handleImageSelect(e) {
|
||||
const files = Array.from(e.target.files);
|
||||
|
||||
files.forEach(file => {
|
||||
if (this.imageFiles.length >= 5) return;
|
||||
|
||||
this.imageFiles.push(file);
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
this.imagePreviews.push(event.target.result);
|
||||
this.updateImagePreviews();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
updateImagePreviews() {
|
||||
const container = this.querySelector('#image-previews');
|
||||
const uploadArea = this.querySelector('#upload-area');
|
||||
|
||||
if (container) {
|
||||
container.innerHTML = this.renderImagePreviews();
|
||||
this.setupRemoveListeners();
|
||||
}
|
||||
|
||||
if (uploadArea) {
|
||||
uploadArea.style.display = this.imageFiles.length >= 5 ? 'none' : 'flex';
|
||||
}
|
||||
}
|
||||
|
||||
renderImagePreviews() {
|
||||
if (this.imagePreviews.length === 0) return '';
|
||||
|
||||
return this.imagePreviews.map((src, index) => /* html */`
|
||||
<div class="image-preview">
|
||||
<img src="${src}" alt="Preview ${index + 1}">
|
||||
<button type="button" class="remove-image" data-index="${index}" aria-label="Remove">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
setupRemoveListeners() {
|
||||
this.querySelectorAll('.remove-image').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
const index = parseInt(e.currentTarget.dataset.index);
|
||||
this.imageFiles.splice(index, 1);
|
||||
this.imagePreviews.splice(index, 1);
|
||||
this.updateImagePreviews();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -209,6 +293,57 @@ style.textContent = /* css */`
|
||||
margin-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
page-create .image-previews {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
page-create .image-previews:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
page-create .image-preview {
|
||||
position: relative;
|
||||
aspect-ratio: 1;
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
page-create .image-preview img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
page-create .remove-image {
|
||||
position: absolute;
|
||||
top: var(--space-xs);
|
||||
right: var(--space-xs);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-error);
|
||||
color: white;
|
||||
border-radius: var(--radius-full);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity var(--transition-fast);
|
||||
}
|
||||
|
||||
page-create .image-preview:hover .remove-image {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
page-create .field-hint {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-muted);
|
||||
margin-top: var(--space-xs);
|
||||
}
|
||||
|
||||
page-create .form-actions {
|
||||
display: flex;
|
||||
gap: var(--space-md);
|
||||
|
||||
Reference in New Issue
Block a user