Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
e38f540c79
|
|||
|
73ad5b4eb1
|
|||
|
b4a70233cf
|
|||
|
cb4b9c6b40
|
@@ -11,6 +11,7 @@ export default class Modal extends Component {
|
||||
|
||||
@action
|
||||
close() {
|
||||
if (this.args.disableClose) return;
|
||||
if (this.args.onClose) {
|
||||
this.args.onClose();
|
||||
}
|
||||
@@ -31,10 +32,11 @@ export default class Modal extends Component {
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="close-modal-btn btn-text"
|
||||
class="close-modal-btn btn-text {{if @disableClose 'disabled'}}"
|
||||
disabled={{@disableClose}}
|
||||
{{on "click" this.close}}
|
||||
>
|
||||
<Icon @name="x" @size={{24}} />
|
||||
<Icon @name="x" @size={{24}} @color="currentColor" />
|
||||
</button>
|
||||
{{yield}}
|
||||
</div>
|
||||
|
||||
@@ -27,6 +27,12 @@ export default class PlaceDetails extends Component {
|
||||
@tracked isPhotoUploadModalOpen = false;
|
||||
@tracked isNostrConnectModalOpen = false;
|
||||
@tracked newlyUploadedPhotoId = null;
|
||||
@tracked isPhotoUploadActive = false;
|
||||
|
||||
@action
|
||||
handleUploadStateChange(isActive) {
|
||||
this.isPhotoUploadActive = isActive;
|
||||
}
|
||||
|
||||
@action
|
||||
openPhotoUploadModal(e) {
|
||||
@@ -42,6 +48,7 @@ export default class PlaceDetails extends Component {
|
||||
|
||||
@action
|
||||
closePhotoUploadModal(eventId) {
|
||||
if (this.isPhotoUploadActive) return;
|
||||
this.isPhotoUploadModalOpen = false;
|
||||
if (typeof eventId === 'string') {
|
||||
this.newlyUploadedPhotoId = eventId;
|
||||
@@ -585,10 +592,14 @@ export default class PlaceDetails extends Component {
|
||||
</div>
|
||||
|
||||
{{#if this.isPhotoUploadModalOpen}}
|
||||
<Modal @onClose={{this.closePhotoUploadModal}}>
|
||||
<Modal
|
||||
@onClose={{this.closePhotoUploadModal}}
|
||||
@disableClose={{this.isPhotoUploadActive}}
|
||||
>
|
||||
<PlacePhotoUpload
|
||||
@place={{this.saveablePlace}}
|
||||
@onClose={{this.closePhotoUploadModal}}
|
||||
@onUploadStateChange={{this.handleUploadStateChange}}
|
||||
/>
|
||||
</Modal>
|
||||
{{/if}}
|
||||
|
||||
@@ -22,6 +22,7 @@ export default class PlacePhotoUploadItem extends Component {
|
||||
@tracked thumbnailUrl = '';
|
||||
@tracked blurhash = '';
|
||||
@tracked error = '';
|
||||
@tracked statusText = '';
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
@@ -47,6 +48,7 @@ export default class PlacePhotoUploadItem extends Component {
|
||||
|
||||
uploadTask = task(async (file) => {
|
||||
this.error = '';
|
||||
this.statusText = 'Processing';
|
||||
try {
|
||||
// 1. Process main image and generate blurhash in worker
|
||||
const mainData = await this.imageProcessor.process(
|
||||
@@ -71,18 +73,34 @@ export default class PlacePhotoUploadItem extends Component {
|
||||
let mainResult, thumbResult;
|
||||
const isMobileDevice = isMobile();
|
||||
|
||||
const mainProgress = (status) => {
|
||||
if (status === 'signing') this.statusText = 'Signing photo upload';
|
||||
if (status === 'uploading') this.statusText = 'Uploading photo';
|
||||
};
|
||||
|
||||
const thumbProgress = (status) => {
|
||||
if (status === 'signing') this.statusText = 'Signing thumbnail upload';
|
||||
if (status === 'uploading') this.statusText = 'Uploading thumbnail';
|
||||
};
|
||||
|
||||
if (isMobileDevice) {
|
||||
// Mobile: sequential uploads to preserve bandwidth and memory
|
||||
mainResult = await this.blossom.upload(mainData.blob, {
|
||||
sequential: true,
|
||||
onProgress: mainProgress,
|
||||
});
|
||||
thumbResult = await this.blossom.upload(thumbData.blob, {
|
||||
sequential: true,
|
||||
onProgress: thumbProgress,
|
||||
});
|
||||
} else {
|
||||
// Desktop: concurrent uploads
|
||||
const mainUploadPromise = this.blossom.upload(mainData.blob);
|
||||
const thumbUploadPromise = this.blossom.upload(thumbData.blob);
|
||||
const mainUploadPromise = this.blossom.upload(mainData.blob, {
|
||||
onProgress: mainProgress,
|
||||
});
|
||||
const thumbUploadPromise = this.blossom.upload(thumbData.blob, {
|
||||
onProgress: thumbProgress,
|
||||
});
|
||||
|
||||
[mainResult, thumbResult] = await Promise.all([
|
||||
mainUploadPromise,
|
||||
@@ -127,6 +145,9 @@ export default class PlacePhotoUploadItem extends Component {
|
||||
@color="white"
|
||||
class="spin-animation"
|
||||
/>
|
||||
{{#if this.statusText}}
|
||||
<span class="upload-status-text">{{this.statusText}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
|
||||
@@ -77,6 +77,9 @@ export default class PlacePhotoUpload extends Component {
|
||||
}
|
||||
this.file = file;
|
||||
this.uploadedPhoto = null;
|
||||
if (this.args.onUploadStateChange) {
|
||||
this.args.onUploadStateChange(true);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -91,6 +94,9 @@ export default class PlacePhotoUpload extends Component {
|
||||
}
|
||||
this.file = null;
|
||||
this.uploadedPhoto = null;
|
||||
if (this.args.onUploadStateChange) {
|
||||
this.args.onUploadStateChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
deletePhotoTask = task(async (photoData) => {
|
||||
@@ -191,6 +197,10 @@ export default class PlacePhotoUpload extends Component {
|
||||
this.file = null;
|
||||
this.uploadedPhoto = null;
|
||||
|
||||
if (this.args.onUploadStateChange) {
|
||||
this.args.onUploadStateChange(false);
|
||||
}
|
||||
|
||||
if (this.args.onClose) {
|
||||
this.args.onClose(event.id);
|
||||
}
|
||||
|
||||
@@ -116,7 +116,8 @@ export default class PlacePhotosCarousel extends Component {
|
||||
{{#each this.photos as |photo|}}
|
||||
{{! template-lint-disable no-inline-styles }}
|
||||
<div
|
||||
class="carousel-slide"
|
||||
class="carousel-slide
|
||||
{{if photo.isLandscape 'landscape' 'portrait'}}"
|
||||
style={{photo.style}}
|
||||
data-event-id={{photo.eventId}}
|
||||
>
|
||||
|
||||
@@ -60,10 +60,13 @@ export default class BlossomService extends Service {
|
||||
return `Nostr ${base64url}`;
|
||||
}
|
||||
|
||||
async _uploadToServer(file, hash, serverUrl) {
|
||||
async _uploadToServer(file, hash, serverUrl, onProgress) {
|
||||
const uploadUrl = getBlossomUrl(serverUrl, 'upload');
|
||||
|
||||
if (onProgress) onProgress('signing');
|
||||
const authHeader = await this._getAuthHeader('upload', hash, serverUrl);
|
||||
|
||||
if (onProgress) onProgress('uploading');
|
||||
// eslint-disable-next-line warp-drive/no-external-request-patterns
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: 'PUT',
|
||||
@@ -109,14 +112,20 @@ export default class BlossomService extends Service {
|
||||
|
||||
if (options.sequential) {
|
||||
// Sequential upload logic
|
||||
mainResult = await this._uploadToServer(file, payloadHash, mainServer);
|
||||
mainResult = await this._uploadToServer(
|
||||
file,
|
||||
payloadHash,
|
||||
mainServer,
|
||||
options.onProgress
|
||||
);
|
||||
|
||||
for (const serverUrl of fallbackServers) {
|
||||
try {
|
||||
const result = await this._uploadToServer(
|
||||
file,
|
||||
payloadHash,
|
||||
serverUrl
|
||||
serverUrl,
|
||||
options.onProgress
|
||||
);
|
||||
fallbackUrls.push(result.url);
|
||||
} catch (error) {
|
||||
@@ -125,9 +134,14 @@ export default class BlossomService extends Service {
|
||||
}
|
||||
} else {
|
||||
// Concurrent upload logic
|
||||
const mainPromise = this._uploadToServer(file, payloadHash, mainServer);
|
||||
const mainPromise = this._uploadToServer(
|
||||
file,
|
||||
payloadHash,
|
||||
mainServer,
|
||||
options.onProgress
|
||||
);
|
||||
const fallbackPromises = fallbackServers.map((serverUrl) =>
|
||||
this._uploadToServer(file, payloadHash, serverUrl)
|
||||
this._uploadToServer(file, payloadHash, serverUrl, options.onProgress)
|
||||
);
|
||||
|
||||
// Main server MUST succeed
|
||||
|
||||
@@ -285,10 +285,20 @@ body {
|
||||
inset: 0;
|
||||
background: rgb(0 0 0 / 60%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.upload-status-text {
|
||||
color: white;
|
||||
margin-top: 1rem;
|
||||
font-size: 0.9rem;
|
||||
text-shadow: 0 1px 3px rgb(0 0 0 / 80%);
|
||||
text-align: center;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.photo-upload-item .error-overlay {
|
||||
background: rgb(224 108 117 / 80%);
|
||||
cursor: pointer;
|
||||
@@ -1006,10 +1016,17 @@ abbr[title] {
|
||||
flex: 0 0 auto;
|
||||
height: 100px;
|
||||
width: auto;
|
||||
aspect-ratio: var(--slide-ratio, 16 / 9);
|
||||
scroll-snap-align: none;
|
||||
}
|
||||
|
||||
.carousel-slide.landscape {
|
||||
aspect-ratio: var(--slide-ratio, 16 / 9);
|
||||
}
|
||||
|
||||
.carousel-slide.portrait {
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
.carousel-placeholder {
|
||||
display: block;
|
||||
background-color: var(--hover-bg);
|
||||
@@ -1798,6 +1815,12 @@ button.create-place {
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
cursor: pointer;
|
||||
color: #898989;
|
||||
}
|
||||
|
||||
.close-modal-btn.disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.place-photo-upload h2 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "marco",
|
||||
"version": "1.20.1",
|
||||
"version": "1.20.2",
|
||||
"private": true,
|
||||
"description": "Unhosted maps app",
|
||||
"repository": {
|
||||
|
||||
1
release/assets/main-9lfQuoS5.css
Normal file
1
release/assets/main-9lfQuoS5.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -39,8 +39,8 @@
|
||||
<meta name="msapplication-TileColor" content="#F6E9A6">
|
||||
<meta name="msapplication-TileImage" content="/icons/icon-144.png">
|
||||
|
||||
<script type="module" crossorigin src="/assets/main-CGySSjv6.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BA3LWr76.css">
|
||||
<script type="module" crossorigin src="/assets/main-D7SnY8s9.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-9lfQuoS5.css">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user