From c309856f74220baf9f70cf9f4d1f17eba70ea763 Mon Sep 17 00:00:00 2001 From: advplyr Date: Sat, 29 Jun 2024 16:15:55 -0500 Subject: [PATCH] Update:Media item share modal UI/UX and localization #1768 --- client/components/modals/ShareModal.vue | 46 ++++++++++++++----------- client/components/ui/TextInput.vue | 36 +++++++++++++++++-- client/pages/item/_id/index.vue | 2 +- client/pages/share/_slug.vue | 9 +++-- client/strings/en-us.json | 9 +++++ 5 files changed, 76 insertions(+), 26 deletions(-) diff --git a/client/components/modals/ShareModal.vue b/client/components/modals/ShareModal.vue index 8f3ab9dc..dc781a74 100644 --- a/client/components/modals/ShareModal.vue +++ b/client/components/modals/ShareModal.vue @@ -2,44 +2,45 @@
@@ -72,15 +73,15 @@ export default { shareDurationUnit: 'minutes', durationUnits: [ { - text: 'Minutes', + text: this.$strings.LabelMinutes, value: 'minutes' }, { - text: 'Hours', + text: this.$strings.LabelHours, value: 'hours' }, { - text: 'Days', + text: this.$strings.LabelDays, value: 'days' } ] @@ -116,15 +117,20 @@ export default { }, currentShareTimeRemaining() { if (!this.currentShare) return 'Error' - if (!this.currentShare.expiresAt) return 'Permanent' + if (!this.currentShare.expiresAt) return this.$strings.LabelPermanent const msRemaining = new Date(this.currentShare.expiresAt).valueOf() - Date.now() if (msRemaining <= 0) return 'Expired' - return this.$elapsedPretty(msRemaining / 1000, true) + return this.$elapsedPrettyExtended(msRemaining / 1000, true, false) }, expireDurationSeconds() { let shareDuration = Number(this.newShareDuration) if (!shareDuration || isNaN(shareDuration)) return 0 return this.newShareDuration * (this.shareDurationUnit === 'minutes' ? 60 : this.shareDurationUnit === 'hours' ? 3600 : 86400) + }, + expirationDateString() { + if (!this.expireDurationSeconds) return this.$strings.LabelPermanent + const dateMs = Date.now() + this.expireDurationSeconds * 1000 + return this.$formatDatetime(dateMs, this.$store.state.serverSettings.dateFormat, this.$store.state.serverSettings.timeFormat) } }, methods: { diff --git a/client/components/ui/TextInput.vue b/client/components/ui/TextInput.vue index 462118f0..04bdfab9 100644 --- a/client/components/ui/TextInput.vue +++ b/client/components/ui/TextInput.vue @@ -1,12 +1,33 @@ @@ -34,6 +55,7 @@ export default { clearable: Boolean, inputId: String, inputName: String, + showCopy: Boolean, step: [String, Number], min: [String, Number] }, @@ -41,7 +63,8 @@ export default { return { showPassword: false, isHovering: false, - isFocused: false + isFocused: false, + hasCopied: false } }, computed: { @@ -67,6 +90,15 @@ export default { } }, methods: { + copyToClipboard() { + if (this.hasCopied) return + this.$copyToClipboard(this.inputValue).then((success) => { + this.hasCopied = success + setTimeout(() => { + this.hasCopied = false + }, 2000) + }) + }, clear() { this.inputValue = '' this.$emit('clear') diff --git a/client/pages/item/_id/index.vue b/client/pages/item/_id/index.vue index 8267e6c6..92f1c213 100644 --- a/client/pages/item/_id/index.vue +++ b/client/pages/item/_id/index.vue @@ -442,7 +442,7 @@ export default { if (this.userIsAdminOrUp && !this.isPodcast) { items.push({ - text: 'Share', + text: this.$strings.LabelShare, action: 'share' }) } diff --git a/client/pages/share/_slug.vue b/client/pages/share/_slug.vue index 9f58d21d..4878481c 100644 --- a/client/pages/share/_slug.vue +++ b/client/pages/share/_slug.vue @@ -2,11 +2,11 @@
-
+
-

{{ mediaItemShare.playbackSession.displayTitle || 'No title' }}

-

{{ mediaItemShare.playbackSession.displayAuthor }}

+

{{ mediaItemShare.playbackSession.displayTitle || 'No title' }}

+

{{ mediaItemShare.playbackSession.displayAuthor }}

@@ -79,6 +79,9 @@ export default { const coverAspectRatio = this.playbackSession.coverAspectRatio return coverAspectRatio === this.$constants.BookCoverAspectRatio.STANDARD ? 1.6 : 1 }, + isMobileLandscape() { + return this.windowWidth > this.windowHeight && this.windowHeight < 450 + }, coverWidth() { const availableCoverWidth = Math.min(450, this.windowWidth - 32) const availableCoverHeight = Math.min(450, this.windowHeight - 250) diff --git a/client/strings/en-us.json b/client/strings/en-us.json index d4d40650..b28b5e33 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -258,6 +258,7 @@ "LabelCurrently": "Currently:", "LabelCustomCronExpression": "Custom Cron Expression:", "LabelDatetime": "Datetime", + "LabelDays": "Days", "LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)", "LabelDescription": "Description", "LabelDeselectAll": "Deselect All", @@ -321,6 +322,7 @@ "LabelHighestPriority": "Highest priority", "LabelHost": "Host", "LabelHour": "Hour", + "LabelHours": "Hours", "LabelIcon": "Icon", "LabelImageURLFromTheWeb": "Image URL from the web", "LabelInProgress": "In Progress", @@ -371,6 +373,7 @@ "LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources", "LabelMetadataProvider": "Metadata Provider", "LabelMinute": "Minute", + "LabelMinutes": "Minutes", "LabelMissing": "Missing", "LabelMissingEbook": "Has no ebook", "LabelMissingSupplementaryEbook": "Has no supplementary ebook", @@ -410,6 +413,7 @@ "LabelOverwrite": "Overwrite", "LabelPassword": "Password", "LabelPath": "Path", + "LabelPermanent": "Permanent", "LabelPermissionsAccessAllLibraries": "Can Access All Libraries", "LabelPermissionsAccessAllTags": "Can Access All Tags", "LabelPermissionsAccessExplicitContent": "Can Access Explicit Content", @@ -507,6 +511,8 @@ "LabelSettingsStoreMetadataWithItem": "Store metadata with item", "LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders", "LabelSettingsTimeFormat": "Time Format", + "LabelShare": "Share", + "LabelShareURL": "Share URL", "LabelShowAll": "Show All", "LabelShowSeconds": "Show seconds", "LabelSize": "Size", @@ -716,6 +722,9 @@ "MessageSelected": "{0} selected", "MessageServerCouldNotBeReached": "Server could not be reached", "MessageSetChaptersFromTracksDescription": "Set chapters using each audio file as a chapter and chapter title as the audio file name", + "MessageShareExpirationWillBe": "Expiration will be {0}", + "MessageShareExpiresIn": "Expires in {0}", + "MessageShareURLWillBe": "Share URL will be {0}", "MessageStartPlaybackAtTime": "Start playback for \"{0}\" at {1}?", "MessageThinking": "Thinking...", "MessageUploaderItemFailed": "Failed to upload",