improve page-create, service-worker and manifest

This commit is contained in:
2026-01-28 08:28:36 +01:00
parent 956cdacd3f
commit 21e05df241
6 changed files with 188 additions and 14 deletions

View File

@@ -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);