mirror of
https://github.com/iv-org/invidious
synced 2024-11-16 21:25:31 +00:00
HTML: Use new buttons for thumbnail overlays
In addition, this commit also heavily changes the structure of the generic "video card" item. Main benefits: * Improved accessibility for keyboard users * Many styling glitches were fixed * PlaylistVideos now use the same items as the rest * Elements all have distinct CSS classes * Design can be expanded to add more icons
This commit is contained in:
parent
7bd6d0ac49
commit
b6bbfb9b20
@ -152,9 +152,15 @@ body a.pure-button-primary:focus {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
button.pure-button-secondary:hover,
|
||||
button.pure-button-secondary:focus {
|
||||
border-color: rgba(0, 182, 240, 1);
|
||||
.pure-button-secondary:hover,
|
||||
.pure-button-secondary:focus {
|
||||
color: rgb(0, 182, 240);
|
||||
border-color: rgb(0, 182, 240);
|
||||
}
|
||||
|
||||
.pure-button-secondary.low-profile {
|
||||
padding: 5px 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
@ -163,21 +169,19 @@ button.pure-button-secondary:focus {
|
||||
*/
|
||||
|
||||
div.thumbnail {
|
||||
padding: 28.125%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
img.thumbnail {
|
||||
position: absolute;
|
||||
display: block; /* See: https://stackoverflow.com/a/11635197 */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
div.watched-overlay {
|
||||
z-index: 50;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -195,28 +199,27 @@ div.watched-indicator {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.length {
|
||||
div.thumbnail > .top-left-overlay,
|
||||
div.thumbnail > .bottom-right-overlay {
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
background-color: rgba(35, 35, 35, 0.75);
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
padding: 2px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
right: 0.25em;
|
||||
bottom: -0.75em;
|
||||
}
|
||||
|
||||
.watched {
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
background-color: rgba(35, 35, 35, 0.75);
|
||||
.top-left-overlay { top: 0.6em; left: 0.6em; }
|
||||
.bottom-right-overlay { bottom: 0.6em; right: 0.6em; }
|
||||
|
||||
.length {
|
||||
padding: 1px;
|
||||
margin: -2px 0;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
padding: 4px 8px 4px 8px;
|
||||
font-size: 16px;
|
||||
left: 0.2em;
|
||||
top: -0.7em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.length, .top-left-overlay button {
|
||||
background-color: rgba(35, 35, 35, 0.85);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<a href="/channel/<%= item.ucid %>">
|
||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||
<center>
|
||||
<img loading="lazy" tabindex="-1" style="width:56.25%" src="/ggpht<%= URI.parse(item.author_thumbnail).request_target.gsub(/=s\d+/, "=s176") %>" alt="" />
|
||||
<img loading="lazy" style="width:56.25%" src="/ggpht<%= URI.parse(item.author_thumbnail).request_target.gsub(/=s\d+/, "=s176") %>" alt="" />
|
||||
</center>
|
||||
<% end %>
|
||||
<p dir="auto"><%= HTML.escape(item.author) %><% if !item.author_verified.nil? && item.author_verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></p>
|
||||
@ -25,7 +25,7 @@
|
||||
<a style="width:100%" href="<%= url %>">
|
||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||
<div class="thumbnail">
|
||||
<img loading="lazy" tabindex="-1" class="thumbnail" src="<%= URI.parse(item.thumbnail || "/").request_target %>" alt="" />
|
||||
<img loading="lazy" class="thumbnail" src="<%= URI.parse(item.thumbnail || "/").request_target %>" alt="" />
|
||||
<p class="length"><%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
@ -38,7 +38,7 @@
|
||||
<a href="/watch?v=<%= item.id %>&list=<%= item.rdid %>">
|
||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||
<div class="thumbnail">
|
||||
<img loading="lazy" tabindex="-1" class="thumbnail" src="/vi/<%= item.id %>/mqdefault.jpg" alt="" />
|
||||
<img loading="lazy" class="thumbnail" src="/vi/<%= item.id %>/mqdefault.jpg" alt="" />
|
||||
<% if item.length_seconds != 0 %>
|
||||
<p class="length"><%= recode_length_seconds(item.length_seconds) %></p>
|
||||
<% end %>
|
||||
@ -54,104 +54,79 @@
|
||||
<a href="/channel/<%= item.ucid %>">
|
||||
<p dir="auto"><b><%= HTML.escape(item.author) %></b></p>
|
||||
</a>
|
||||
<% when PlaylistVideo %>
|
||||
<a style="width:100%" href="/watch?v=<%= item.id %>&list=<%= item.plid %>&index=<%= item.index %>">
|
||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||
<div class="thumbnail">
|
||||
<img loading="lazy" tabindex="-1" class="thumbnail" src="/vi/<%= item.id %>/mqdefault.jpg" alt="" />
|
||||
|
||||
<% if plid_form = env.get?("remove_playlist_items") %>
|
||||
<form data-onsubmit="return_false" action="/playlist_ajax?action_remove_video=1&set_video_id=<%= item.index %>&playlist_id=<%= plid_form %>&referer=<%= env.get("current_page") %>" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
|
||||
<p class="watched">
|
||||
<button type="submit" style="all:unset" data-onclick="remove_playlist_item" data-index="<%= item.index %>" data-plid="<%= plid_form %>"><i class="icon ion-md-trash"></i></button>
|
||||
</p>
|
||||
</form>
|
||||
<% end %>
|
||||
|
||||
<% if item.responds_to?(:live_now) && item.live_now %>
|
||||
<p class="length"><i class="icon ion-ios-play-circle"></i> <%= translate(locale, "LIVE") %></p>
|
||||
<% elsif item.length_seconds != 0 %>
|
||||
<p class="length"><%= recode_length_seconds(item.length_seconds) %></p>
|
||||
<% end %>
|
||||
|
||||
<% if item_watched %>
|
||||
<div class="watched-overlay"></div>
|
||||
<div class="watched-indicator" data-length="<%= item.length_seconds %>" data-id="<%= item.id %>"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<p dir="auto"><%= HTML.escape(item.title) %></p>
|
||||
</a>
|
||||
|
||||
<div class="video-card-row flexible">
|
||||
<div class="flex-left"><a href="/channel/<%= item.ucid %>">
|
||||
<p class="channel-name" dir="auto"><%= HTML.escape(item.author) %></p>
|
||||
</a></div>
|
||||
<% endpoint_params = "?v=#{item.id}&list=#{item.plid}" %>
|
||||
<%= rendered "components/video-context-buttons" %>
|
||||
</div>
|
||||
|
||||
<div class="video-card-row flexible">
|
||||
<div class="flex-left">
|
||||
<% if item.responds_to?(:premiere_timestamp) && item.premiere_timestamp.try &.> Time.utc %>
|
||||
<p dir="auto"><%= translate(locale, "Premieres in `x`", recode_date((item.premiere_timestamp.as(Time) - Time.utc).ago, locale)) %></p>
|
||||
<% elsif Time.utc - item.published > 1.minute %>
|
||||
<p dir="auto"><%= translate(locale, "Shared `x` ago", recode_date(item.published, locale)) %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if item.responds_to?(:views) && item.views %>
|
||||
<div class="flex-right">
|
||||
<p dir="auto"><%= translate_count(locale, "generic_views_count", item.views || 0, NumberFormatting::Short) %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% when Category %>
|
||||
<% else %>
|
||||
<a style="width:100%" href="/watch?v=<%= item.id %>">
|
||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||
<div class="thumbnail">
|
||||
<img loading="lazy" tabindex="-1" class="thumbnail" src="/vi/<%= item.id %>/mqdefault.jpg" alt="" />
|
||||
<% if env.get? "show_watched" %>
|
||||
<form data-onsubmit="return_false" action="/watch_ajax?action_mark_watched=1&id=<%= item.id %>&referer=<%= env.get("current_page") %>" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
|
||||
<p class="watched">
|
||||
<button type="submit" style="all:unset" data-onclick="mark_watched" data-id="<%= item.id %>">
|
||||
<i data-mouse="switch_classes" data-switch-classes="ion-ios-eye-off,ion-ios-eye" class="icon ion-ios-eye"></i>
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
<% elsif plid_form = env.get? "add_playlist_items" %>
|
||||
<form data-onsubmit="return_false" action="/playlist_ajax?action_add_video=1&video_id=<%= item.id %>&playlist_id=<%= plid_form %>&referer=<%= env.get("current_page") %>" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
|
||||
<p class="watched">
|
||||
<button type="submit" style="all:unset" data-onclick="add_playlist_item" data-id="<%= item.id %>" data-plid="<%= plid_form %>"><i class="icon ion-md-add"></i></button>
|
||||
</p>
|
||||
</form>
|
||||
<% end %>
|
||||
<%-
|
||||
# `endpoint_params` is used for the "video-context-buttons" component
|
||||
if item.is_a?(PlaylistVideo)
|
||||
link_url = "/watch?v=#{item.id}&list=#{item.plid}&index=#{item.index}"
|
||||
endpoint_params = "?v=#{item.id}&list=#{item.plid}"
|
||||
else
|
||||
link_url = "/watch?v=#{item.id}"
|
||||
endpoint_params = "?v=#{item.id}"
|
||||
end
|
||||
-%>
|
||||
|
||||
<% if item.responds_to?(:live_now) && item.live_now %>
|
||||
<p class="length" dir="auto"><i class="icon ion-ios-play-circle"></i> <%= translate(locale, "LIVE") %></p>
|
||||
<% elsif item.length_seconds != 0 %>
|
||||
<p class="length"><%= recode_length_seconds(item.length_seconds) %></p>
|
||||
<% end %>
|
||||
<div class="thumbnail">
|
||||
<%- if !env.get("preferences").as(Preferences).thin_mode -%>
|
||||
<a tabindex="-1" href="<%= link_url %>">
|
||||
<img loading="lazy" class="thumbnail" src="/vi/<%= item.id %>/mqdefault.jpg" alt="" />
|
||||
</a>
|
||||
<%- end -%>
|
||||
|
||||
<% if item_watched %>
|
||||
<div class="watched-overlay"></div>
|
||||
<div class="watched-indicator" data-length="<%= item.length_seconds %>" data-id="<%= item.id %>"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="top-left-overlay">
|
||||
<%- if env.get? "show_watched" -%>
|
||||
<form data-onsubmit="return_false" action="/watch_ajax?action_mark_watched=1&id=<%= item.id %>&referer=<%= env.get("current_page") %>" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
|
||||
<button type="submit" class="pure-button pure-button-secondary low-profile"
|
||||
data-onclick="mark_watched" data-id="<%= item.id %>">
|
||||
<i data-mouse="switch_classes" data-switch-classes="ion-ios-eye-off,ion-ios-eye" class="icon ion-ios-eye"></i>
|
||||
</button>
|
||||
</form>
|
||||
<%- end -%>
|
||||
|
||||
<%- if plid_form = env.get?("add_playlist_items") -%>
|
||||
<%- form_parameters = "action_add_video=1&video_id=#{item.id}&playlist_id=#{plid_form}&referer=#{env.get("current_page")}" -%>
|
||||
<form data-onsubmit="return_false" action="/playlist_ajax?<%= form_parameters %>" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
|
||||
<button type="submit" class="pure-button pure-button-secondary low-profile"
|
||||
data-onclick="add_playlist_item" data-id="<%= item.id %>" data-plid="<%= plid_form %>"><i class="icon ion-md-add"></i></button>
|
||||
</form>
|
||||
<%- elsif item.is_a?(PlaylistVideo) && (plid_form = env.get?("remove_playlist_items")) -%>
|
||||
<%- form_parameters = "action_remove_video=1&set_video_id=#{item.index}&playlist_id=#{plid_form}&referer=#{env.get("current_page")}" -%>
|
||||
<form data-onsubmit="return_false" action="/playlist_ajax?<%= form_parameters %>" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
|
||||
<button type="submit" class="pure-button pure-button-secondary low-profile"
|
||||
data-onclick="remove_playlist_item" data-index="<%= item.index %>" data-plid="<%= plid_form %>"><i class="icon ion-md-trash"></i></button>
|
||||
</form>
|
||||
<%- end -%>
|
||||
</div>
|
||||
|
||||
<div class="bottom-right-overlay">
|
||||
<%- if item.responds_to?(:live_now) && item.live_now -%>
|
||||
<p class="length" dir="auto"><i class="icon ion-ios-play-circle"></i> <%= translate(locale, "LIVE") %></p>
|
||||
<%- elsif item.length_seconds != 0 -%>
|
||||
<p class="length"><%= recode_length_seconds(item.length_seconds) %></p>
|
||||
<%- end -%>
|
||||
</div>
|
||||
|
||||
<% if item_watched %>
|
||||
<div class="watched-overlay"></div>
|
||||
<div class="watched-indicator" data-length="<%= item.length_seconds %>" data-id="<%= item.id %>"></div>
|
||||
<% end %>
|
||||
<p dir="auto"><%= HTML.escape(item.title) %></p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="video-card-row">
|
||||
<a href="<%= link_url %>"><p dir="auto"><%= HTML.escape(item.title) %></p></a>
|
||||
</div>
|
||||
|
||||
<div class="video-card-row flexible">
|
||||
<div class="flex-left"><a href="/channel/<%= item.ucid %>">
|
||||
<p class="channel-name" dir="auto"><%= HTML.escape(item.author) %><% if !item.is_a?(ChannelVideo) && !item.author_verified.nil? && item.author_verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></p>
|
||||
<p class="channel-name" dir="auto"><%= HTML.escape(item.author) %>
|
||||
<%- if item.responds_to?(:author_verified) && item.author_verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end -%>
|
||||
</p>
|
||||
</a></div>
|
||||
|
||||
<% endpoint_params = "?v=#{item.id}" %>
|
||||
<%= rendered "components/video-context-buttons" %>
|
||||
</div>
|
||||
|
||||
|
@ -35,12 +35,14 @@
|
||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||
<div class="thumbnail">
|
||||
<img class="thumbnail" src="/vi/<%= item %>/mqdefault.jpg" alt="" />
|
||||
|
||||
<div class="top-left-overlay"><div class="watched">
|
||||
<form data-onsubmit="return_false" action="/watch_ajax?action_mark_unwatched=1&id=<%= item %>&referer=<%= env.get("current_page") %>" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<%= URI.encode_www_form(env.get?("csrf_token").try &.as(String) || "") %>">
|
||||
<p class="watched">
|
||||
<button type="submit" style="all:unset" data-onclick="mark_unwatched" data-id="<%= item %>"><i class="icon ion-md-trash"></i></button>
|
||||
</p>
|
||||
<button type="submit" class="pure-button pure-button-secondary low-profile"
|
||||
data-onclick="mark_unwatched" data-id="<%= item %>"><i class="icon ion-md-trash"></i></button>
|
||||
</form>
|
||||
</div></div>
|
||||
</div>
|
||||
<p></p>
|
||||
<% end %>
|
||||
|
Loading…
Reference in New Issue
Block a user