Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: grid-cards style for twitch channels widget #232

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,9 @@ Preview:
| ---- | ---- | -------- | ------- |
| channels | array | yes | |
| collapse-after | integer | no | 5 |
| collapse-after-rows | integer | no | 4 |
| style | string | no | |
| show-offline | boolean | no | false |
| sort-by | string | no | viewers |

##### `channels`
Expand All @@ -1596,6 +1599,15 @@ A list of channels to display.
##### `collapse-after`
How many channels are visible before the "SHOW MORE" button appears. Set to `-1` to never collapse.

##### `collapse-after-rows`
Specify the number of rows to show when using the `grid-cards` style before the "SHOW MORE" button appears.

##### `style`
Used to change the appearance of the widget. Possible values are `grid-cards`.

##### `show-offline`


##### `sort-by`
Can be used to specify the order in which the channels are displayed. Possible values are `viewers` and `live`.

Expand Down
1 change: 1 addition & 0 deletions internal/assets/static/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ details[open] .summary::after {
@container widget (max-width: 850px) { .cards-grid { --cards-per-row: 3; } }
@container widget (max-width: 750px) { .cards-grid { --cards-per-row: 3; } }
@container widget (max-width: 650px) { .cards-grid { --cards-per-row: 2; } }
@container widget (max-width: 300px) { .cards-grid { --cards-per-row: 1; } }

.widget-small-content-bounds {
max-width: 350px;
Expand Down
1 change: 1 addition & 0 deletions internal/assets/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
MonitorTemplate = compileTemplate("monitor.html", "widget-base.html")
TwitchGamesListTemplate = compileTemplate("twitch-games-list.html", "widget-base.html")
TwitchChannelsTemplate = compileTemplate("twitch-channels.html", "widget-base.html")
TwitchChannelsGridTemplate = compileTemplate("twitch-channels-grid.html", "widget-base.html", "twitch-channels-card-contents.html")
RepositoryTemplate = compileTemplate("repository.html", "widget-base.html")
SearchTemplate = compileTemplate("search.html", "widget-base.html")
ExtensionTemplate = compileTemplate("extension.html", "widget-base.html")
Expand Down
32 changes: 32 additions & 0 deletions internal/assets/templates/twitch-channels-card-contents.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{{ define "twitch-channels-card-contents" }}
{{ if .IsLive }}
<img class="video-thumbnail thumbnail" loading="lazy" src="https://static-cdn.jtvnw.net/previews-ttv/live_user_{{ .Login }}-440x248.jpg" alt="" />
{{ end }}
<div class="flex flex-column grow padding-widget">
<div class="{{ if .IsLive }}twitch-channel-live {{ end }}flex gap-10 items-start thumbnail-parent">
<div class="twitch-channel-avatar-container">
<a href="https://twitch.tv/{{ .Login }}" class="twitch-channel-avatar-link" target="_blank" rel="noreferrer" >
<img class="twitch-channel-avatar thumbnail" src="{{ .AvatarUrl }}" alt="{{ .Login }}" loading="lazy"/>
</a>
</div>
<div class="min-width-0">
<a href="https://twitch.tv/{{ .Login }}" class="size-h3{{ if .IsLive }} color-highlight{{ end }} block text-truncate" target="_blank" rel="noreferrer">{{ .Name }}</a>
{{ if .Exists }}
{{ if .IsLive }}
{{ if .Category }}
<a class="text-truncate block" href="https://www.twitch.tv/directory/category/{{ .CategorySlug }}" target="_blank" rel="noreferrer">{{ .Category }}</a>
{{ end }}
<ul class="list-horizontal-text">
<li {{ dynamicRelativeTimeAttrs .LiveSince }}></li>
<li>{{ .ViewersCount | formatViewerCount }} viewers</li>
</ul>
{{ else }}
<div>Offline</div>
{{ end }}
{{ else }}
<div class="color-negative">Not found</div>
{{ end }}
</div>
</div>
</div>
{{ end }}
29 changes: 29 additions & 0 deletions internal/assets/templates/twitch-channels-grid.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{{ template "widget-base.html" . }}
{{ define "widget-content-classes" }}widget-content-frameless{{ end }}
{{ define "widget-content" }}
<div class="flex flex-column">
<div>
<div class="cards-grid collapsible-container" data-collapse-after-rows="{{ .CollapseAfterRows }}">
{{ range .Groups.Online }}
<div class="card widget-content-frame thumbnail-parent">
{{ template "twitch-channels-card-contents" . }}
</div>
{{ end }}
</div>
</div>
{{ if .ShowOffline }}
<div class="margin-top-25">
<div class="widget-header">
<div class="uppercase">Offline Channels</div>
</div>
<div class="cards-grid collapsible-container" data-collapse-after-rows="1">
{{ range .Groups.Offline }}
<div class="card widget-content-frame thumbnail-parent">
{{ template "twitch-channels-card-contents" . }}
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
{{ end }}
10 changes: 10 additions & 0 deletions internal/feed/twitch.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ type TwitchChannel struct {

type TwitchChannels []TwitchChannel

func (channels TwitchChannels) GroupByLive() map[string][]TwitchChannel {
grouped := make(map[string][]TwitchChannel)
statusMap := map[bool]string{true: "Online", false: "Offline"}
for _, channel := range channels {
IsLive := statusMap[channel.IsLive]
grouped[IsLive] = append(grouped[IsLive], channel)
}
return grouped
}

func (channels TwitchChannels) SortByViewers() {
sort.Slice(channels, func(i, j int) bool {
return channels[i].ViewersCount > channels[j].ViewersCount
Expand Down
26 changes: 21 additions & 5 deletions internal/widget/twitch-channels.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ import (
)

type TwitchChannels struct {
widgetBase `yaml:",inline"`
ChannelsRequest []string `yaml:"channels"`
Channels []feed.TwitchChannel `yaml:"-"`
CollapseAfter int `yaml:"collapse-after"`
SortBy string `yaml:"sort-by"`
widgetBase `yaml:",inline"`
ChannelsRequest []string `yaml:"channels"`
Channels []feed.TwitchChannel `yaml:"-"`
Groups map[string][]feed.TwitchChannel `yaml:"-"`
CollapseAfter int `yaml:"collapse-after"`
CollapseAfterRows int `yaml:"collapse-after-rows"`
Style string `yaml:"style"`
SortBy string `yaml:"sort-by"`
ShowOffline bool `yaml:"show-offline"`
}

func (widget *TwitchChannels) Initialize() error {
Expand All @@ -27,6 +31,10 @@ func (widget *TwitchChannels) Initialize() error {
widget.CollapseAfter = 5
}

if widget.CollapseAfterRows == 0 || widget.CollapseAfterRows < -1 {
widget.CollapseAfterRows = 4
}

if widget.SortBy != "viewers" && widget.SortBy != "live" {
widget.SortBy = "viewers"
}
Expand All @@ -46,10 +54,18 @@ func (widget *TwitchChannels) Update(ctx context.Context) {
} else if widget.SortBy == "live" {
channels.SortByLive()
}

if widget.Style == "grid-cards" {
groupedChannels := channels.GroupByLive()
widget.Groups = groupedChannels
}

widget.Channels = channels
}

func (widget *TwitchChannels) Render() template.HTML {
if widget.Style == "grid-cards" {
return widget.render(widget, assets.TwitchChannelsGridTemplate)
}
return widget.render(widget, assets.TwitchChannelsTemplate)
}