diff --git a/reddit/widget.go b/reddit/widget.go index c11ce34..bbc075e 100644 --- a/reddit/widget.go +++ b/reddit/widget.go @@ -25,6 +25,10 @@ type Widget interface { } const ( + widgetKindTextArea = "textarea" + widgetKindButton = "button" + widgetKindImage = "image" + widgetKindCommunityList = "community-list" widgetKindMenu = "menu" widgetKindCommunityDetails = "id-card" widgetKindModerators = "moderators" @@ -55,6 +59,14 @@ func (l *WidgetList) UnmarshalJSON(data []byte) error { var widget Widget switch root.Kind { + case widgetKindTextArea: + widget = new(TextAreaWidget) + case widgetKindButton: + widget = new(ButtonWidget) + case widgetKindImage: + widget = new(ImageWidget) + case widgetKindCommunityList: + widget = new(CommunityListWidget) case widgetKindMenu: widget = new(MenuWidget) case widgetKindCommunityDetails: @@ -87,6 +99,56 @@ type widget struct { Style *WidgetStyle `json:"styles,omitempty"` } +// TextAreaWidget displays a box of text in the subreddit. +type TextAreaWidget struct { + widget + + Name string `json:"shortName,omitempty"` + Text string `json:"text,omitempty"` +} + +func (w *TextAreaWidget) kind() string { + return widgetKindTextArea +} + +// ButtonWidget displays up to 10 button style links with customizable font colors for each button. +type ButtonWidget struct { + widget + + Name string `json:"shortName,omitempty"` + Description string `json:"description,omitempty"` + Buttons []*WidgetButton `json:"buttons,omitempty"` +} + +func (w *ButtonWidget) kind() string { + return widgetKindButton +} + +// ImageWidget display a random image from up to 10 selected images. +// The image can be clickable links. +type ImageWidget struct { + widget + + Name string `json:"shortName,omitempty"` + Images []*WidgetImageLink `json:"data,omitempty"` +} + +func (w *ImageWidget) kind() string { + return widgetKindImage +} + +// CommunityListWidget display a list of up to 10 other communities (subreddits). +type CommunityListWidget struct { + widget + + Name string `json:"shortName,omitempty"` + Communities []*WidgetCommunity `json:"data,omitempty"` +} + +func (w *CommunityListWidget) kind() string { + return widgetKindCommunityList +} + // MenuWidget displays tabs for your community's menu. These can be direct links or submenus that // create a drop-down menu to multiple links. type MenuWidget struct { @@ -216,8 +278,8 @@ func (*CustomWidget) kind() string { // WidgetStyle contains style information for the widget. type WidgetStyle struct { - HeaderColor string `json:"headerColor"` - BackgroundColor string `json:"backgroundColor"` + HeaderColor string `json:"headerColor,omitempty"` + BackgroundColor string `json:"backgroundColor,omitempty"` } // WidgetImage is an image in a widget. @@ -285,6 +347,40 @@ func (l *WidgetLinkList) UnmarshalJSON(data []byte) error { return nil } +// WidgetImageLink is an image that links to an URL within a widget. +type WidgetImageLink struct { + URL string `json:"url,omitempty"` + LinkURL string `json:"linkURL,omitempty"` +} + +// WidgetCommunity is a community (subreddit) that's displayed in a widget. +type WidgetCommunity struct { + Name string `json:"name,omitempty"` + Subscribers int `json:"subscribers"` + Subscribed bool `json:"isSubscribed"` + NSFW bool `json:"isNSFW"` +} + +// WidgetButton is a button that's part of a widget. +type WidgetButton struct { + Text string `json:"text,omitempty"` + URL string `json:"url,omitempty"` + TextColor string `json:"textColor,omitempty"` + FillColor string `json:"fillColor,omitempty"` + // The color of the button's "outline". + StrokeColor string `json:"color,omitempty"` + HoverState *WidgetButtonHoverState `json:"hoverState,omitempty"` +} + +// WidgetButtonHoverState is the behaviour of a button that's part of a widget when it's hovered over with the mouse. +type WidgetButtonHoverState struct { + Text string `json:"text,omitempty"` + TextColor string `json:"textColor,omitempty"` + FillColor string `json:"fillColor,omitempty"` + // The color of the button's "outline". + StrokeColor string `json:"color,omitempty"` +} + // Get the subreddit's widgets. func (s *WidgetService) Get(ctx context.Context, subreddit string) ([]Widget, *Response, error) { path := fmt.Sprintf("r/%s/api/widgets?progressive_images=true", subreddit) diff --git a/reddit/widget_test.go b/reddit/widget_test.go index 897ea68..4159664 100644 --- a/reddit/widget_test.go +++ b/reddit/widget_test.go @@ -10,6 +10,84 @@ import ( ) var expectedWidgets = []Widget{ + &TextAreaWidget{ + widget: widget{ + ID: "widget_15p7borvnnw5a", + Kind: "textarea", + Style: &WidgetStyle{ + HeaderColor: "#373c3f", + BackgroundColor: "#cc5289", + }, + }, + Name: "test title", + Text: "test text", + }, + + &ButtonWidget{ + widget: widget{ + ID: "widget_15paxrbiodp8v", + Kind: "button", + Style: &WidgetStyle{}, + }, + Name: "test text", + Description: "test description", + Buttons: []*WidgetButton{ + { + Text: "test text", + URL: "https://example.com", + TextColor: "#ff66ac", + FillColor: "#014980", + StrokeColor: "#73ad34", + HoverState: &WidgetButtonHoverState{ + Text: "test text", + TextColor: "#000000", + FillColor: "#00a6a5", + StrokeColor: "#000000", + }, + }, + }, + }, + + &ImageWidget{ + widget: widget{ + ID: "widget_15p7o01nqr5tu", + Kind: "image", + Style: &WidgetStyle{}, + }, + Name: "test title", + Images: []*WidgetImageLink{ + { + URL: "https://www.redditstatic.com/image-processing.png", + LinkURL: "https://example.com", + }, + }, + }, + + &CommunityListWidget{ + widget: widget{ + ID: "widget_15p7qwb2kxc6j", + Kind: "community-list", + Style: &WidgetStyle{ + HeaderColor: "#ffb000", + }, + }, + Name: "test title", + Communities: []*WidgetCommunity{ + { + Name: "nba", + Subscribers: 3571840, + Subscribed: true, + NSFW: false, + }, + { + Name: "golang", + Subscribers: 125961, + Subscribed: true, + NSFW: false, + }, + }, + }, + &SubredditRulesWidget{ widget: widget{ ID: "widget_rules-2uquw1", diff --git a/testdata/widget/widgets.json b/testdata/widget/widgets.json index b4596dc..a68562a 100644 --- a/testdata/widget/widgets.json +++ b/testdata/widget/widgets.json @@ -1,5 +1,92 @@ { "items": { + "widget_15p7borvnnw5a": { + "styles": { + "headerColor": "#373c3f", + "backgroundColor": "#cc5289" + }, + "kind": "textarea", + "textHtml": "<!-- SC_OFF --><div class=\"md\"><p>test text</p>\n</div><!-- SC_ON -->", + "text": "test text", + "shortName": "test title", + "id": "widget_15p7borvnnw5a" + }, + "widget_15paxrbiodp8v": { + "styles": { + "headerColor": "", + "backgroundColor": "" + }, + "kind": "button", + "description": "test description", + "buttons": [ + { + "kind": "text", + "hoverState": { + "color": "#000000", + "text": "test text", + "kind": "text", + "textColor": "#000000", + "fillColor": "#00a6a5" + }, + "url": "https://example.com", + "text": "test text", + "color": "#73ad34", + "fillColor": "#014980", + "textColor": "#ff66ac" + } + ], + "descriptionHtml": "<!-- SC_OFF --><div class=\"md\"><p>toto</p>\n</div><!-- SC_ON -->", + "shortName": "test text", + "id": "widget_15paxrbiodp8v" + }, + "widget_15p7o01nqr5tu": { + "styles": { + "headerColor": null, + "backgroundColor": null + }, + "kind": "image", + "data": [ + { + "url": "https://www.redditstatic.com/image-processing.png", + "width": 64, + "linkUrl": "https://example.com", + "height": 64 + } + ], + "shortName": "test title", + "id": "widget_15p7o01nqr5tu" + }, + "widget_15p7qwb2kxc6j": { + "styles": { + "headerColor": "#ffb000", + "backgroundColor": "" + }, + "kind": "community-list", + "data": [ + { + "iconUrl": "https://b.thumbs.redditmedia.com/lh3XYdayDnfF474A_Ro9fBWUViOibSr4BoTpx0ETyvg.png", + "name": "nba", + "subscribers": 3571840, + "primaryColor": "#ffa500", + "isSubscribed": true, + "type": "subreddit", + "communityIcon": "https://styles.redditmedia.com/t5_2qo4s/styles/communityIcon_1podsfdai4301.png?width=256&s=90f8734cee5cfb8e06306013d830d43e31d68f27", + "isNSFW": false + }, + { + "iconUrl": "", + "name": "golang", + "subscribers": 125961, + "primaryColor": "", + "isSubscribed": true, + "type": "subreddit", + "communityIcon": "https://styles.redditmedia.com/t5_2rc7j/styles/communityIcon_wy4riduoe9k11.png?width=256&s=0d681daaa8d4b6271e6be788d0f9379f0661e04a", + "isNSFW": false + } + ], + "shortName": "test title", + "id": "widget_15p7qwb2kxc6j" + }, "widget_15osq4jms4tdo": { "styles": { "headerColor": null,