From 0f01a8eda5655926eac53d0f5805341d5b0cb753 Mon Sep 17 00:00:00 2001 From: chand1012 Date: Wed, 15 May 2024 20:04:08 -0400 Subject: [PATCH 1/3] Add search box --- README.md | 1 + docs/configuration.md | 33 +++++++++++++++ docs/images/search-widget-preview.png | Bin 0 -> 39677 bytes internal/assets/static/main.css | 56 ++++++++++++++++++++++++++ internal/assets/templates.go | 1 + internal/assets/templates/search.html | 18 +++++++++ internal/widget/search.go | 30 ++++++++++++++ internal/widget/widget.go | 2 + 8 files changed, 141 insertions(+) create mode 100644 docs/images/search-widget-preview.png create mode 100644 internal/assets/templates/search.html create mode 100644 internal/widget/search.go diff --git a/README.md b/README.md index 715c8e5..7baa9a4 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ * GitHub releases * Repository overview * Site monitor +* Search box #### Themeable ![multiple color schemes example](docs/images/themes-example.png) diff --git a/docs/configuration.md b/docs/configuration.md index e698fdd..40938a6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -21,6 +21,7 @@ - [Twitch Channels](#twitch-channels) - [Twitch Top Games](#twitch-top-games) - [iframe](#iframe) + - [Search](#search) ## Intro Configuration is done via a single YAML file and a server restart is required in order for any changes to take effect. Trying to start the server with an invalid config file will result in an error. @@ -1132,3 +1133,35 @@ The source of the iframe. ##### `height` The height of the iframe. The minimum allowed height is 50. + +### Search +Display a search bar that can be used to search for specific terms on various search engines. + +Example: + +```yaml +- type: search + search-url: https://www.google.com/search?q= + query: This is a default search +``` + +Preview: + +![](images/search-widget-preview.png) + +#### Properties +| Name | Type | Required | Default | +| ---- | ---- | -------- | ------- | +| search-url | string | no | https://duckduckgo.com/?q= | +| query | string | no | | + +##### `search-url` +The URL to use for the search. The query will be appended to the end of the URL. Some common examples: +- Google: `https://www.google.com/search?q=` +- DuckDuckGo: `https://duckduckgo.com/?q=` +- Bing: `https://www.bing.com/search?q=` +- Perplexity AI: `https://perplexity.ai/search?q=` +- ChatGPT (requires ChatGPT Plus subscription): `https://chatgpt.com/?model=gpt-4o&oai-dm=1&q=` + +##### `query` +The default query to show in the search bar. If left blank the search bar will be empty. diff --git a/docs/images/search-widget-preview.png b/docs/images/search-widget-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..c058401cc0a34ef76e6c9a3b3f58fe812b62a255 GIT binary patch literal 39677 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 +{{ define "widget-content" }} +
+
+ + +
+
+{{ end }} diff --git a/internal/widget/search.go b/internal/widget/search.go new file mode 100644 index 0000000..1786ee1 --- /dev/null +++ b/internal/widget/search.go @@ -0,0 +1,30 @@ +package widget + +import ( + "html/template" + + "github.com/glanceapp/glance/internal/assets" +) + +type Search struct { + widgetBase `yaml:",inline"` + SearchURL string `yaml:"search-url"` + Query string `yaml:"query"` +} + +func (widget *Search) Initialize() error { + widget.withTitle("Search").withError(nil) + + if widget.SearchURL == "" { + // set to the duckduckgo search engine + widget.SearchURL = "https://duckduckgo.com/?q=" + } + + // if no query is provided, leave an empty string + + return nil +} + +func (widget *Search) Render() template.HTML { + return widget.render(widget, assets.SearchTemplate) +} diff --git a/internal/widget/widget.go b/internal/widget/widget.go index 3707b7e..17b4f87 100644 --- a/internal/widget/widget.go +++ b/internal/widget/widget.go @@ -45,6 +45,8 @@ func New(widgetType string) (Widget, error) { return &TwitchChannels{}, nil case "repository": return &Repository{}, nil + case "search": + return &Search{}, nil default: return nil, fmt.Errorf("unknown widget type: %s", widgetType) } From 8392b7a60634c3fcdacfdffc5c252ea53c726f2d Mon Sep 17 00:00:00 2001 From: chand1012 Date: Fri, 17 May 2024 10:18:58 -0400 Subject: [PATCH 2/3] Fix some styling issues and query bug --- internal/assets/static/main.css | 8 +++++++- internal/assets/templates/search.html | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/assets/static/main.css b/internal/assets/static/main.css index a5b8acb..1f8b442 100644 --- a/internal/assets/static/main.css +++ b/internal/assets/static/main.css @@ -1221,12 +1221,13 @@ body { .search-input { width: 100%; padding: 10px 40px 10px 10px; - font-size: var(--font-size-h3); + font-size: var(--font-size-h2); border: 1px solid var(--color-widget-content-border); border-radius: 20px; color: white; background: var(--color-background); transition: border-color 0.15s ease; + font-family: 'JetBrains Mono', monospace; } .search-input:focus { @@ -1234,6 +1235,11 @@ body { border-color: var(--color-primary); } +.search-input:placeholder-shown { + color: var(--color-text-subdue); + font-family: 'JetBrains Mono', monospace; +} + .search-button { position: absolute; right: 10px; diff --git a/internal/assets/templates/search.html b/internal/assets/templates/search.html index be70575..211ed0c 100644 --- a/internal/assets/templates/search.html +++ b/internal/assets/templates/search.html @@ -3,7 +3,7 @@ {{ define "widget-content" }}
- + -
-
+ {{ end }} diff --git a/internal/widget/search.go b/internal/widget/search.go index 1786ee1..9cfd64e 100644 --- a/internal/widget/search.go +++ b/internal/widget/search.go @@ -1,30 +1,66 @@ package widget import ( + "fmt" "html/template" + "strings" "github.com/glanceapp/glance/internal/assets" ) +type SearchBang struct { + Title string + Shortcut string + URL string +} + type Search struct { - widgetBase `yaml:",inline"` - SearchURL string `yaml:"search-url"` - Query string `yaml:"query"` + widgetBase `yaml:",inline"` + cachedHTML template.HTML `yaml:"-"` + SearchEngine string `yaml:"search-engine"` + Bangs []SearchBang `yaml:"bangs"` +} + +func convertSearchUrl(url string) string { + // Go's template is being stubborn and continues to escape the curlies in the + // URL regardless of what the type of the variable is so this is my way around it + return strings.ReplaceAll(url, "{QUERY}", "!QUERY!") +} + +var searchEngines = map[string]string{ + "duckduckgo": "https://duckduckgo.com/?q={QUERY}", + "google": "https://www.google.com/search?q={QUERY}", } func (widget *Search) Initialize() error { widget.withTitle("Search").withError(nil) - if widget.SearchURL == "" { - // set to the duckduckgo search engine - widget.SearchURL = "https://duckduckgo.com/?q=" + if widget.SearchEngine == "" { + widget.SearchEngine = "duckduckgo" } - // if no query is provided, leave an empty string + if url, ok := searchEngines[widget.SearchEngine]; ok { + widget.SearchEngine = url + } + widget.SearchEngine = convertSearchUrl(widget.SearchEngine) + + for i := range widget.Bangs { + if widget.Bangs[i].Shortcut == "" { + return fmt.Errorf("Search bang %d has no shortcut", i+1) + } + + if widget.Bangs[i].URL == "" { + return fmt.Errorf("Search bang %d has no URL", i+1) + } + + widget.Bangs[i].URL = convertSearchUrl(widget.Bangs[i].URL) + } + + widget.cachedHTML = widget.render(widget, assets.SearchTemplate) return nil } func (widget *Search) Render() template.HTML { - return widget.render(widget, assets.SearchTemplate) + return widget.cachedHTML }