v0.7.0

glanceapp/glancev0.7.0Feb 9, 2025by svilenmarkov

AI Summary

A major release introducing new widgets (Docker containers, Custom API, Server stats, Split column, Calendar), auto-reload, and extensive configuration enhancements.

Key Highlights

  • New Docker containers widget with label support for organization
  • New Custom API widget for displaying JSON data
  • New Server stats widget for monitoring system resources
  • New Split column widget for multi-column layouts
  • Calendar widget reworked to support user timezone

Breaking Changes

  • Changed Docker config file default location from `/app/glance.yml` to `/app/config/glance.yml`
  • Changed CLI command for config validation from `--check-config` to `config:validate`

New Features

  • Auto reload on config change
  • Environment variables can now be used anywhere in the config
  • Ability to include files in the config using `!include`
  • Custom HTML support in document `<head>`
  • Support for selfh.st and Dashboard icons
  • New styles: Monitor `compact` and Videos `vertical-list`
  • Twitch channels: Stream preview on hover
  • RSS: Request headers, limit per feed, and preserve-order
  • Videos: Support for YouTube playlists
  • Group: Support for `title-url`
  • Monitor: `alt-status-codes` and `error-url`
  • Extension: Specify if content should have no frame
  • Bookmarks: `target` for links, `same-tab`, and `hide-arrow` for groups
  • Reddit: `proxy` support
  • Search: `placeholder` and clear input on search
  • Markets: `chart-link-template`, `symbol-link-template`, and `sort-by`
  • Releases: `include-prereleases`
  • DNS stats: `hide-graph`, `hide-top-domains`, and `allow-insecure`
  • Clock: Displays exact time difference for timezones

Full Release Notes

## Jump to section

