From 5b618dc36702747db7011e2790b88a667328bce3 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Tue, 5 Nov 2024 00:18:16 +0100 Subject: [PATCH] UX: add proper delete dialog, add option to report images --- langs/en.json | 23 +++ package-lock.json | 14 +- package.json | 2 +- public/css/index-tailwind-output.css | 43 ++-- src/Logic/ImageProviders/AllImageProviders.ts | 8 +- src/Logic/ImageProviders/ImageProvider.ts | 8 + src/Logic/ImageProviders/Panoramax.ts | 14 +- src/UI/Base/DotMenu.svelte | 2 +- src/UI/Base/Popup.svelte | 12 +- src/UI/Flowbite/AccordionSingle.svelte | 3 +- src/UI/Image/AttributedImage.svelte | 15 +- src/UI/Image/DeletableImage.svelte | 188 ++++++++++++++++++ src/UI/Image/ImageCarousel.svelte | 27 +++ src/UI/Image/ImageCarousel.ts | 62 ------ src/UI/Image/ImageOperations.svelte | 26 +-- src/UI/Image/SlideShow.ts | 48 ----- src/UI/SpecialVisualizations.ts | 10 +- src/index.css | 5 - 18 files changed, 334 insertions(+), 176 deletions(-) create mode 100644 src/UI/Image/DeletableImage.svelte create mode 100644 src/UI/Image/ImageCarousel.svelte delete mode 100644 src/UI/Image/ImageCarousel.ts delete mode 100644 src/UI/Image/SlideShow.ts diff --git a/langs/en.json b/langs/en.json index 4c371afe2..bad4e5e3d 100644 --- a/langs/en.json +++ b/langs/en.json @@ -596,10 +596,33 @@ "seeNearby": "Browse nearby pictures", "title": "Nearby streetview imagery" }, + "panoramax": { + "deletionRequested": "The report has been sent. A moderator will look to it shortly", + "freeform": "Is there other relevant information?", + "otherFreeform": "Please specify why this image should be removed:", + "placeholder": "Explain why the picture should be deleted", + "report": { + "blur_excess": "To much is blurred, making the picture useless", + "blur_missing": "A face or license plate is not blurred in this picture", + "copyright": "The picture contains copyrighted content", + "inappropriate": "This picture is inappropriate (it contains nudity, calls for hate or is not streetview)", + "mislocated": "The picture is from a different location", + "other": "Another reason, please specify", + "picture_low_quality": "The picture is of low quality", + "privacy": "The picture shows a private property" + }, + "requestDeletion": "Request picture deletion", + "title": "Why should this image be permanently deleted?" + }, "pleaseLogin": "Please log in to add a picture", "processing": "The server is processing your image", "respectPrivacy": "Do not upload from Google Maps, Google Streetview or other copyrighted sources.", "toBig": "Your image is too large as it is {actual_size}. Please use images of at most {max_size}", + "unlink": { + "button": "Unlink picture", + "explanation": "By unlinking this image, this picture will not be shown anymore with this object. It will still appear in the nearby-images and possibly other objects.", + "title": "Unlink this image?" + }, "upload": { "failReasons": "You might have lost connection to the internet", "failReasonsAdvanced": "Alternatively, make sure your browser and extensions do not block third-party API's.", diff --git a/package-lock.json b/package-lock.json index 1a2925bce..304e8729c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "opening_hours": "^3.6.0", "osm-auth": "^2.5.0", "osmtogeojson": "^3.0.0-beta.5", - "panoramax-js": "^0.3.10", + "panoramax-js": "^0.4.7", "panzoom": "^9.4.3", "papaparse": "^5.3.1", "pg": "^8.11.3", @@ -16128,9 +16128,9 @@ "license": "MIT" }, "node_modules/panoramax-js": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.3.10.tgz", - "integrity": "sha512-ZI9gH98FB3RFWYy69Evsv6vWA+crwhlsdiY8KiZgXAdVYnW7C1YzuQg/Mls546ZHh8/WHj1GMwfe8w5UU6OcFg==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.4.7.tgz", + "integrity": "sha512-Lai4IXbxQ/sDBUyl11zgoL7D+4s7YErPPgvGjWj5oZJBjsBFMLnai+du8WcVvRYrZNIDKCGk1vPLsmIvFsR4rw==", "dependencies": { "@ogcapi-js/features": "^1.1.1", "@ogcapi-js/shared": "^1.1.1", @@ -32312,9 +32312,9 @@ "version": "1.0.0" }, "panoramax-js": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.3.10.tgz", - "integrity": "sha512-ZI9gH98FB3RFWYy69Evsv6vWA+crwhlsdiY8KiZgXAdVYnW7C1YzuQg/Mls546ZHh8/WHj1GMwfe8w5UU6OcFg==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.4.7.tgz", + "integrity": "sha512-Lai4IXbxQ/sDBUyl11zgoL7D+4s7YErPPgvGjWj5oZJBjsBFMLnai+du8WcVvRYrZNIDKCGk1vPLsmIvFsR4rw==", "requires": { "@ogcapi-js/features": "^1.1.1", "@ogcapi-js/shared": "^1.1.1", diff --git a/package.json b/package.json index 5746d82ae..bcccb10f8 100644 --- a/package.json +++ b/package.json @@ -212,7 +212,7 @@ "opening_hours": "^3.6.0", "osm-auth": "^2.5.0", "osmtogeojson": "^3.0.0-beta.5", - "panoramax-js": "^0.3.10", + "panoramax-js": "^0.4.7", "panzoom": "^9.4.3", "papaparse": "^5.3.1", "pg": "^8.11.3", diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 560839295..6e8dbe4e4 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -1462,6 +1462,10 @@ input[type="range"].range-lg::-moz-range-thumb { margin-right: 4rem; } +.mb-4 { + margin-bottom: 1rem; +} + .mt-4 { margin-top: 1rem; } @@ -1478,10 +1482,6 @@ input[type="range"].range-lg::-moz-range-thumb { margin-bottom: 4rem; } -.mb-4 { - margin-bottom: 1rem; -} - .ml-1 { margin-left: 0.25rem; } @@ -1698,14 +1698,14 @@ input[type="range"].range-lg::-moz-range-thumb { height: 6rem; } -.h-full { - height: 100%; -} - .h-screen { height: 100vh; } +.h-full { + height: 100%; +} + .h-fit { height: -webkit-fit-content; height: -moz-fit-content; @@ -2157,6 +2157,11 @@ input[type="range"].range-lg::-moz-range-thumb { max-width: 100%; } +.max-w-max { + max-width: -webkit-max-content; + max-width: max-content; +} + .max-w-fit { max-width: -webkit-fit-content; max-width: -moz-fit-content; @@ -2576,18 +2581,18 @@ input[type="range"].range-lg::-moz-range-thumb { margin-bottom: calc(0px * var(--tw-space-y-reverse)); } -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); -} - .space-x-2 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.5rem * var(--tw-space-x-reverse)); margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); } +.space-x-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); +} + .space-x-3 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.75rem * var(--tw-space-x-reverse)); @@ -4108,6 +4113,10 @@ input[type="range"].range-lg::-moz-range-thumb { text-align: justify; } +.text-start { + text-align: start; +} + .text-xl { font-size: 1.25rem; line-height: 1.75rem; @@ -5612,12 +5621,6 @@ svg.apply-fill path { /************************* LEGACY MARKER - CLEANUP BELOW ********************************/ -.slideshow-item img { - /* Legacy: should be replace when the image element is ported to Svelte*/ - height: var(--image-carousel-height); - width: unset; -} - .animate-height { /* Legacy: should be replaced by headlessui disclosure in time */ transition: max-height 0.5s ease-in-out; diff --git a/src/Logic/ImageProviders/AllImageProviders.ts b/src/Logic/ImageProviders/AllImageProviders.ts index 3cc966414..19aa6640b 100644 --- a/src/Logic/ImageProviders/AllImageProviders.ts +++ b/src/Logic/ImageProviders/AllImageProviders.ts @@ -66,8 +66,9 @@ export default class AllImageProviders { return AllImageProviders.genericImageProvider } + private static readonly _cachedImageStores: Record> = {} /** - * Tries to extract all image data for this image + * Tries to extract all image data for this image. Cachedon tags?.data?.id */ public static LoadImagesFor( tags: Store>, @@ -76,6 +77,10 @@ export default class AllImageProviders { if (tags?.data?.id === undefined) { return undefined } + const id = tags?.data?.id + if(this._cachedImageStores[id]){ + return this._cachedImageStores[id] + } const source = new UIEventSource([]) const allSources: Store[] = [] @@ -93,6 +98,7 @@ export default class AllImageProviders { source.set(dedup) }) } + this._cachedImageStores[id] = source return source } diff --git a/src/Logic/ImageProviders/ImageProvider.ts b/src/Logic/ImageProviders/ImageProvider.ts index bf9fea781..f4051460e 100644 --- a/src/Logic/ImageProviders/ImageProvider.ts +++ b/src/Logic/ImageProviders/ImageProvider.ts @@ -88,4 +88,12 @@ export default abstract class ImageProvider { }): Promise public abstract apiUrls(): string[] + + public static async offerImageAsDownload(image: ProvidedImage){ + const response = await fetch(image.url_hd ?? image.url) + const blob = await response.blob() + Utils.offerContentsAsDownloadableFile(blob, new URL(image.url).pathname.split("/").at(-1), { + mimetype: "image/jpg", + }) + } } diff --git a/src/Logic/ImageProviders/Panoramax.ts b/src/Logic/ImageProviders/Panoramax.ts index 97c82663d..5560acba5 100644 --- a/src/Logic/ImageProviders/Panoramax.ts +++ b/src/Logic/ImageProviders/Panoramax.ts @@ -138,11 +138,12 @@ export default class PanoramaxImageProvider extends ImageProvider { } return data?.some( (img) => - img?.status !== undefined && img?.status !== "ready" && img?.status !== "broken" + img?.status !== undefined && img?.status !== "ready" && img?.status !== "broken" && img?.status !== "hidden" ) } Stores.Chronic(1500, () => hasLoading(source.data)).addCallback((_) => { + console.log("Testing panoramax URLS again as some were loading", source.data, hasLoading(source.data)) super.getRelevantUrlsFor(tags, prefixes).then((data) => { source.set(data) return !hasLoading(data) @@ -168,6 +169,17 @@ export default class PanoramaxImageProvider extends ImageProvider { public apiUrls(): string[] { return ["https://panoramax.mapcomplete.org", "https://panoramax.xyz"] } + + public static getPanoramaxInstance (host: string){ + host = new URL(host).host + if(new URL(this.defaultPanoramax.host).host === host){ + return this.defaultPanoramax + } + if(new URL(this.xyz.host).host === host){ + return this.xyz + } + return new Panoramax(host) + } } export class PanoramaxUploader implements ImageUploader { diff --git a/src/UI/Base/DotMenu.svelte b/src/UI/Base/DotMenu.svelte index 3eee40139..2f0adb246 100644 --- a/src/UI/Base/DotMenu.svelte +++ b/src/UI/Base/DotMenu.svelte @@ -28,7 +28,7 @@ } -
+