diff --git a/assets/css/carousel.css b/assets/css/carousel.css new file mode 100644 index 00000000..4bae92e5 --- /dev/null +++ b/assets/css/carousel.css @@ -0,0 +1,119 @@ +/* +Copyright (c) 2024 by Jennifer (https://codepen.io/jwjertzoch/pen/JjyGeRy) + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall +be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +.carousel { + margin: 0 auto; + overflow: hidden; + text-align: center; +} + +.slides { + width: 100%; + display: flex; + overflow-x: scroll; + scrollbar-width: none; + scroll-snap-type: x mandatory; + scroll-behavior: smooth; +} + +.slides::-webkit-scrollbar { + display: none; +} + +.slides-item { + align-items: center; + border-radius: 10px; + display: flex; + flex-shrink: 0; + font-size: 100px; + height: 600px; + justify-content: center; + margin: 0 1rem; + position: relative; + scroll-snap-align: start; + transform: scale(1); + transform-origin: center center; + transition: transform .5s; + width: 100%; +} + +.carousel__nav { + padding: 1.25rem .5rem; +} + +.slider-nav { + align-items: center; + background-color: #ddd; + border-radius: 50%; + color: #000; + display: inline-flex; + height: 1.5rem; + justify-content: center; + padding: .5rem; + position: relative; + text-decoration: none; + width: 1.5rem; +} + +.skip-link { + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} + +.skip-link:focus { + align-items: center; + background-color: #000; + color: #fff; + display: flex; + font-size: 30px; + height: 30px; + justify-content: center; + opacity: .8; + text-decoration: none; + width: 50%; + z-index: 1; +} + +.light-theme .slider-nav { + background-color: #ddd; +} + +.dark-theme .slider-nav { + background-color: #0005; +} + +@media (prefers-color-scheme: light) { + .no-theme .slider-nav { + background-color: #ddd; + } +} + +@media (prefers-color-scheme: dark) { + .no-theme .slider-nav { + background-color: #0005; + } +} diff --git a/locales/en-US.json b/locales/en-US.json index da83767c..10887612 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -493,5 +493,8 @@ "channel_tab_playlists_label": "Playlists", "channel_tab_community_label": "Community", "channel_tab_channels_label": "Channels", - "toggle_theme": "Toggle Theme" + "toggle_theme": "Toggle Theme", + "carousel_slide": "Slide {{current}} of {{total}}", + "carousel_skip": "Skip the Carousel", + "carousel_go_to": "Go to slide `x`" } diff --git a/src/invidious/frontend/comments_youtube.cr b/src/invidious/frontend/comments_youtube.cr index ecc0bc1b..aecac87f 100644 --- a/src/invidious/frontend/comments_youtube.cr +++ b/src/invidious/frontend/comments_youtube.cr @@ -107,6 +107,36 @@ module Invidious::Frontend::Comments END_HTML end + when "multiImage" + html << <<-END_HTML + + #{translate(locale, "carousel_skip")} + + END_HTML + image_array = attachment["images"].as_a + + image_array.each_index do |i| + html << <<-END_HTML + (i + 1).to_s, "total" => image_array.size.to_s})}" tabindex="0"> + + + END_HTML + end + + html << <<-END_HTML + + + END_HTML + attachment["images"].as_a.each_index do |i| + html << <<-END_HTML + #{i + 1} + END_HTML + end + html << <<-END_HTML + + + + END_HTML else nil # Ignore end end diff --git a/src/invidious/helpers/i18n.cr b/src/invidious/helpers/i18n.cr index 76e477a4..23a1aafc 100644 --- a/src/invidious/helpers/i18n.cr +++ b/src/invidious/helpers/i18n.cr @@ -78,7 +78,7 @@ def load_all_locales return locales end -def translate(locale : String?, key : String, text : String | Nil = nil) : String +def translate(locale : String?, key : String, text : String | Hash(String, String) | Nil = nil) : String # Log a warning if "key" doesn't exist in en-US locale and return # that key as the text, so this is more or less transparent to the user. if !LOCALES["en-US"].has_key?(key) @@ -101,10 +101,12 @@ def translate(locale : String?, key : String, text : String | Nil = nil) : Strin match_length = 0 raw_data.as_h.each do |hash_key, value| - if md = text.try &.match(/#{hash_key}/) - if md[0].size >= match_length - translation = value.as_s - match_length = md[0].size + if text.is_a?(String) + if md = text.try &.match(/#{hash_key}/) + if md[0].size >= match_length + translation = value.as_s + match_length = md[0].size + end end end end @@ -114,8 +116,13 @@ def translate(locale : String?, key : String, text : String | Nil = nil) : Strin raise "Invalid translation \"#{raw_data}\"" end - if text + if text.is_a?(String) translation = translation.gsub("`x`", text) + elsif text.is_a?(Hash(String, String)) + # adds support for multi string interpolation. Based on i18next https://www.i18next.com/translation-function/interpolation#basic + text.each_key do |hash_key| + translation = translation.gsub("{{#{hash_key}}}", text[hash_key]) + end end return translation diff --git a/src/invidious/views/template.ecr b/src/invidious/views/template.ecr index 5623bf77..9904b4fc 100644 --- a/src/invidious/views/template.ecr +++ b/src/invidious/views/template.ecr @@ -21,6 +21,7 @@ +