* [Docker container breaking changes](#g-rh-1)
* [CLI breaking changes](#g-rh-2)
* [New widgets](#g-rh-3)
    - [Docker containers](#g-rh-4)
    - [Custom API](#g-rh-5)
    - [Server stats](#g-rh-6)
    - [Split column](#g-rh-7)
    - [Calendar](#g-rh-8) (reworked)
* [New features](#g-rh-9)
    - [Auto reload on config change](#g-rh-10)
    - [Environment variables _anywhere_ in the config](#g-rh-11)
    - [Include files in the config](#g-rh-12)
    - [Custom HTML in document &lt;head&gt;](#g-rh-13)
    - [Support for selfh.st and Dashboard icons](#g-rh-14)
* [New styles](#g-rh-15)
    - [[Monitor] `compact`](#g-rh-16)
    - [[Videos] `vertical-list`](#g-rh-17)
* [Widget enhancements](#g-rh-18)
    - [[Twitch channels] stream preview on hover](#g-rh-19)
    - [[RSS] request headers, `limit` per feed, `preserve-order`](#g-rh-20)
    - [[Videos] `playlists`](#g-rh-21)
    - [[Group] support for `title-url`](#g-rh-22)
    - [[Monitor] `alt-status-codes`, `error-url`](#g-rh-23)
    - [[Extension] specify if content should have no frame](#g-rh-24)
    - [[Bookmarks] `target` for links, `same-tab` and `hide-arrow` for groups](#g-rh-25)
    - [[Reddit] `proxy`](#g-rh-26)
    - [[Search] `placeholder` and clear input on search](#g-rh-27)
    - [[Markets] `chart-link-template`, `symbol-link-template` and `sort-by`](#g-rh-28)
    - [[Releases] `include-prereleases`](#g-rh-29)
    - [[DNS stats] `hide-graph`, `hide-top-domains` and `allow-insecure`](#g-rh-30)
    - [[Clock] now displays exact time difference for timezones](#g-rh-31)
* [Fixes](#g-rh-32)
* [Been a while](#g-rh-33)
* [Community overhaul](#g-rh-34)
* [Thank you](#g-rh-35)

## <a id="g-rh-1"></a> Docker container breaking changes
Until now, setting up Glance using its Docker container involved a somewhat unusual step where the config file was solely mounted as a volume. This tripped up some users and caused unnecessary confusion due to a few odd behaviors.

The default location of the config file has now been changed to `/app/config/glance.yml` from `/app/glance.yml`. That means your `docker-compose.yml` file should now look like the following:

```yaml
services:
  glance:
    image: glanceapp/glance
    volumes:
      - ./config:/app/config
```

This also requires that you place your `glance.yml` file in a `config` directory in the same location as your `docker-compose.yml` file. If you're unsure what changes you need to make, there is an upgrade guide available [here](https://github.com/glanceapp/glance/tree/main/docs/v0.7.0-upgrade.md) as well as a new recommended docker compose directory structure available [here](https://github.com/glanceapp/docker-compose-template/tree/main/root).

## <a id="g-rh-2"></a> CLI breaking changes
Previously, you could run the following to validate your config file without starting Glance:

```glance --config /path/to/config.yml --check-config```

For the sake of consistency with the few new added comands (and because this shouldn't have been a flag in the first place), this has now been changed to:

```glance --config /path/to/config.yml config:validate```

## <a id="g-rh-3"></a> New widgets

### <a id="g-rh-4"></a> Docker containers
Display the status of your Docker containers along with an icon and an optional short description.

![docker-containers-preview](https://github.com/user-attachments/assets/67b6bab6-67a6-4759-a209-f5df1cadab93)

```yaml
- type: docker-containers
  hide-by-default: false
```

> [!NOTE]
>
> The widget requires access to `docker.sock`. If you're running Glance inside a container, this can be done by mounting the socket as a volume:
>
> ```yaml
> services:
>   glance:
>     image: glanceapp/glance
>     volumes:
>       - /var/run/docker.sock:/var/run/docker.sock
> ```

Configuration of the containers is done via labels applied to each container:

```yaml
  jellyfin:
    image: jellyfin/jellyfin:latest
    labels:
      glance.name: Jellyfin
      glance.icon: si:jellyfin
      glance.url: https://jellyfin.domain.com
      glance.description: Movies & shows
```

For services with multiple containers you can specify a `glance.id` on the "main" container and `glance.parent` on each "child" container:

<details>
<summary>View <code>docker-compose.yml</code></summary>
<br>

```yaml
services:
  immich-server:
    image: ghcr.io/immich-app/immich-server
    labels:
      glance.name: Immich
      glance.icon: si:immich
      glance.url: https://immich.domain.com
      glance.description: Image & video management
      glance.id: immich

  redis:
    image: docker.io/redis:6.2-alpine
    labels:
      glance.parent: immich
      glance.name: Redis

  database:
    image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0
    labels:
      glance.parent: immich
      glance.name: DB

  proxy:
    image: nginx:stable
    labels:
      glance.parent: immich
      glance.name: Proxy
```
</details>
<br>

This will place all child containers under the `Immich` container when hovering over its icon:

![docker-container-parent](https://github.com/user-attachments/assets/c11ee105-0357-4dec-8f28-123c3dfba8ba)

If any of the child containers are down, their status will propagate up to the parent container:

![docker-container-parent2](https://github.com/user-attachments/assets/d881d7ec-daaa-42d8-896b-1b3391223b86)

(thanks @baranovskis & @reality-exe, inspired by https://github.com/DVDAndroid/glance-docker-container-ext)

### <a id="g-rh-5"></a> Custom API

Display data from any JSON API in an entirely customizable template.

> [!NOTE]
>
> With great power come great requirements.
>
> The configuration of this widget requires some basic knowledge of programming, HTML, CSS, the Go template language and Glance-specific concepts.

![custom-api-preview-1](https://github.com/user-attachments/assets/c02e30fc-61cd-47dc-a50c-32464efd656f)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
- type: custom-api
  title: Random Fact
  cache: 6h
  url: https://uselessfacts.jsph.pl/api/v2/facts/random
  template: |
    <p class="size-h4 color-paragraph">{{ .JSON.String "text" }}</p>
```
</details>
<br>

![custom-api-preview-2](https://github.com/user-attachments/assets/10364b50-d886-473d-a1e5-2af73f84b742)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
- type: custom-api
  title: Immich stats
  cache: 1d
  url: https://${IMMICH_URL}/api/server/statistics
  headers:
    x-api-key: ${IMMICH_API_KEY}
    Accept: application/json
  template: |
    <div class="flex justify-between text-center">
      <div>
          <div class="color-highlight size-h3">{{ .JSON.Int "photos" | formatNumber }}</div>
          <div class="size-h6">PHOTOS</div>
      </div>
      <div>
          <div class="color-highlight size-h3">{{ .JSON.Int "videos" | formatNumber }}</div>
          <div class="size-h6">VIDEOS</div>
      </div>
      <div>
          <div class="color-highlight size-h3">{{ div (.JSON.Int "usage" | toFloat) 1073741824 | toInt | formatNumber }}GB</div>
          <div class="size-h6">USAGE</div>
      </div>
    </div>
```
</details>
<br>

![custom-api-preview-3](https://github.com/user-attachments/assets/66bc42fd-9f3a-4909-b1af-c3d2f6b9e01a)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
- type: custom-api
  title: Steam Specials
  cache: 12h
  url: https://store.steampowered.com/api/featuredcategories?cc=us
  template: |
    <ul class="list list-gap-10 collapsible-container" data-collapse-after="5">
    {{ range .JSON.Array "specials.items" }}
      <li>
        <a class="size-h4 color-highlight block text-truncate" href="https://store.steampowered.com/app/{{ .Int "id" }}/">{{ .String "name" }}</a>
        <ul class="list-horizontal-text">
          <li>{{ div (.Int "final_price" | toFloat) 100 | printf "$%.2f" }}</li>
          {{ $discount := .Int "discount_percent" }}
          <li{{ if ge $discount 40 }} class="color-positive"{{ end }}>{{ $discount }}% off</li>
        </ul>
      </li>
    {{ end }}
    </ul>
```
</details>
<br>

(thanks @reality-exe)

### <a id="g-rh-6"></a> Server stats

There are other projects dedicated to providing this kind of functionality and this is not meant to be a replacement for any of them, it's intended for people who just want the most basic information about their server without setting up a separate monitoring solution. Things will get improved based on feedback, but the goal is to keep it simple and minimal. If you're looking for a more feature-rich server monitoring solution, [Beszel](https://github.com/henrygd/beszel/issues) looks like a good choice. With that out of the way:

![server-stats-preview](https://github.com/user-attachments/assets/7cdc94de-f845-4fca-b377-8a3ffddf14ac)

```yaml
- type: server-stats
  servers:
    - type: local
      name: Services
      # optionally override the sensor used to determine CPU temperature
      # cpu-temp-sensor: thermal_zone0

      # optionally hide swap
      # hide-swap: true

      # optionally hide or rename mountpoints
      # mountpoints:
      #   "/boot/efi":
      #     hide: true
      #     name: EFI
```

There's a bunch of bars and their purpose might not be immediately obvious:

* CPU - 1m and 15m average load
* RAM - RAM and SWAP
* Disk – the two mountpoints with the highest usage percentages

If your CPU is feeling a little spicy (assuming Glance was able to determine your CPU sensor) and reaches >=80°C, you'll see a little flame icon next to it. The progress indicators will also turn red (or the equivalent of your negative color) to hopefully grab your attention if anything is unusually high:

![server-stats-preview-1](https://github.com/user-attachments/assets/40597baf-e6e6-4d9c-be3b-3a22c3505d01)

Now, it's not uncommon to have [multiple servers at home](https://www.reddit.com/r/homelab/) these days, and you'd probably want to see their stats as well, so there's support for that too:

![server-stats-preview-2](https://github.com/user-attachments/assets/2c9f683e-d124-4861-9433-835157f3e0b5)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
- type: server-stats
  servers:
    - type: remote
      name: Services
      url: http://${SERVER_IP}:27973
      token: ${AGENT_TOKEN}

    - type: remote
      name: DNS
      url: http://${SERVER_IP}:27973
      token: ${AGENT_TOKEN}
```
</details>

After looking for an existing solution to delegate this job to, nothing quite fit all of the following criteria:

  * Super minimal and lightweight
  * Does nothing in the background, no storage, just provides system info when asked
  * HTTP JSON API
  * Optional authentication
  * Easy, configurable installation with both a single binary and a Docker container
  * Supports x86_64 and ARM

As a result, somewhat contradictory to the first paragraph, [I decided to build one](https://github.com/glanceapp/agent) (it will be made available in the next couple of days). It's quite simple, very much work in progress, and I'm not sure how well it will work for everyone, but it's an option for those who want to go with this approach. It's not required if you just want to see the stats of the server Glance is installed on, only if you want to see the stats of multiple servers, in which case you'd have to install it on each. Here's what the setup process looks like:

https://github.com/user-attachments/assets/16369256-c851-4519-976f-e4b310b15a23

Installed, configured and uninstalled like it never existed in less than a minute.

Because the agent provides this information via a simple HTTP JSON API, you could use the custom API widget to display the stats in any way you like:

![custom-api-server-stats](https://github.com/user-attachments/assets/3d2abcd8-b84d-4fef-b82c-a608b9dfbe1a)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
- type: custom-api
  title: Server stats
  url: http://${SERVER_IP}:27973/api/sysinfo/all
  headers:
    Authorization: Bearer ${AGENT_TOKEN}
  template: |
    <div class="flex justify-between text-center">
      <div>
          <div class="color-highlight size-h3">{{ .JSON.Int "cpu.load1_percent" }}%</div>
          <div class="size-h6">CPU</div>
      </div>
      <div>
          <div class="color-highlight size-h3">{{ .JSON.Int "memory.used_percent" }}%</div>
          <div class="size-h6">RAM</div>
      </div>
      <div>
          <div class="color-highlight size-h3">{{ .JSON.Int "mountpoints.0.used_percent" }}%</div>
          <div class="size-h6">DISK</div>
      </div>
    </div>

- type: custom-api
  title: Server stats
  url: http://${SERVER_IP}:27973/api/sysinfo/all
  headers:
    Authorization: Bearer ${AGENT_TOKEN}
  template: |
    <div class="flex flex-column gap-5">
      <div class="flex gap-20 items-center">
          <div class="size-h5" style="width: 4ch">CPU</div>
          <div class="progress-bar grow">
            <div class="progress-value" style="--percent: {{ .JSON.Int "cpu.load1_percent" }}"></div>
          </div>
          <div class="color-highlight text-very-compact text-right" style="width: 4ch">{{ .JSON.Int "cpu.load1_percent" }} <span class="color-base size-h5">%</span></div>
      </div>
      <div class="flex gap-20 items-center">
          <div class="size-h5" style="width: 4ch">RAM</div>
          <div class="progress-bar grow">
            <div class="progress-value" style="--percent: {{ .JSON.Int "memory.used_percent" }}"></div>
          </div>
          <div class="color-highlight text-very-compact text-right" style="width: 4ch">{{ .JSON.Int "memory.used_percent" }} <span class="color-base size-h5">%</span></div>
      </div>
      <div class="flex gap-20 items-center">
          <div class="size-h5" style="width: 4ch">DISK</div>
          <div class="progress-bar grow">
            <div class="progress-value" style="--percent: {{ .JSON.Int "mountpoints.0.used_percent" }}"></div>
          </div>
          <div class="color-highlight text-very-compact text-right" style="width: 4ch">{{ .JSON.Int "mountpoints.0.used_percent" }} <span class="color-base size-h5">%</span></div>
      </div>
    </div>
```
</details>

There are plans to also add the ability to view the stats of Docker containers, so you could combine this with the Docker containers widget and see the status of your containers across multiple servers.

Support for other providers (such as [Glances](https://github.com/nicolargo/glances/)) are likely be added once everything else gets fleshed out a bit more.

(thanks @FedeP14 and [shirou for the excellent module](https://github.com/shirou/gopsutil))

### <a id="g-rh-7"></a> Split column
The ways in which you could organize your widgets has so far been somewhat limited. This widget brings a new dimension that you play around with by allowing you to vertically split a full sized column into multiple smaller columns of equal width.

Two widgets side by side in a `full` column:

![split-column-widget-preview](https://github.com/user-attachments/assets/3cac5cf8-8d06-4653-a2ec-475f9a6074df)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
# ...
- size: full
  widgets:
    - type: split-column
      widgets:
        - type: hacker-news
          collapse-after: 3
        - type: lobsters
          collapse-after: 3

    - type: videos
# ...
```
</details>
<br>

You can also achieve a number of new full page layouts that were previously not possible, such as:

3 column layout where all columns have equal width:

![split-column-widget-3-columns](https://github.com/user-attachments/assets/58e57c40-6bd9-48cd-a45b-799705a537c4)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
pages:
  - name: Home
    columns:
      - size: full
        widgets:
          - type: split-column
            max-columns: 3
            widgets:
              - type: reddit
                subreddit: selfhosted
                collapse-after: 15
              - type: reddit
                subreddit: homelab
                collapse-after: 15
              - type: reddit
                subreddit: sysadmin
                collapse-after: 15
```
</details>
<br>

4 column layout where all columns have equal width (and the page is set to `width: wide`):

![split-column-widget-4-columns](https://github.com/user-attachments/assets/39cc3418-c16d-43f6-9e97-39c28ccdfc11)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
pages:
  - name: Home
    width: wide
    columns:
      - size: full
        widgets:
          - type: split-column
            max-columns: 4
            widgets:
              - type: reddit
                subreddit: selfhosted
                collapse-after: 15
              - type: reddit
                subreddit: homelab
                collapse-after: 15
              - type: reddit
                subreddit: linux
                collapse-after: 15
              - type: reddit
                subreddit: sysadmin
                collapse-after: 15
```
</details>
<br>

Masonry layout with up to 5 columns where all columns have equal width (and the page is set to `width: wide`):

![split-column-widget-masonry](https://github.com/user-attachments/assets/635af55c-97a9-46f2-833c-16806ec5f006)

<details>
<summary>View <code>glance.yml</code></summary>
<br>

```yaml
define:
  - &subreddit-settings
    type: reddit
    collapse-after: 5

pages:
  - name: Home
    width: wide
    columns:
      - size: full
        widgets:
          - type: split-column
            max-columns: 5
            widgets:
              - subreddit: selfhosted
                <<: *subreddit-settings
              - subreddit: homelab
                <<: *subreddit-settings
              - subreddit: linux
                <<: *subreddit-settings
              - subreddit: sysadmin
                <<: *subreddit-settings
              - subreddit: DevOps
                <<: *subreddit-settings
              - subreddit: Networking
                <<: *subreddit-settings
              - subreddit: DataHoarding
                <<: *subreddit-settings
              - subreddit: OpenSource
                <<: *subreddit-settings
              - subreddit: Privacy
                <<: *subreddit-settings
              - subreddit: FreeSoftware
                <<: *subreddit-settings
```
</details>
<br>

Just like the `group` widget, you can insert any widget type, you can even insert a `group` widget inside of a `split-column` widget, but you can't insert a `split-column` widget inside of a `group` widget.

> [!NOTE]
>
> This does not create new columns in the usual sense, meaning that you won't see a "dot" in the mobile navigation for each of these columns, it will just be a single dot. When viewing the page on a mobile device, all columns will turn into in a single one with the widgets stacked on top of each other in the order they were defined.

### <a id="g-rh-8"></a> Calendar
The calendar widget has been reworked to look and behave more like an actual calendar.

![calendar-widget-preview](https://github.com/user-attachments/assets/4fa799be-c4eb-4d1e-a5b7-1a56030af8ed)

```yaml
- type: calendar
  first-day-of-week: monday # make it any day of the week you need
```

Previously, the calendar would display the time of the server running Glance. This has now been changed to display the current time in the user's timezone based on their browser settings. As a result, mounting `/etc/timezone` and `/etc/localtime` in your Docker container is no longer necessary.

Because the new calendar is considered WIP and does not yet include the same 3 week view, the old calendar widget is still available under the widget type `calendar-legacy`. The old calendar widget also has a new property for setting the first day of the week as sunday via `start-sunday: true` (thanks @xendke).

> [!NOTE]
>
> If you do want to use the legacy calendar you would still need to mount `/etc/timezone` and `/etc/localtime` in your Docker container.

This release was also meant to include the ability to add calendar events from ICS feeds, however unfortunately this feature turned out to be more complex than anticipated and will be included in a future release instead.

## <a id="g-rh-9"></a> New features

### <a id="g-rh-10"></a> Auto reload on config change
_Finally_, the highly requested feature of automatically reloading Glance when the config changes has been implemented. There are some things that break this functionality, such as deleting the config file, but for the most part it should work as expected. Note that changing environment variable values still requires a full manual restart.

> [!CAUTION]
>
> Reloading the config clears your cached data, so be mindful when making lots of changes as you may end up hitting rate limits on APIs.

(thanks @bcurran3 & @helloteemo & @arminus & everyone else who suggested this or tried implementing it)

### <a id="g-rh-11"></a> Environment variables _anywhere_ in the config
Up until now, the ability to use environment variables worked only on specific properties in the config and needed to be added individually for each property. This functionality has now been expanded to work _anywhere_ in the config:

```yaml
pages:
  - name: Home
    columns:
      - size: ${WORKS_HERE}
        widgets:
          - type: ${WORKS_HERE}
            limit: ${WORKS_HERE}
            collapse-after: ${AND_HERE}
            cache: ${AS_WELL_AS_HERE}
            feeds:
              - url: ${AND_OF_COURSE_HERE}
              - ${EVEN_HERE}: https://${HERE_TOO}/feed
```

If you need to use the syntax `${NAME}` in your config without it being interpreted as an environment variable, you can escape it by prefixing with a backslash `\`:

```yaml
something: \${NOT_AN_ENV_VAR}
```

(thanks @jfroy & @mgrimace)

### <a id="g-rh-12"></a> Include files in the config
Having a single, ever-growing config file can get a little overwhelming, especially with how picky YAML can be about indentation. To help with this, you can now split your config into multiple files and include them in the main config:

```yaml
theme:
  !include: theme.yml

pages:
  !include: home.yml
  !include: news.yml
  !include: homelab.yml

  # these paths also work:
  !include: ../pages/home.yml
  !include: pages/news.yml
  !include: /etc/opt/glance/homelab.yml

  # can be anywhere in the config, so long as they are on their own line:
  - name: Example
    columns:
      - size: small
        !include: example-left.yml
      - size: full
        !include: example-middle.yml
      - size: small
        !include: example-right.yml
```

The path of each file is relative to the main config file but you can also specify an absolute path. Changes to these included files will also trigger an automatic reload.

The proper indentation is automatically applied to the included content based on where it's included. The included file itself should have no extra indentation.

> [!NOTE]
>
> For now, the `!include` directive only works in the main config file and not in included files.

> [!NOTE]
>
> The `!include` directive is a preprocessing step, meaning that all files first get "stitched" together and then parsed as a single YAML file. Any YAML syntax errors will report the line number in the concatenated text, not the original file. To help with debugging, there is a new command that prints the full parsed config file with all includes resolved:
>
>```sh
> glance --config /path/to/config.yml config:print
>```
>
> You can pipe the output to `less -N` which will display line numbers.

> [!NOTE]
>
> *(yes, that's 3 notes in a row)*
>
> Because of the above note, including a file does not override existing keys at the same level. This will result in an error because the key `collapse-after` is defined twice:
>
> `reddit-settings.yml`:
> ```yaml
> collapse-after: 5
> limit: 10
> ```
> `glance.yml`:
> ```yaml
> - type: reddit
>   subreddit: linux
>   collapse-after: 10
>   !include: reddit-settings.yml
> ```
>
> To reuse properties like this use [YAML anchors](https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/) instead.

(thanks @p5 & @Krojack)

### <a id="g-rh-13"></a> Custom HTML in document &lt;head&gt;

Previously, if you wanted to insert HTML into the document across all pages, you had to do so through the `custom-footer` property which wasn't ideal. You can now insert custom HTML in the document's &lt;head&gt;:

```yaml
# this is a top level property
document:
  head: |
    <meta http-equiv="refresh" content="120">
    <script>alert("probably don't do this... but you could if you wanted to!");</script>
```

(thank you to the peeps from the Discord server for bringing this up)

### <a id="g-rh-14"></a> Support for selfh.st and Dashboard icons
You can now use [selfh.st](https://selfh.st/icons/) and [Dashboard](https://github.com/walkxcode/dashboard-icons) icons in the `icon` property of widgets such as the `monitor` and `bookmarks`:

```yaml
  icon: si:github # simple icons
  icon: sh:github # selfh.st icons
  icon: di:github # Dashboard icons
```

(thanks @2q2code)

## <a id="g-rh-15"></a> New styles

### <a id="g-rh-16"></a> [Monitor] `compact`

![monitor-widget-compact-preview](https://github.com/user-attachments/assets/61fa3772-7786-41fa-ae57-7db560864cd6)

```yaml
- type: monitor
  style: compact
```

(thanks for the idea Gato :D)

### <a id="g-rh-17"></a> [Videos] `vertical-list`

![videos-widget-vertical-list-preview](https://github.com/user-attachments/assets/76e295a0-f2be-4fb4-a0d6-c111adff65d8)

```yaml
- type: videos
  style: vertical-list
```

## <a id="g-rh-18"></a> Widget enhancements
### <a id="g-rh-19"></a> [Twitch channels] stream preview on hover

![stream-hover-preview](https://github.com/user-attachments/assets/48f9aaca-a3a8-480c-9af4-9b66dde99f9e)

(thanks for the idea @uykukacinca)

### <a id="g-rh-20"></a> [RSS] request headers, `limit` per feed, `preserve-order`
You can now specify request headers on a per-feed basis:

```yaml
- type: rss
  feeds:
    - url: https://domain.com/rss
      headers:
        User-Agent: Custom User Agent
        Authorization: Bearer ${FEED_TOKEN}
        # etc...
```

You can also limit the number of items per feed, for those feeds which post a little too frequently and push the rest of the articles from other feeds down:

```yaml
- type: rss
  feeds:
    - url: https://domain.com/rss
      limit: 5
```

And finally, you can now preserve the order of the items in each feed, useful for feeds which place their most important articles at the top:

```yaml
- type: rss
  preserve-order: true
  feeds:
    - url: https://domain.com/rss
```

(thanks @paulkakell & @lunik1)

### <a id="g-rh-21"></a> [Videos] `playlists`
You can now add YouTube playlists to the videos widget:

```yaml
- type: videos
  playlists:
    - PL8mG-RkN2uTyZZ00ObwZxxoG_nJbs3qec
    - PL8mG-RkN2uTxTK4m_Vl2dYR9yE41kRdBg
```

(thanks @DickenSerm & @vishalkadam47)

### <a id="g-rh-22"></a> [Group] support for `title-url`
The `title-url` property now works for widgets placed inside of a group. To open their link in a new tab you can either middle click on any of the titles, or click again on the currently selected widget's title.

### <a id="g-rh-23"></a> [Monitor] `alt-status-codes`, `error-url`
You can now specify alternative status codes to be considered as "up" for the monitor widget:

```yaml
- type: monitor
  title: Services
  sites:
    - title: Jellyfin
      url: https://jellyfin.yourdomain.com
      icon: sh:jellyfin
      alt-status-codes: [401, 403]
```

You can also specify an alternative URL for the site for when it is down:

```yaml
- type: monitor
  title: Services
  sites:
    - title: Jellyfin
      url: https://jellyfin.yourdomain.com
      icon: sh:jellyfin
      error-url: https://status.yourdomain.com
```

(thanks @cmeadowstech & @JeckDev)

### <a id="g-rh-24"></a> [Extension] specify if content should have no frame
Extensions can now return a `Widget-Content-Frameless` header with a value of `true` to have their content displayed without a frame (the lighter background and border).

(thanks @DallasHoff)

### <a id="g-rh-25"></a> [Bookmarks] `target` for links, `same-tab` and `hide-arrow` for groups

You can now specify the target for links in the bookmarks widget:

```yaml
- type: bookmarks
  groups:
    - links:
        - title: Gmail
          url: https://mail.google.com/mail/u/0/
          target: _parent
```

In addition, you can now specify `same-tab`, `hide-arrow` and `target` on groups and have each link in the group inherit those properties, or override them for a specific link:

```yaml
- type: bookmarks
  groups:
    - same-tab: true   # ╺┓
      hide-arrow: true # ╺╋╸ default for all links in this group
      target: _parent  # ╺┛
      links:
        - title: Link
          url: ...
        - title: Link
          url: ...
          same-tab: false # override for this link
        - title: Link
          url: ...
```

(thanks @Jacksaur & @K0ng2)

### <a id="g-rh-26"></a> [Reddit] `proxy`

You can now use a standard HTTP proxy in the Reddit widget for instances where Reddit is blocked:

```yaml
- type: reddit
  subreddit: linux
  proxy:
    url: http://proxy.com:8080
    allow-insecure: true
    timeout: 10s
```

(thanks Bifrons)

### <a id="g-rh-27"></a> [Search] `placeholder` and clear input on search

You can now specify a placeholder text for the search widget:

```yaml
- type: search
  placeholder: Search...
```

In addition, when performing a search in a new tab, the search query will be cleared from the input field. You can press <kbd>Up</kbd> arrow to bring back the last search query.

(thanks @hecht-a & @KSJaay)

### <a id="g-rh-28"></a> [Markets] `chart-link-template`, `symbol-link-template` and `sort-by`

You can now specify a sort order of `change` for descending order based on the stock's percentage change (e.g. 1% would be sorted higher than -1%).

```yaml
- type: markets
  sort-by: change
  markets:
    - symbol: AAPL
```

You can also specify a template for the `chart-link` and `symbol-link` so you don't have to repeat the same URL for each market:

```yaml
- type: markets
  chart-link-template: https://tradingview.com/chart?symbol={SYMBOL}
  symbol-link-template: https://finance.yahoo.com/quote/{SYMBOL}
  markets:
    - symbol: AAPL
    - symbol: TSLA
    - symbol: MSFT
    - symbol: GOOGL
```

(thanks @ehaughee)

### <a id="g-rh-29"></a> [Releases] `include-prereleases`

You can now include prereleases in the releases widget for individual repositories (only supports GitHub for now):

```yaml
- type: releases
  repositories:
    - repository: glanceapp/glance
      include-prereleases: true
    - immich/immich-server
    - jellyfin/jellyfin
    - go-gitea/gitea
```

(thanks @Mystically11)

### <a id="g-rh-30"></a> [DNS stats] `hide-graph`, `hide-top-domains` and `allow-insecure`

You can now hide the graph as well as top domains in the DNS stats widget:

```yaml
- type: dns-stats
  hide-graph: true
  hide-top-domains: true
```

You can also use an insecure connection to the API by setting `allow-insecure: true` if you're using a self-signed certificate.

(thanks @zatevakhin)

### <a id="g-rh-31"></a> [Clock] now displays exact time difference for other timezones

(thanks @oliver-mitchell)

## <a id="g-rh-32"></a> Fixes
* URLs in the config with non-http/https schemas will no longer be escaped (thanks @kamilkosek)
* Titles in RSS feeds with special characters will now be properly displayed (thanks @marb08)
* Various visual bug fixes on iOS (thanks @DallasHoff)

## <a id="g-rh-33"></a> Been a while
It's been almost 5 months since v0.6.0 and that's a _long_ time to wait for new stuff. As new feature requests kept coming in I got stuck in a "I'll add this to the next release" loop, so the amount of things needing to be done grew out of hand. I want to avoid making this mistake again in the future by releasing smaller but more frequent updates.

I'm sorry for the wait y'all, I'll try and do better. I hope there's at least one thing in this release for everyone to get excited about.

There's a lot of new stuff out at once so inevitably there may be some bugs, I'll try and prioritize fixing those and releasing hotfixes over the next few weeks.

## <a id="g-rh-34"></a> Community overhaul
The community side of the repository has gone through a bit of an overhaul. Previously, there were no guidelines around where and how to submit feature requests, bug reports or ask for help, so they were scattered across the issues and discussions which made them difficult to keep track of. Now, clear guidelines are in place: feature requests and bug reports should be submitted exclusively via issues. The discussions as well as Discord server will be for general discussions, help and sharing guides/resources.

## <a id="g-rh-35"></a> Thank you
To all the [sponsors](https://github.com/sponsors/glanceapp) who have continued to support the project even in the lack of activity during the last couple of months and to everyone who has contributed in the meantime. Also, I'd like to thank Ethan for featuring Glance on [selfh.st](https://selfh.st)! It's been a great motivator to see Glance listed alongside so many other great projects.