diff --git a/.dockerignore b/.dockerignore
index 1f9515c..8708dce 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -5,7 +5,6 @@
# Only add necessary files to the Docker build context (Dockerfiles are always included implicitly)
!/build/
!/internal/
-!/pkg/
!/go.mod
!/go.sum
!main.go
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
deleted file mode 100644
index bdd4fe6..0000000
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-name: Bug report
-description: Let us know if something isn't working as expected
-labels: ["bug report"]
-body:
- - type: markdown
- attributes:
- value: |
- > [!NOTE]
- >
- > Do not prefix your title with "[BUG]", "[Bug report]", etc., a label will be added automatically.
-
- If you're unsure whether you're experiencing a bug or not, consider using the [Discussions](https://github.com/glanceapp/glance/discussions) or [Discord](https://discord.com/invite/7KQ7Xa9kJd) to ask for help.
-
- Please include only the information you think is relevant to the bug:
-
- * How did you install Glance? (Docker container, manual binary install, etc)
- * Which version of Glance are you using?
- * Include the relevant parts of your `glance.yml` if applicable (widget, data source, properties used, etc)
- * Include any relevant logs or screenshots if applicable
- * Is the issue specific to a certain browser or OS?
- * Steps to reliably reproduce the issue
- * Are you hosting Glance on a VPS?
- * Anything else you think might be relevant
-
- **No need to copy the above list into your description, it's just a guide to help you provide the most useful information.**
-
- - type: textarea
- id: description
- validations:
- required: true
- attributes:
- label: Description
-
- - type: markdown
- attributes:
- value: |
- Thank you for taking the time to submit a bug report.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
deleted file mode 100644
index e8c34af..0000000
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-blank_issues_enabled: false
-contact_links:
- - name: Discussions
- url: https://github.com/glanceapp/glance/discussions
- about: For help, feedback, guides, resources and more
- - name: Discord
- url: https://discord.com/invite/7KQ7Xa9kJd
- about: Much like the discussions but more chatty
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
deleted file mode 100644
index d8f5343..0000000
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: Feature request
-description: Share your ideas for new features or improvements
-labels: ["feature request"]
-body:
- - type: markdown
- attributes:
- value: |
- > [!NOTE]
- >
- > Do not prefix your title with "[REQUEST]", "[Feature request]", etc., a label will be added automatically.
-
- Please provide a detailed description of what the feature would do and what it would look like:
-
- * What problem would this feature solve?
- * Are there any potential downsides to this feature?
- * If applicable, what would the configuration for this feature look like?
- * Are there any existing examples of this feature in other software?
- * If applicable, include any external documentation required to implement this feature
- * Anything else you think might be relevant
-
- **No need to copy the above list into your description, it's just a guide to help you provide the most useful information.**
-
- - type: textarea
- id: description
- validations:
- required: true
- attributes:
- label: Description
-
- - type: markdown
- attributes:
- value: |
- Thank you for taking the time to submit your idea.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 690586f..22b3d05 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1 +1,7 @@
-
+
diff --git a/.gitignore b/.gitignore
index 2cd84fc..062999d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
/assets
/build
/playground
-/.idea
-/glance*.yml
+glance.yml
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index 7153a4f..c9c5297 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -50,9 +50,9 @@ dockers:
dockerfile: Dockerfile.goreleaser
- image_templates:
- - &armv7_image "{{ .ProjectName }}:{{ .Tag }}-armv7"
+ - &arm64v7_image "{{ .ProjectName }}:{{ .Tag }}-arm64v7"
build_flag_templates:
- - --platform=linux/arm/v7
+ - --platform=linux/arm64/v7
goarch: arm
goarm: 7
use: buildx
@@ -60,10 +60,13 @@ dockers:
docker_manifests:
- name_template: "{{ .ProjectName }}:{{ .Tag }}"
- image_templates: &multiarch_images
+ image_templates:
- *amd64_image
- *arm64v8_image
- - *armv7_image
+ - *arm64v7_image
- name_template: "{{ .ProjectName }}:latest"
skip_push: auto
- image_templates: *multiarch_images
+ image_templates:
+ - *amd64_image
+ - *arm64v8_image
+ - *arm64v7_image
diff --git a/Dockerfile b/Dockerfile
index 0c4cc63..e4019ba 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,16 +1,13 @@
-FROM golang:1.24.2-alpine3.21 AS builder
+FROM golang:1.22.5-alpine3.20 AS builder
WORKDIR /app
COPY . /app
RUN CGO_ENABLED=0 go build .
-FROM alpine:3.21
+FROM alpine:3.20
WORKDIR /app
COPY --from=builder /app/glance .
-HEALTHCHECK --timeout=10s --start-period=60s --interval=60s \
- CMD wget --spider -q http://localhost:8080/api/healthz
-
EXPOSE 8080/tcp
-ENTRYPOINT ["/app/glance", "--config", "/app/config/glance.yml"]
+ENTRYPOINT ["/app/glance"]
diff --git a/Dockerfile.goreleaser b/Dockerfile.goreleaser
index bbfa8ad..dec9ac4 100644
--- a/Dockerfile.goreleaser
+++ b/Dockerfile.goreleaser
@@ -1,10 +1,8 @@
-FROM alpine:3.21
+FROM alpine:3.20
WORKDIR /app
COPY glance .
-HEALTHCHECK --timeout=10s --start-period=60s --interval=60s \
- CMD wget --spider -q http://localhost:8080/api/healthz
-
EXPOSE 8080/tcp
-ENTRYPOINT ["/app/glance", "--config", "/app/config/glance.yml"]
+
+ENTRYPOINT ["/app/glance"]
diff --git a/README.md b/README.md
index ca16c49..25db4df 100644
--- a/README.md
+++ b/README.md
@@ -1,436 +1,111 @@
-
+
-## Features
-### Various widgets
+### Features
+#### Various widgets
* RSS feeds
* Subreddit posts
-* Hacker News posts
-* Weather forecasts
-* YouTube channel uploads
-* Twitch channels
-* Market prices
-* Docker containers status
-* Server stats
-* Custom widgets
-* [and many more...](docs/configuration.md)
+* Weather
+* Bookmarks
+* Hacker News
+* Lobsters
+* Latest YouTube videos from specific channels
+* Clock
+* Calendar
+* Stocks
+* iframe
+* Twitch channels & top games
+* GitHub releases
+* Repository overview
+* Site monitor
+* Search box
-### Fast and lightweight
-* Low memory usage
-* Few dependencies
-* Minimal vanilla JS
-* Single <20mb binary available for multiple OSs & architectures and just as small Docker container
-* Uncached pages usually load within ~1s (depending on internet speed and number of widgets)
+#### Themeable
+
-### Tons of customizability
-* Different layouts
-* As many pages/tabs as you need
-* Numerous configuration options for each widget
-* Multiple styles for some widgets
-* Custom CSS
+#### Optimized for mobile devices
+
-### Optimized for mobile devices
-Because you'll want to take it with you on the go.
+#### Fast and lightweight
+* Minimal JS, no bloated frameworks
+* Very few dependencies
+* Single, easily distributed <15mb binary and just as small docker container
+* All requests are parallelized, uncached pages usually load within ~1s (depending on internet speed and number of widgets)
-
+### Configuration
+Checkout the [configuration docs](docs/configuration.md) to learn more. A [preconfigured page](docs/configuration.md#preconfigured-page) is also available to get you started quickly.
-### Themeable
-Easily create your own theme by tweaking a few numbers or choose from one of the [already available themes](docs/themes.md).
+### Installation
+> [!CAUTION]
+>
+> The project is under active development, expect things to break every once in a while.
-
-
-
-
-## Configuration
-Configuration is done through YAML files, to learn more about how the layout works, how to add more pages and how to configure widgets, visit the [configuration documentation](docs/configuration.md).
-
-
-Preview example configuration file
-
-
-```yaml
-pages:
- - name: Home
- columns:
- - size: small
- widgets:
- - type: calendar
- first-day-of-week: monday
-
- - type: rss
- limit: 10
- collapse-after: 3
- cache: 12h
- feeds:
- - url: https://selfh.st/rss/
- title: selfh.st
- limit: 4
- - url: https://ciechanow.ski/atom.xml
- - url: https://www.joshwcomeau.com/rss.xml
- title: Josh Comeau
- - url: https://samwho.dev/rss.xml
- - url: https://ishadeed.com/feed.xml
- title: Ahmad Shadeed
-
- - type: twitch-channels
- channels:
- - theprimeagen
- - j_blow
- - piratesoftware
- - cohhcarnage
- - christitustech
- - EJ_SA
-
- - size: full
- widgets:
- - type: group
- widgets:
- - type: hacker-news
- - type: lobsters
-
- - type: videos
- channels:
- - UCXuqSBlHAE6Xw-yeJA0Tunw # Linus Tech Tips
- - UCR-DXc1voovS8nhAvccRZhg # Jeff Geerling
- - UCsBjURrPoezykLs9EqgamOA # Fireship
- - UCBJycsmduvYEL83R_U4JriQ # Marques Brownlee
- - UCHnyfMqiRRG1u-2MsSQLbXA # Veritasium
-
- - type: group
- widgets:
- - type: reddit
- subreddit: technology
- show-thumbnails: true
- - type: reddit
- subreddit: selfhosted
- show-thumbnails: true
-
- - size: small
- widgets:
- - type: weather
- location: London, United Kingdom
- units: metric
- hour-format: 12h
-
- - type: markets
- markets:
- - symbol: SPY
- name: S&P 500
- - symbol: BTC-USD
- name: Bitcoin
- - symbol: NVDA
- name: NVIDIA
- - symbol: AAPL
- name: Apple
- - symbol: MSFT
- name: Microsoft
-
- - type: releases
- cache: 1d
- repositories:
- - glanceapp/glance
- - go-gitea/gitea
- - immich-app/immich
- - syncthing/syncthing
-```
-
-
-
-
-## Installation
-
-Choose one of the following methods:
-
-
-Docker compose using provided directory structure (recommended)
-
-
-Create a new directory called `glance` as well as the template files within it by running:
-
-```bash
-mkdir glance && cd glance && curl -sL https://github.com/glanceapp/docker-compose-template/archive/refs/heads/main.tar.gz | tar -xzf - --strip-components 2
-```
-
-*[click here to view the files that will be created](https://github.com/glanceapp/docker-compose-template/tree/main/root)*
-
-Then, edit the following files as desired:
-* `docker-compose.yml` to configure the port, volumes and other containery things
-* `config/home.yml` to configure the widgets or layout of the home page
-* `config/glance.yml` if you want to change the theme or add more pages
-
-
-Other files you may want to edit
-
-* `.env` to configure environment variables that will be available inside configuration files
-* `assets/user.css` to add custom CSS
-
-
-When ready, run:
-
-```bash
-docker compose up -d
-```
-
-If you encounter any issues, you can check the logs by running:
-
-```bash
-docker compose logs
-```
-
-
-
-
-
-Docker compose manual
-
-
-Create a `docker-compose.yml` file with the following contents:
-
-```yaml
-services:
- glance:
- container_name: glance
- image: glanceapp/glance
- restart: unless-stopped
- volumes:
- - ./config:/app/config
- ports:
- - 8080:8080
-```
-
-Then, create a new directory called `config` and download the example starting [`glance.yml`](https://github.com/glanceapp/glance/blob/main/docs/glance.yml) file into it by running:
-
-```bash
-mkdir config && wget -O config/glance.yml https://raw.githubusercontent.com/glanceapp/glance/refs/heads/main/docs/glance.yml
-```
-
-Feel free to edit the `glance.yml` file to your liking, and when ready run:
-
-```bash
-docker compose up -d
-```
-
-If you encounter any issues, you can check the logs by running:
-
-```bash
-docker logs glance
-```
-
-
-
-
-
-Manual binary installation
-
-
-Precompiled binaries are available for Linux, Windows and macOS (x86, x86_64, ARM and ARM64 architectures).
-
-### Linux
-
-Visit the [latest release page](https://github.com/glanceapp/glance/releases/latest) for available binaries. You can place the binary in `/opt/glance/` and have it start with your server via a [systemd service](https://linuxhandbook.com/create-systemd-services/). By default, when running the binary, it will look for a `glance.yml` file in the directory it's placed in. To specify a different path for the config file, use the `--config` option:
+#### Manual
+Checkout the [releases page](https://github.com/glanceapp/glance/releases) for available binaries. You can place the binary inside `/opt/glance/` and have it start with your server via a [systemd service](https://linuxhandbook.com/create-systemd-services/). To specify a different path for the config file use the `--config` option:
```bash
/opt/glance/glance --config /etc/glance.yml
```
-To grab a starting template for the config file, run:
+#### Docker
+> [!IMPORTANT]
+>
+> Make sure you have a valid `glance.yml` file in the same directory before running the container.
```bash
-wget https://raw.githubusercontent.com/glanceapp/glance/refs/heads/main/docs/glance.yml
+docker run -d -p 8080:8080 \
+ -v ./glance.yml:/app/glance.yml \
+ -v /etc/timezone:/etc/timezone:ro \
+ -v /etc/localtime:/etc/localtime:ro \
+ glanceapp/glance
```
-### Windows
-
-Download and extract the executable from the [latest release](https://github.com/glanceapp/glance/releases/latest) (most likely the file called `glance-windows-amd64.zip` if you're on a 64-bit system) and place it in a folder of your choice. Then, create a new text file called `glance.yml` in the same folder and paste the content from [here](https://raw.githubusercontent.com/glanceapp/glance/refs/heads/main/docs/glance.yml) in it. You should then be able to run the executable and access the dashboard by visiting `http://localhost:8080` in your browser.
-
-
-
-
-
-
-
-Other
-
-
-Glance can also be installed through the following 3rd party channels:
-* [Proxmox VE Helper Script](https://community-scripts.github.io/ProxmoxVE/scripts?id=glance)
-* [NixOS package](https://search.nixos.org/packages?channel=unstable&show=glance)
-* [Coolify.io](https://coolify.io/docs/services/glance/)
-
-
-
-
-
-
-## Common issues
-
-Requests timing out
-
-The most common cause of this is when using Pi-Hole, AdGuard Home or other ad-blocking DNS services, which by default have a fairly low rate limit. Depending on the number of widgets you have in a single page, this limit can very easily be exceeded. To fix this, increase the rate limit in the settings of your DNS service.
-
-If using Podman, in some rare cases the timeout can be caused by an unknown issue, in which case it may be resolved by adding the following to the bottom of your `docker-compose.yml` file:
-```yaml
-networks:
- podman:
- external: true
-```
-
-
-
-Broken layout for markets, bookmarks or other widgets
-
-This is almost always caused by the browser extension Dark Reader. To fix this, disable dark mode for the domain where Glance is hosted.
-
-
-
-cannot unmarshal !!map into []glance.page
-
-The most common cause of this is having a `pages` key in your `glance.yml` and then also having a `pages` key inside one of your included pages. To fix this, remove the `pages` key from the top of your included pages.
-
-
-
-
-
-## FAQ
-
-Does the information on the page update automatically?
-No, a page refresh is required to update the information. Some things do dynamically update where it makes sense, like the clock widget and the relative time showing how long ago something happened.
-
-
-
-How frequently do widgets update?
-No requests are made periodically in the background, information is only fetched upon loading the page and then cached. The default cache lifetime is different for each widget and can be configured.
-
-
-
-Can I create my own widgets?
-
-Yes, there are multiple ways to create custom widgets:
-* `iframe` widget - allows you to embed things from other websites
-* `html` widget - allows you to insert your own static HTML
-* `extension` widget - fetch HTML from a URL
-* `custom-api` widget - fetch JSON from a URL and render it using custom HTML
-
-
-
-Can I change the title of a widget?
-
-Yes, the title of all widgets can be changed by specifying the `title` property in the widget's configuration:
+Or if you prefer docker compose:
```yaml
-- type: rss
- title: My custom title
-
-- type: markets
- title: My custom title
-
-- type: videos
- title: My custom title
-
-# and so on for all widgets...
+services:
+ glance:
+ image: glanceapp/glance
+ volumes:
+ - ./glance.yml:/app/glance.yml
+ - /etc/timezone:/etc/timezone:ro
+ - /etc/localtime:/etc/localtime:ro
+ ports:
+ - 8080:8080
+ restart: unless-stopped
```
-
-
+### Building from source
-## Feature requests
+Requirements: [Go](https://go.dev/dl/) >= v1.22
-New feature suggestions are always welcome and will be considered, though please keep in mind that some of them may be out of scope for what the project is trying to achieve (or is reasonably capable of). If you have an idea for a new feature and would like to share it, you can do so [here](https://github.com/glanceapp/glance/issues/new?template=feature_request.yml).
-
-Feature requests are tagged with one of the following:
-
-* [Roadmap](https://github.com/glanceapp/glance/labels/roadmap) - will be implemented in a future release
-* [Backlog](https://github.com/glanceapp/glance/labels/backlog) - may be implemented in the future but needs further feedback or interest from the community
-* [Icebox](https://github.com/glanceapp/glance/labels/icebox) - no plans to implement as it doesn't currently align with the project's goals or capabilities, may be revised at a later date
-
-
-
-## Building from source
-
-Choose one of the following methods:
-
-
-Build binary with Go
-
-
-Requirements: [Go](https://go.dev/dl/) >= v1.23
-
-To build the project for your current OS and architecture, run:
+To build:
```bash
go build -o build/glance .
```
-To build for a specific OS and architecture, run:
-
-```bash
-GOOS=linux GOARCH=amd64 go build -o build/glance .
-```
-
-[*click here for a full list of GOOS and GOARCH combinations*](https://go.dev/doc/install/source#:~:text=$GOOS%20and%20$GOARCH)
-
-Alternatively, if you just want to run the app without creating a binary, like when you're testing out changes, you can run:
+To run:
```bash
go run .
```
-
-
-
-Build project and Docker image with Docker
-
+### Building Docker image
-Requirements: [Docker](https://docs.docker.com/engine/install/)
+Build the image:
-To build the project and image using just Docker, run:
-
-*(replace `owner` with your name or organization)*
+**Make sure to replace "owner" with your name or organization.**
```bash
docker build -t owner/glance:latest .
```
-If you wish to push the image to a registry (by default Docker Hub), run:
+Push the image to your registry:
```bash
docker push owner/glance:latest
```
-
-
-
-
-
-
-## Contributing guidelines
-
-* Before working on a new feature it's preferable to submit a feature request first and state that you'd like to implement it yourself
-* Please don't submit PRs for feature requests that are either in the roadmap[1], backlog[2] or icebox[3]
-* Use `dev` for the base branch if you're adding new features or fixing bugs, otherwise use `main`
-* Avoid introducing new dependencies
-* Avoid making backwards-incompatible configuration changes
-* Avoid introducing new colors or hard-coding colors, use the standard `primary`, `positive` and `negative`
-* For icons, try to use [heroicons](https://heroicons.com/) where applicable
-* Provide a screenshot of the changes if UI related where possible
-* No `package.json`
-
-
-[1] [2] [3]
-
-[1] The feature likely already has work put into it that may conflict with your implementation
-
-[2] The demand, implementation or functionality for this feature is not yet clear
-
-[3] No plans to add this feature for the time being
-
-
-
-
-
-## Thank you
-
-To all the people who were generous enough to [sponsor](https://github.com/sponsors/glanceapp) the project and to everyone who has contributed in any way, be it PRs, submitting issues, helping others in the discussions or Discord server, creating guides and tools or just mentioning Glance on social media. Your support is greatly appreciated and helps keep the project going.
diff --git a/docs/configuration.md b/docs/configuration.md
index 3999d8c..7d4669f 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -1,15 +1,10 @@
-# Configuring Glance
+# Configuration
+- [Intro](#intro)
- [Preconfigured page](#preconfigured-page)
-- [The config file](#the-config-file)
- - [Auto reload](#auto-reload)
- - [Environment variables](#environment-variables)
- - [Including other config files](#including-other-config-files)
- [Server](#server)
-- [Document](#document)
-- [Branding](#branding)
- [Theme](#theme)
- - [Available themes](#available-themes)
+ - [Themes](#themes)
- [Pages & Columns](#pages--columns)
- [Widgets](#widgets)
- [RSS](#rss)
@@ -18,20 +13,13 @@
- [Lobsters](#lobsters)
- [Reddit](#reddit)
- [Search](#search-widget)
- - [Group](#group)
- - [Split Column](#split-column)
- - [Custom API](#custom-api)
- [Extension](#extension)
- [Weather](#weather)
- [Monitor](#monitor)
- [Releases](#releases)
- - [Docker Containers](#docker-containers)
- - [DNS Stats](#dns-stats)
- - [Server Stats](#server-stats)
- [Repository](#repository)
- [Bookmarks](#bookmarks)
- [Calendar](#calendar)
- - [Calendar (legacy)](#calendar-legacy)
- [ChangeDetection.io](#changedetectionio)
- [Clock](#clock)
- [Markets](#markets)
@@ -40,114 +28,85 @@
- [iframe](#iframe)
- [HTML](#html)
+## 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.
## Preconfigured page
-If you don't want to spend time reading through all the available configuration options and just want something to get you going quickly you can use [this `glance.yml` file](glance.yml) and make changes to it as you see fit. It will give you a page that looks like the following:
-
-
-
-Configure the widgets, add more of them, add extra pages, etc. Make it your own!
-
-## The config file
-
-### Auto reload
-Automatic config reload is supported, meaning that you can make changes to the config file and have them take effect on save without having to restart the container/service. Making changes to environment variables does not trigger a reload and requires manual restart. Deleting a config file will stop that file from being watched, even if it is recreated.
-
-> [!NOTE]
->
-> If you attempt to start Glance with an invalid config it will exit with an error outright. If you successfully started Glance with a valid config and then made changes to it which result in an error, you'll see that error in the console and Glance will continue to run with the old configuration. You can then continue to make changes and when there are no errors the new configuration will be loaded.
-
-> [!CAUTION]
->
-> Reloading the configuration file clears your cached data, meaning that you have to request the data anew each time you do this. This can lead to rate limiting for some APIs if you do it too frequently. Having a cache that persists between reloads will be added in the future.
-
-### Environment variables
-Inserting environment variables is supported anywhere in the config. This is done via the `${ENV_VAR}` syntax. Attempting to use an environment variable that doesn't exist will result in an error and Glance will either not start or load your new config on save. Example:
-
-```yaml
-server:
- host: ${HOST}
- port: ${PORT}
-```
-
-Can also be in the middle of a string:
-
-```yaml
-- type: rss
- title: ${RSS_TITLE}
- feeds:
- - url: http://domain.com/rss/${RSS_CATEGORY}.xml
-```
-
-Works with any type of value, not just strings:
-
-```yaml
-- type: rss
- limit: ${RSS_LIMIT}
-```
-
-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}
-```
-
-### Including other config files
-Including config files from within your main config file is supported. This is done via the `!include` directive along with a relative or absolute path to the file you want to include. If the path is relative, it will be relative to the main config file. Additionally, environment variables can be used within included files, and changes to the included files will trigger an automatic reload. Example:
-
-```yaml
-pages:
- !include: home.yml
- !include: videos.yml
- !include: homelab.yml
-```
-
-The file you are including should not have any additional indentation, its values should be at the top level and the appropriate amount of indentation will be added automatically depending on where the file is included. Example:
-
-`glance.yml`
+If you don't want to spend time reading through all the available configuration options and just want something to get you going quickly you can use the following `glance.yml` and make changes as you see fit:
```yaml
pages:
- name: Home
columns:
+ - size: small
+ widgets:
+ - type: calendar
+
+ - type: rss
+ limit: 10
+ collapse-after: 3
+ cache: 3h
+ feeds:
+ - url: https://ciechanow.ski/atom.xml
+ - url: https://www.joshwcomeau.com/rss.xml
+ title: Josh Comeau
+ - url: https://samwho.dev/rss.xml
+ - url: https://awesomekling.github.io/feed.xml
+ - url: https://ishadeed.com/feed.xml
+ title: Ahmad Shadeed
+
+ - type: twitch-channels
+ channels:
+ - theprimeagen
+ - cohhcarnage
+ - christitustech
+ - blurbs
+ - asmongold
+ - jembawls
+
- size: full
widgets:
- !include: rss.yml
- - name: News
- columns:
- - size: full
+ - type: hacker-news
+
+ - type: videos
+ channels:
+ - UCR-DXc1voovS8nhAvccRZhg # Jeff Geerling
+ - UCv6J_jJa8GJqFwQNgNrMuww # ServeTheHome
+ - UCOk-gHyjcWZNj3Br4oxwh0A # Techno Tim
+
+ - type: reddit
+ subreddit: selfhosted
+
+ - size: small
widgets:
- - type: group
- widgets:
- !include: rss.yml
- - type: reddit
- subreddit: news
+ - type: weather
+ location: London, United Kingdom
+
+ - type: markets
+ markets:
+ - symbol: SPY
+ name: S&P 500
+ - symbol: BTC-USD
+ name: Bitcoin
+ - symbol: NVDA
+ name: NVIDIA
+ - symbol: AAPL
+ name: Apple
+ - symbol: MSFT
+ name: Microsoft
+ - symbol: GOOGL
+ name: Google
+ - symbol: AMD
+ name: AMD
+ - symbol: RDDT
+ name: Reddit
```
-`rss.yml`
+This will give you a page that looks like the following:
-```yaml
-- type: rss
- title: News
- feeds:
- - url: ${RSS_URL}
-```
+
-The `!include` directive can be used anywhere in the config file, not just in the `pages` property, however it must be on its own line and have the appropriate indentation.
-
-If you encounter YAML parsing errors when using the `!include` directive, the reported line numbers will likely be incorrect. This is because the inclusion of files is done before the YAML is parsed, as YAML itself does not support file inclusion. To help with debugging in cases like this, you can use the `config:print` command and pipe it into `less -N` to see the full config file with includes resolved and line numbers added:
-
-```sh
-glance --config /path/to/glance.yml config:print | less -N
-```
-
-This is a bit more convoluted when running Glance inside a Docker container:
-
-```sh
-docker run --rm -v ./glance.yml:/app/config/glance.yml glanceapp/glance config:print | less -N
-```
-
-This assumes that the config you want to print is in your current working directory and is named `glance.yml`.
+Configure the widgets, add more of them, add extra pages, etc. Make it your own!
## Server
Server configuration is done through a top level `server` property. Example:
@@ -164,7 +123,6 @@ server:
| ---- | ---- | -------- | ------- |
| host | string | no | |
| port | number | no | 8080 |
-| base-url | string | no | |
| assets-path | string | no | |
#### `host`
@@ -173,13 +131,6 @@ The address which the server will listen on. Setting it to `localhost` means tha
#### `port`
A number between 1 and 65,535, so long as that port isn't already used by anything else.
-#### `base-url`
-The base URL that Glance is hosted under. No need to specify this unless you're using a reverse proxy and are hosting Glance under a directory. If that's the case then you can set this value to `/glance` or whatever the directory is called. Note that the forward slash (`/`) in the beginning is required unless you specify the full domain and path.
-
-> [!IMPORTANT]
-> You need to strip the `base-url` prefix before forwarding the request to the Glance server.
-> In Caddy you can do this using [`handle_path`](https://caddyserver.com/docs/caddyfile/directives/handle_path) or [`uri strip_prefix`](https://caddyserver.com/docs/caddyfile/directives/uri).
-
#### `assets-path`
The path to a directory that will be served by the server under the `/assets/` path. This is handy for widgets like the Monitor where you have to specify an icon URL and you want to self host all the icons rather than pointing to an external source.
@@ -217,51 +168,6 @@ To be able to point to an asset from your assets path, use the `/assets/` path l
icon: /assets/gitea-icon.png
```
-## Document
-If you want to insert custom HTML into the `` of the document for all pages, you can do so by using the `document` property. Example:
-
-```yaml
-document:
- head: |
-
-```
-
-## Branding
-You can adjust the various parts of the branding through a top level `branding` property. Example:
-
-```yaml
-branding:
- custom-footer: |
-
- logo-url: /assets/logo.png
- favicon-url: /assets/logo.png
-```
-
-### Properties
-
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| hide-footer | bool | no | false |
-| custom-footer | string | no | |
-| logo-text | string | no | G |
-| logo-url | string | no | |
-| favicon-url | string | no | |
-
-#### `hide-footer`
-Hides the footer when set to `true`.
-
-#### `custom-footer`
-Specify custom HTML to use for the footer.
-
-#### `logo-text`
-Specify custom text to use instead of the "G" found in the navigation.
-
-#### `logo-url`
-Specify a URL to a custom image to use instead of the "G" found in the navigation. If both `logo-text` and `logo-url` are set, only `logo-url` will be used.
-
-#### `favicon-url`
-Specify a URL to a custom image to use for the favicon.
-
## Theme
Theming is done through a top level `theme` property. Values for the colors are in [HSL](https://giggster.com/guide/basics/hue-saturation-lightness/) (hue, saturation, lightness) format. You can use a color picker [like this one](https://hslpicker.com/) to convert colors from other formats to HSL. The values are separated by a space and `%` is not required for any of the numbers.
@@ -274,7 +180,7 @@ theme:
contrast-multiplier: 1.1
```
-### Available themes
+### Themes
If you don't want to spend time configuring your own theme, there are [several available themes](themes.md) which you can simply copy the values for.
### Properties
@@ -328,9 +234,6 @@ theme:
> .widget-type-rss a {
> font-size: 1.5rem;
> }
-> ```
->
-> In addition, you can also use the `css-class` property which is available on every widget to set custom class names for individual widgets.
## Pages & Columns
@@ -356,41 +259,17 @@ pages:
### Properties
| Name | Type | Required | Default |
| ---- | ---- | -------- | ------- |
-| name | string | yes | |
+| title | string | yes | |
| slug | string | no | |
-| width | string | no | |
-| center-vertically | boolean | no | false |
-| hide-desktop-navigation | boolean | no | false |
-| expand-mobile-page-navigation | boolean | no | false |
| show-mobile-header | boolean | no | false |
| columns | array | yes | |
-#### `name`
+#### `title`
The name of the page which gets shown in the navigation bar.
#### `slug`
The URL friendly version of the title which is used to access the page. For example if the title of the page is "RSS Feeds" you can make the page accessible via `localhost:8080/feeds` by setting the slug to `feeds`. If not defined, it will automatically be generated from the title.
-#### `width`
-The maximum width of the page on desktop. Possible values are `slim` and `wide`.
-
-* default: `1600px` (when no value is specified)
-* slim: `1100px`
-* wide: `1920px`
-
-> [!NOTE]
->
-> When using `slim`, the maximum number of columns allowed for that page is `2`.
-
-#### `center-vertically`
-When set to `true`, vertically centers the content on the page. Has no effect if the content is taller than the height of the viewport.
-
-#### `hide-desktop-navigation`
-Whether to show the navigation links at the top of the page on desktop.
-
-#### `expand-mobile-page-navigation`
-Whether the mobile page navigation should be expanded by default.
-
#### `show-mobile-header`
Whether to show a header displaying the name of the page on mobile. The header purposefully has a lot of vertical whitespace in order to push the content down and make it easier to reach on tall devices.
@@ -475,9 +354,7 @@ pages:
| ---- | ---- | -------- |
| type | string | yes |
| title | string | no |
-| title-url | string | no |
| cache | string | no |
-| css-class | string | no |
#### `type`
Used to specify the widget.
@@ -485,9 +362,6 @@ Used to specify the widget.
#### `title`
The title of the widget. If left blank it will be defined by the widget.
-#### `title-url`
-The URL to go to when clicking on the widget's title. If left blank it will be defined by the widget (if available).
-
#### `cache`
How long to keep the fetched data in memory. The value is a string and must be a number followed by one of s, m, h, d. Examples:
@@ -502,9 +376,6 @@ cache: 1d # 1 day
>
> Not all widgets can have their cache duration modified. The calendar and weather widgets update on the hour and this cannot be changed.
-#### `css-class`
-Set custom CSS classes for the specific widget instance.
-
### RSS
Display a list of articles from multiple RSS feeds.
@@ -531,31 +402,10 @@ Example:
| thumbnail-height | float | no | 10 |
| card-height | float | no | 27 |
| limit | integer | no | 25 |
-| preserve-order | bool | no | false |
-| single-line-titles | boolean | no | false |
| collapse-after | integer | no | 5 |
-##### `limit`
-The maximum number of articles to show.
-
-##### `collapse-after`
-How many articles are visible before the "SHOW MORE" button appears. Set to `-1` to never collapse.
-
-##### `preserve-order`
-When set to `true`, the order of the articles will be preserved as they are in the feeds. Useful if a feed uses its own sorting order which denotes the importance of the articles. If you use this property while having a lot of feeds, it's recommended to set a `limit` to each individual feed since if the first defined feed has 15 articles, the articles from the second feed will start after the 15th article in the list.
-
-##### `single-line-titles`
-When set to `true`, truncates the title of each post if it exceeds one line. Only applies when the style is set to `vertical-list`.
-
##### `style`
-Used to change the appearance of the widget. Possible values are:
-
-* `vertical-list` - suitable for `full` and `small` columns
-* `detailed-list` - suitable for `full` columns
-* `horizontal-cards` - suitable for `full` columns
-* `horizontal-cards-2` - suitable for `full` columns
-
-Below is a preview of each style:
+Used to change the appearance of the widget. Possible values are `vertical-list` and `horizontal-cards` where the former is intended to be used within a small column and the latter a full column. Below are previews of each style.
`vertical-list`
@@ -589,26 +439,16 @@ An array of RSS/atom feeds. The title can optionally be changed.
| title | string | no | the title provided by the feed | |
| hide-categories | boolean | no | false | Only applicable for `detailed-list` style |
| hide-description | boolean | no | false | Only applicable for `detailed-list` style |
-| limit | integer | no | | |
| item-link-prefix | string | no | | |
-| headers | key (string) & value (string) | no | | |
-
-###### `limit`
-The maximum number of articles to show from that specific feed. Useful if you have a feed which posts a lot of articles frequently and you want to prevent it from excessively pushing down articles from other feeds.
###### `item-link-prefix`
If an RSS feed isn't returning item links with a base domain and Glance has failed to automatically detect the correct domain you can manually add a prefix to each link with this property.
-###### `headers`
-Optionally specify the headers that will be sent with the request. Example:
+##### `limit`
+The maximum number of articles to show.
-```yaml
-- type: rss
- feeds:
- - url: https://domain.com/rss
- headers:
- User-Agent: Custom User Agent
-```
+##### `collapse-after`
+How many articles are visible before the "SHOW MORE" button appears. Set to `-1` to never collapse.
### Videos
Display a list of the latest videos from specific YouTube channels.
@@ -630,18 +470,13 @@ Preview:
| Name | Type | Required | Default |
| ---- | ---- | -------- | ------- |
| channels | array | yes | |
-| playlists | array | no | |
| limit | integer | no | 25 |
| style | string | no | horizontal-cards |
-| collapse-after | integer | no | 7 |
| collapse-after-rows | integer | no | 4 |
-| include-shorts | boolean | no | false |
| video-url-template | string | no | https://www.youtube.com/watch?v={VIDEO-ID} |
##### `channels`
-A list of channels IDs.
-
-One way of getting the ID of a channel is going to the channel's page and clicking on its description:
+A list of channel IDs. One way of getting the ID of a channel is going to the channel's page and clicking on its description:

@@ -649,32 +484,14 @@ Then scroll down and click on "Share channel", then "Copy channel ID":

-##### `playlists`
-
-A list of playlist IDs:
-
-```yaml
-- type: videos
- playlists:
- - PL8mG-RkN2uTyZZ00ObwZxxoG_nJbs3qec
- - PL8mG-RkN2uTxTK4m_Vl2dYR9yE41kRdBg
-```
-
##### `limit`
The maximum number of videos to show.
-##### `collapse-after`
-Specify the number of videos to show when using the `vertical-list` style before the "SHOW MORE" button appears.
-
##### `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 `horizontal-cards`, `vertical-list` and `grid-cards`.
-
-Preview of `vertical-list`:
-
-
+Used to change the appearance of the widget. Possible values are `horizontal-cards` and `grid-cards`.
Preview of `grid-cards`:
@@ -755,23 +572,11 @@ Preview:
#### Properties
| Name | Type | Required | Default |
| ---- | ---- | -------- | ------- |
-| instance-url | string | no | https://lobste.rs/ |
-| custom-url | string | no | |
| limit | integer | no | 15 |
| collapse-after | integer | no | 5 |
| sort-by | string | no | hot |
| tags | array | no | |
-##### `instance-url`
-The base URL for a lobsters instance hosted somewhere other than on lobste.rs. Example:
-
-```yaml
-instance-url: https://www.journalduhacker.net/
-```
-
-##### `custom-url`
-A custom URL to retrieve lobsters posts from. If this is specified, the `instance-url`, `sort-by` and `tags` properties are ignored.
-
##### `limit`
The maximum number of posts to show.
@@ -804,12 +609,10 @@ Example:
| subreddit | string | yes | |
| style | string | no | vertical-list |
| show-thumbnails | boolean | no | false |
-| show-flairs | boolean | no | false |
| limit | integer | no | 15 |
| collapse-after | integer | no | 5 |
| comments-url-template | string | no | https://www.reddit.com/{POST-PATH} |
| request-url-template | string | no | |
-| proxy | string or multiple parameters | no | |
| sort-by | string | no | hot |
| top-period | string | no | day |
| search | string | no | |
@@ -842,9 +645,6 @@ Shows or hides thumbnails next to the post. This only works if the `style` is `v
>
> Thumbnails don't work for some subreddits due to Reddit's API not returning the thumbnail URL. No workaround for this yet.
-##### `show-flairs`
-Shows post flairs when set to `true`.
-
##### `limit`
The maximum number of posts to show.
@@ -871,7 +671,7 @@ r/selfhosted/comments/bsp01i/welcome_to_rselfhosted_please_read_this_first/
`{SUBREDDIT}` - the subreddit name
##### `request-url-template`
-A custom request URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to route them through a proxy that accepts the URL as either a part of the path or a query parameter.
+A custom request url that will be used to fetch the data instead. This is useful when you're hosting Glance on a VPS and Reddit is blocking the requests, and you want to route it through an HTTP proxy.
Placeholders:
@@ -882,29 +682,6 @@ https://proxy/{REQUEST-URL}
https://your.proxy/?url={REQUEST-URL}
```
-##### `proxy`
-A custom HTTP/HTTPS proxy URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to bypass the restriction by routing the requests through a proxy. Example:
-
-```yaml
-proxy: http://user:pass@proxy.com:8080
-proxy: https://user:pass@proxy.com:443
-```
-
-Alternatively, you can specify the proxy URL as well as additional options by using multiple parameters:
-
-```yaml
-proxy:
- url: http://proxy.com:8080
- allow-insecure: true
- timeout: 10s
-```
-
-###### `allow-insecure`
-When set to `true`, allows the use of insecure connections such as when the proxy has a self-signed certificate.
-
-###### `timeout`
-The maximum time to wait for a response from the proxy. The value is a string and must be a number followed by one of s, m, h, d. Example: `10s` for 10 seconds, `1m` for 1 minute, etc
-
##### `sort-by`
Can be used to specify the order in which the posts should get returned. Possible values are `hot`, `new`, `top` and `rising`.
@@ -946,19 +723,11 @@ Preview:
| Enter | Perform search in the same tab | Search input is focused and not empty |
| Ctrl + Enter | Perform search in a new tab | Search input is focused and not empty |
| Escape | Leave focus | Search input is focused |
-| Up | Insert the last search query since the page was opened into the input field | Search input is focused |
-
-> [!TIP]
->
-> You can use the property `new-tab` with a value of `true` if you want to show search results in a new tab by default. Ctrl + Enter will then show results in the same tab.
#### Properties
| Name | Type | Required | Default |
| ---- | ---- | -------- | ------- |
| search-engine | string | no | duckduckgo |
-| new-tab | boolean | no | false |
-| autofocus | boolean | no | false |
-| placeholder | string | no | Type here to search… |
| bangs | array | no | |
##### `search-engine`
@@ -969,15 +738,6 @@ Either a value from the table below or a URL to a custom search engine. Use `{QU
| duckduckgo | `https://duckduckgo.com/?q={QUERY}` |
| google | `https://www.google.com/search?q={QUERY}` |
-##### `new-tab`
-When set to `true`, swaps the shortcuts for showing results in the same or new tab, defaulting to showing results in a new tab.
-
-##### `autofocus`
-When set to `true`, automatically focuses the search input on page load.
-
-##### `placeholder`
-When set, modifies the text displayed in the input field before typing.
-
##### `bangs`
What now? [Bangs](https://duckduckgo.com/bangs). They're shortcuts that allow you to use the same search box for many different sites. Assuming you have it configured, if for example you start your search input with `!yt` you'd be able to perform a search on YouTube:
@@ -1012,394 +772,6 @@ url: https://store.steampowered.com/search/?term={QUERY}
url: https://www.amazon.com/s?k={QUERY}
```
-### Group
-Group multiple widgets into one using tabs. Widgets are defined using a `widgets` property exactly as you would on a page column. The only limitation is that you cannot place a group widget or a split column widget within a group widget.
-
-Example:
-
-```yaml
-- type: group
- widgets:
- - type: reddit
- subreddit: gamingnews
- show-thumbnails: true
- collapse-after: 6
- - type: reddit
- subreddit: games
- - type: reddit
- subreddit: pcgaming
- show-thumbnails: true
-```
-
-Preview:
-
-
-
-#### Sharing properties
-
-To avoid repetition you can use [YAML anchors](https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/) and share properties between widgets.
-
-Example:
-
-```yaml
-- type: group
- define: &shared-properties
- type: reddit
- show-thumbnails: true
- collapse-after: 6
- widgets:
- - subreddit: gamingnews
- <<: *shared-properties
- - subreddit: games
- <<: *shared-properties
- - subreddit: pcgaming
- <<: *shared-properties
-```
-
-### Split Column
-Splits a full sized column in half, allowing you to place widgets side by side horizontally. This is converted to a single column on mobile devices or if not enough width is available. Widgets are defined using a `widgets` property exactly as you would on a page column.
-
-Two widgets side by side in a `full` column:
-
-
-
-
-View glance.yml
-
-
-```yaml
-# ...
-- size: full
- widgets:
- - type: split-column
- widgets:
- - type: hacker-news
- collapse-after: 3
- - type: lobsters
- collapse-after: 3
-
- - type: videos
-# ...
-```
-
-
-
-You can also achieve a number of different full page layouts using just this widget, such as:
-
-3 column layout where all columns have equal width:
-
-
-
-
-View glance.yml
-
-
-```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
-```
-
-
-
-4 column layout where all columns have equal width (and the page is set to `width: wide`):
-
-
-
-
-View glance.yml
-
-
-```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
-```
-
-
-
-Masonry layout with up to 5 columns where all columns have equal width (and the page is set to `width: wide`):
-
-
-
-
-View glance.yml
-
-
-```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
-```
-
-
-
-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.
-
-
-### Custom API
-
-Display data from a JSON API using a custom template.
-
-> [!NOTE]
->
-> The configuration of this widget requires some basic knowledge of programming, HTML, CSS, the Go template language and Glance-specific concepts.
-
-Examples:
-
-
-
-
-View glance.yml
-
-
-```yaml
-- type: custom-api
- title: Random Fact
- cache: 6h
- url: https://uselessfacts.jsph.pl/api/v2/facts/random
- template: |
-
-```
-
-
-#### Properties
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| url | string | yes | |
-| headers | key (string) & value (string) | no | |
-| method | string | no | GET |
-| body-type | string | no | json |
-| body | any | no | |
-| frameless | boolean | no | false |
-| allow-insecure | boolean | no | false |
-| skip-json-validation | boolean | no | false |
-| template | string | yes | |
-| parameters | key (string) & value (string|array) | no | |
-| subrequests | map of requests | no | |
-
-##### `url`
-The URL to fetch the data from. It must be accessible from the server that Glance is running on.
-
-##### `headers`
-Optionally specify the headers that will be sent with the request. Example:
-
-```yaml
-headers:
- x-api-key: your-api-key
- Accept: application/json
-```
-
-##### `method`
-The HTTP method to use when making the request. Possible values are `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS` and `HEAD`.
-
-##### `body-type`
-The type of the body that will be sent with the request. Possible values are `json`, and `string`.
-
-##### `body`
-The body that will be sent with the request. It can be a string or a map. Example:
-
-```yaml
-body-type: json
-body:
- key1: value1
- key2: value2
- multiple-items:
- - item1
- - item2
-```
-
-```yaml
-body-type: string
-body: |
- key1=value1&key2=value2
-```
-
-##### `frameless`
-When set to `true`, removes the border and padding around the widget.
-
-##### `allow-insecure`
-Whether to ignore invalid/self-signed certificates.
-
-##### `skip-json-validation`
-When set to `true`, skips the JSON validation step. This is useful when the API returns JSON Lines/newline-delimited JSON, which is a format that consists of several JSON objects separated by newlines.
-
-##### `template`
-The template that will be used to display the data. It relies on Go's `html/template` package so it's recommended to go through [its documentation](https://pkg.go.dev/text/template) to understand how to do basic things such as conditionals, loops, etc. In addition, it also uses [tidwall's gjson](https://github.com/tidwall/gjson) package to parse the JSON data so it's worth going through its documentation if you want to use more advanced JSON selectors. You can view additional examples with explanations and function definitions [here](custom-api.md).
-
-##### `parameters`
-A list of keys and values that will be sent to the custom-api as query paramters.
-
-##### `subrequests`
-A map of additional requests that will be executed concurrently and then made available in the template via the `.Subrequest` property. Example:
-
-```yaml
-- type: custom-api
- cache: 2h
- subrequests:
- another-one:
- url: https://uselessfacts.jsph.pl/api/v2/facts/random
- title: Random Fact
- url: https://uselessfacts.jsph.pl/api/v2/facts/random
- template: |
-
-```
-
-The subrequests support all the same properties as the main request, except for `subrequests` itself, so you can use `headers`, `parameters`, etc.
-
-`(.Subrequest "key")` can be a little cumbersome to write, so you can define a variable to make it easier:
-
-```yaml
- template: |
- {{ $anotherOne := .Subrequest "another-one" }}
-
{{ $anotherOne.JSON.String "text" }}
-```
-
-You can also access the `.Response` property of a subrequest as you would with the main request:
-
-```yaml
- template: |
- {{ $anotherOne := .Subrequest "another-one" }}
-
{{ $anotherOne.Response.StatusCode }}
-```
-
-> [!NOTE]
->
-> Setting this property will override any query parameters that are already in the URL.
-
-```yaml
-parameters:
- param1: value1
- param2:
- - item1
- - item2
-```
-
### Extension
Display a widget provided by an external source (3rd party). If you want to learn more about developing extensions, checkout the [extensions documentation](extensions.md) (WIP).
@@ -1415,24 +787,11 @@ Display a widget provided by an external source (3rd party). If you want to lear
| Name | Type | Required | Default |
| ---- | ---- | -------- | ------- |
| url | string | yes | |
-| fallback-content-type | string | no | |
| allow-potentially-dangerous-html | boolean | no | false |
-| headers | key & value | no | |
| parameters | key & value | no | |
##### `url`
-The URL of the extension. **Note that the query gets stripped from this URL and the one defined by `parameters` gets used instead.**
-
-##### `fallback-content-type`
-Optionally specify the fallback content type of the extension if the URL does not return a valid `Widget-Content-Type` header. Currently the only supported value for this property is `html`.
-
-##### `headers`
-Optionally specify the headers that will be sent with the request. Example:
-
-```yaml
-headers:
- x-api-key: ${SECRET_KEY}
-```
+The URL of the extension.
##### `allow-potentially-dangerous-html`
Whether to allow the extension to display HTML.
@@ -1542,21 +901,13 @@ You can hover over the "ERROR" text to view more information.
#### Properties
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| sites | array | yes | |
-| style | string | no | |
-| show-failing-only | boolean | no | false |
-
-##### `show-failing-only`
-Shows only a list of failing sites when set to `true`.
+| Name | Type | Required |
+| ---- | ---- | -------- |
+| sites | array | yes |
+| style | string | no |
##### `style`
-Used to change the appearance of the widget. Possible values are `compact`.
-
-Preview of `compact`:
-
-
+To make the widget scale appropriately in a `full` size column, set the style to the experimental `dynamic-columns-experimental` option.
##### `sites`
@@ -1566,12 +917,9 @@ Properties for each site:
| ---- | ---- | -------- | ------- |
| title | string | yes | |
| url | string | yes | |
-| check-url | string | no | |
-| error-url | string | no | |
| icon | string | no | |
| allow-insecure | boolean | no | false |
| same-tab | boolean | no | false |
-| alt-status-codes | array | no | |
`title`
@@ -1579,19 +927,11 @@ The title used to indicate the site.
`url`
-The public facing URL of a monitored service, the user will be redirected here. If `check-url` is not specified, this is used as the status check.
-
-`check-url`
-
-The URL which will be requested and its response will determine the status of the site. If not specified, the `url` property is used.
-
-`error-url`
-
-If the monitored service returns an error, the user will be redirected here. If not specified, the `url` property is used.
+The URL which will be requested and its response will determine the status of the site. Optionally, you can specify this using an environment variable with the syntax `${VARIABLE_NAME}`.
`icon`
-Optional URL to an image which will be used as the icon for the site. Can be an external URL or internal via [server configured assets](#assets-path). You can also directly use [Simple Icons](https://simpleicons.org/) via a `si:` prefix or [Dashboard Icons](https://github.com/walkxcode/dashboard-icons) via a `di:` prefix:
+Optional URL to an image which will be used as the icon for the site. Can be an external URL or internal via [server configured assets](#assets-path). You can also directly use [Simple Icons](https://simpleicons.org/) via a `si:` prefix:
```yaml
icon: si:jellyfin
@@ -1601,7 +941,7 @@ icon: si:adguard
> [!WARNING]
>
-> Simple Icons are loaded externally and are hosted on `cdn.jsdelivr.net`, if you do not wish to depend on a 3rd party you are free to download the icons individually and host them locally.
+> Simple Icons are loaded externally and are hosted on `cdnjs.cloudflare.com`, if you do not wish to depend on a 3rd party you are free to download the icons individually and host them locally.
`allow-insecure`
@@ -1611,30 +951,18 @@ Whether to ignore invalid/self-signed certificates.
Whether to open the link in the same or a new tab.
-`alt-status-codes`
-
-Status codes other than 200 that you want to return "OK".
-
-```yaml
-alt-status-codes:
- - 403
-```
-
### Releases
-Display a list of latest releases for specific repositories on Github, GitLab, Codeberg or Docker Hub.
+Display a list of releases for specific repositories on Github. Draft releases and prereleases will not be shown.
Example:
```yaml
- type: releases
- show-source-icon: true
repositories:
+ - immich-app/immich
- go-gitea/gitea
+ - dani-garcia/vaultwarden
- jellyfin/jellyfin
- - glanceapp/glance
- - codeberg:redict/redict
- - gitlab:fdroid/fdroidclient
- - dockerhub:gotify/server
```
Preview:
@@ -1646,53 +974,12 @@ Preview:
| Name | Type | Required | Default |
| ---- | ---- | -------- | ------- |
| repositories | array | yes | |
-| show-source-icon | boolean | no | false | |
| token | string | no | |
-| gitlab-token | string | no | |
| limit | integer | no | 10 |
| collapse-after | integer | no | 5 |
##### `repositories`
-A list of repositores to fetch the latest release for. Only the name/repo is required, not the full URL. A prefix can be specified for repositories hosted elsewhere such as GitLab, Codeberg and Docker Hub. Example:
-
-```yaml
-repositories:
- - gitlab:inkscape/inkscape
- - dockerhub:glanceapp/glance
- - codeberg:redict/redict
-```
-
-Official images on Docker Hub can be specified by omitting the owner:
-
-```yaml
-repositories:
- - dockerhub:nginx
- - dockerhub:node
- - dockerhub:alpine
-```
-
-You can also specify exact tags for Docker Hub images:
-
-```yaml
-repositories:
- - dockerhub:nginx:latest
- - dockerhub:nginx:stable-alpine
-```
-
-To include prereleases you can specify the repository as an object and use the `include-prereleases` property:
-
-**Note: This feature is currently only available for GitHub repositories.**
-
-```yaml
-repositories:
- - gitlab:inkscape/inkscape
- - repository: glanceapp/glance
- include-prereleases: true
- - codeberg:redict/redict
-```
-
-##### `show-source-icon`
-Shows an icon of the source (GitHub/GitLab/Codeberg/Docker Hub) next to the repository name when set to `true`.
+A list of repositores for which to fetch the latest release for. Only the name/repo is required, not the full URL.
##### `token`
Without authentication Github allows for up to 60 requests per hour. You can easily exceed this limit and start seeing errors if you're tracking lots of repositories or your cache time is low. To circumvent this you can [create a read only token from your Github account](https://github.com/settings/personal-access-tokens/new) and provide it here.
@@ -1704,7 +991,7 @@ services:
glance:
image: glanceapp/glance
environment:
- - GITHUB_TOKEN=
+ - GITHUB_TOKEN:
```
and then use it in your `glance.yml` like this:
@@ -1717,303 +1004,12 @@ and then use it in your `glance.yml` like this:
This way you can safely check your `glance.yml` in version control without exposing the token.
-##### `gitlab-token`
-Same as the above but used when fetching GitLab releases.
-
##### `limit`
The maximum number of releases to show.
#### `collapse-after`
How many releases are visible before the "SHOW MORE" button appears. Set to `-1` to never collapse.
-### Docker Containers
-
-Display the status of your Docker containers along with an icon and an optional short description.
-
-
-
-```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:
-
-
-View docker-compose.yml
-
-
-```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
-```
-
-
-
-This will place all child containers under the `Immich` container when hovering over its icon:
-
-
-
-If any of the child containers are down, their status will propagate up to the parent container:
-
-
-
-#### Properties
-
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| hide-by-default | boolean | no | false |
-| sock-path | string | no | /var/run/docker.sock |
-
-##### `hide-by-default`
-Whether to hide the containers by default. If set to `true` you'll have to manually add a `glance.hide: false` label to each container you want to display. By default all containers will be shown and if you want to hide a specific container you can add a `glance.hide: true` label.
-
-##### `sock-path`
-The path to the Docker socket.
-
-#### Labels
-| Name | Description |
-| ---- | ----------- |
-| glance.name | The name displayed in the UI. If not specified, the name of the container will be used. |
-| glance.icon | The icon displayed in the UI. Can be an external URL or an icon prefixed with si:, sh: or di: like with the bookmarks and monitor widgets |
-| glance.url | The URL that the user will be redirected to when clicking on the container. |
-| glance.same-tab | Whether to open the link in the same or a new tab. Default is `false`. |
-| glance.description | A short description displayed in the UI. Default is empty. |
-| glance.hide | Whether to hide the container. If set to `true` the container will not be displayed. Defaults to `false`. |
-| glance.id | The custom ID of the container. Used to group containers under a single parent. |
-| glance.parent | The ID of the parent container. Used to group containers under a single parent. |
-
-### DNS Stats
-Display statistics from a self-hosted ad-blocking DNS resolver such as AdGuard Home or Pi-hole.
-
-Example:
-
-```yaml
-- type: dns-stats
- service: adguard
- url: https://adguard.domain.com/
- username: admin
- password: ${ADGUARD_PASSWORD}
-```
-
-Preview:
-
-
-
-> [!NOTE]
->
-> When using AdGuard Home the 3rd statistic on top will be the average latency and when using Pi-hole it will be the total number of blocked domains from all adlists.
-
-#### Properties
-
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| service | string | no | pihole |
-| allow-insecure | bool | no | false |
-| url | string | yes | |
-| username | string | when service is `adguard` | |
-| password | string | when service is `adguard` or `pihole-v6` | |
-| token | string | when service is `pihole` | |
-| hide-graph | bool | no | false |
-| hide-top-domains | bool | no | false |
-| hour-format | string | no | 12h |
-
-##### `service`
-Either `adguard`, or `pihole` (major version 5 and below) or `pihole-v6` (major version 6 and above).
-
-##### `allow-insecure`
-Whether to allow invalid/self-signed certificates when making the request to the service.
-
-##### `url`
-The base URL of the service.
-
-##### `username`
-Only required when using AdGuard Home. The username used to log into the admin dashboard.
-
-##### `password`
-Required when using AdGuard Home, where the password is the one used to log into the admin dashboard.
-
-Also requried when using Pi-hole major version 6 and above, where the password is the one used to log into the admin dashboard or the application password, which can be found in `Settings -> Web Interface / API -> Configure app password`.
-
-##### `token`
-Only required when using Pi-hole major version 5 or earlier. The API token which can be found in `Settings -> API -> Show API token`.
-
-##### `hide-graph`
-Whether to hide the graph showing the number of queries over time.
-
-##### `hide-top-domains`
-Whether to hide the list of top blocked domains.
-
-##### `hour-format`
-Whether to display the relative time in the graph in `12h` or `24h` format.
-
-### Server Stats
-Display statistics such as CPU usage, memory usage and disk usage of the server Glance is running on or other servers.
-
-Example:
-
-```yaml
-- type: server-stats
- servers:
- - type: local
- name: Services
-```
-
-Preview:
-
-
-
-> [!NOTE]
->
-> This widget is currently under development, some features might not function as expected or may change.
-
-To display data from a remote server you need to have the Glance Agent running on that server. You can download the agent from [here](https://github.com/glanceapp/agent), though keep in mind that it is still in development and may not work as expected. Support for other providers such as Glances will be added in the future.
-
-In the event that the CPU temperature goes over 80°C, a flame icon will appear next to the CPU. The progress indicators will also turn red (or the equivalent of your negative color) to hopefully grab your attention if anything is unusually high:
-
-
-
-#### Properties
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| servers | array | no | |
-
-##### `servers`
-If not provided it will display the statistics of the server Glance is running on.
-
-##### Properties for both `local` and `remote` servers
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| type | string | yes | |
-| name | string | no | |
-| hide-swap | boolean | no | false |
-
-###### `type`
-Whether to display statistics for the local server or a remote server. Possible values are `local` and `remote`.
-
-###### `name`
-The name of the server which will be displayed on the widget. If not provided it will default to the server's hostname.
-
-###### `hide-swap`
-Whether to hide the swap usage.
-
-##### Properties for the `local` server
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| cpu-temp-sensor | string | no | |
-| hide-mountpoints-by-default | boolean | no | false |
-| mountpoints | map\[string\]object | no | |
-
-###### `cpu-temp-sensor`
-The name of the sensor to use for the CPU temperature. When not provided the widget will attempt to find the correct one, if it fails to do so the temperature will not be displayed. To view the available sensors you can use `sensors` command.
-
-###### `hide-mountpoints-by-default`
-If set to `true` you'll have to manually make each mountpoint visible by adding a `hide: false` property to it like so:
-
-```yaml
-- type: server-stats
- servers:
- - type: local
- hide-mountpoints-by-default: true
- mountpoints:
- "/":
- hide: false
- "/mnt/data":
- hide: false
-```
-
-This is useful if you're running Glance inside of a container which usually mounts a lot of irrelevant filesystems.
-
-###### `mountpoints`
-A map of mountpoints to display disk usage for. The key is the path to the mountpoint and the value is an object with optional properties. Example:
-
-```yaml
-mountpoints:
- "/":
- name: Root
- "/mnt/data":
- name: Data
- "/boot/efi":
- hide: true
-```
-
-##### Properties for each `mountpoint`
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| name | string | no | |
-| hide | boolean | no | false |
-
-###### `name`
-The name of the mountpoint which will be displayed on the widget. If not provided it will default to the mountpoint's path.
-
-###### `hide`
-Whether to hide this mountpoint from the widget.
-
-##### Properties for `remote` servers
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| url | string | yes | |
-| token | string | no | |
-| timeout | string | no | 3s |
-
-###### `url`
-The URL and port of the server to fetch the statistics from.
-
-###### `token`
-The authentication token to use when fetching the statistics.
-
-###### `timeout`
-The maximum time to wait for a response from the server. The value is a string and must be a number followed by one of s, m, h, d. Example: `10s` for 10 seconds, `1m` for 1 minute, etc
-
### Repository
Display general information about a repository as well as a list of the latest open pull requests and issues.
@@ -2024,7 +1020,6 @@ Example:
repository: glanceapp/glance
pull-requests-limit: 5
issues-limit: 3
- commits-limit: 3
```
Preview:
@@ -2039,7 +1034,6 @@ Preview:
| token | string | no | |
| pull-requests-limit | integer | no | 3 |
| issues-limit | integer | no | 3 |
-| commits-limit | integer | no | -1 |
##### `repository`
The owner and repository name that will have their information displayed.
@@ -2053,9 +1047,6 @@ The maximum number of latest open pull requests to show. Set to `-1` to not show
##### `issues-limit`
The maximum number of latest open issues to show. Set to `-1` to not show any.
-##### `commits-limit`
-The maximum number of lastest commits to show from the default branch. Set to `-1` to not show any.
-
### Bookmarks
Display a list of links which can be grouped.
@@ -2105,23 +1096,20 @@ Preview:
| Name | Type | Required |
| ---- | ---- | -------- |
| groups | array | yes |
+| style | string | no |
##### `groups`
An array of groups which can optionally have a title and a custom color.
+##### `style`
+To make the widget scale appropriately in a `full` size column, set the style to the experimental `dynamic-columns-experimental` option.
+
###### Properties for each group
| Name | Type | Required | Default |
| ---- | ---- | -------- | ------- |
| title | string | no | |
| color | HSL | no | the primary color of the theme |
| links | array | yes | |
-| same-tab | boolean | no | false |
-| hide-arrow | boolean | no | false |
-| target | string | no | |
-
-> [!TIP]
->
-> You can set `same-tab`, `hide-arrow` and `target` either on the group which will apply them to all links in that group, or on each individual link which will override the value set on the group.
###### Properties for each link
| Name | Type | Required | Default |
@@ -2131,11 +1119,10 @@ An array of groups which can optionally have a title and a custom color.
| icon | string | no | |
| same-tab | boolean | no | false |
| hide-arrow | boolean | no | false |
-| target | string | no | |
`icon`
-URL pointing to an image. You can also directly use [Simple Icons](https://simpleicons.org/) via a `si:` prefix or [Dashboard Icons](https://github.com/walkxcode/dashboard-icons) via a `di:` prefix:
+URL pointing to an image. You can also directly use [Simple Icons](https://simpleicons.org/) via a `si:` prefix:
```yaml
icon: si:gmail
@@ -2145,7 +1132,7 @@ icon: si:reddit
> [!WARNING]
>
-> Simple Icons are loaded externally and are hosted on `cdn.jsdelivr.net`, if you do not wish to depend on a 3rd party you are free to download the icons individually and host them locally.
+> Simple Icons are loaded externally and are hosted on `cdnjs.cloudflare.com`, if you do not wish to depend on a 3rd party you are free to download the icons individually and host them locally.
`same-tab`
@@ -2155,10 +1142,6 @@ Whether to open the link in the same tab or a new one.
Whether to hide the colored arrow on each link.
-`target`
-
-Set a custom value for the link's `target` attribute. Possible values are `_blank`, `_self`, `_parent` and `_top`, you can read more about what they do [here](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target). This property has precedence over `same-tab`.
-
### ChangeDetection.io
Display a list watches from changedetection.io.
@@ -2258,52 +1241,15 @@ Example:
```yaml
- type: calendar
- first-day-of-week: monday
```
Preview:

-#### Properties
-
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| first-day-of-week | string | no | monday |
-
-##### `first-day-of-week`
-The day of the week that the calendar starts on. All week days are available as possible values.
-
-### Calendar (legacy)
-Display a calendar.
-
-Example:
-
-```yaml
-- type: calendar-legacy
- start-sunday: false
-```
-
-Preview:
-
-
-
> [!NOTE]
>
-> This widget is deprecated and may be removed in a future version.
-
-#### Properties
-
-| Name | Type | Required | Default |
-| ---- | ---- | -------- | ------- |
-| start-sunday | boolean | no | false |
-
-##### `start-sunday`
-Whether calendar weeks start on Sunday or Monday.
-
-> [!NOTE]
->
-> There is currently little customizability available for the calendar. Extra features will be added in the future.
+> There is currently no customizability available for the calendar. Extra features will be added in the future.
### Markets
Display a list of markets, their current value, change for the day and a small 21d chart. Data is taken from Yahoo Finance.
@@ -2335,30 +1281,18 @@ Preview:
| ---- | ---- | -------- |
| markets | array | yes |
| sort-by | string | no |
-| chart-link-template | string | no |
-| symbol-link-template | string | no |
+| style | string | no |
##### `markets`
An array of markets for which to display information about.
##### `sort-by`
-By default the markets are displayed in the order they were defined. You can customize their ordering by setting the `sort-by` property to `change` for descending order based on the stock's percentage change (e.g. 1% would be sorted higher than -1%) or `absolute-change` for descending order based on the stock's absolute price change (e.g. -1% would be sorted higher than +0.5%).
+By default the markets are displayed in the order they were defined. You can customize their ordering by setting the `sort-by` property to `absolute-change` for descending order based on the stock's absolute price change.
-##### `chart-link-template`
-A template for the link to go to when clicking on the chart that will be applied to all markets. The value `{SYMBOL}` will be replaced with the symbol of the market. You can override this on a per-market basis by specifying a `chart-link` property. Example:
+##### `style`
+To make the widget scale appropriately in a `full` size column, set the style to the experimental `dynamic-columns-experimental` option.
-```yaml
-chart-link-template: https://www.tradingview.com/chart/?symbol={SYMBOL}
-```
-
-##### `symbol-link-template`
-A template for the link to go to when clicking on the symbol that will be applied to all markets. The value `{SYMBOL}` will be replaced with the symbol of the market. You can override this on a per-market basis by specifying a `symbol-link` property. Example:
-
-```yaml
-symbol-link-template: https://www.google.com/search?tbm=nws&q={SYMBOL}
-```
-
-###### Properties for each market
+###### Properties for each stock
| Name | Type | Required |
| ---- | ---- | -------- |
| symbol | string | yes |
@@ -2375,11 +1309,9 @@ The symbol, as seen in Yahoo Finance.
The name that will be displayed under the symbol.
`symbol-link`
-
The link to go to when clicking on the symbol.
`chart-link`
-
The link to go to when clicking on the chart.
### Twitch Channels
diff --git a/docs/custom-api.md b/docs/custom-api.md
deleted file mode 100644
index d42d1fc..0000000
--- a/docs/custom-api.md
+++ /dev/null
@@ -1,415 +0,0 @@
-[Jump to function definitions](#functions)
-
-## Examples
-
-The best way to get an idea of how the templates work would be with a bunch examples. Here are the most common use cases:
-
-JSON response:
-
-```json
-{
- "title": "My Title",
- "content": "My Content",
-}
-```
-
-To access the two fields in the JSON response, you would use the following:
-
-```html
-
{{ .JSON.String "title" }}
-
{{ .JSON.String "content" }}
-```
-
-Output:
-
-```html
-
My Title
-
My Content
-```
-
-
-
-JSON response:
-
-```json
-{
- "author": "John Doe",
- "posts": [
- {
- "title": "My Title",
- "content": "My Content"
- },
- {
- "title": "My Title 2",
- "content": "My Content 2"
- }
- ]
-}
-```
-
-To loop through the array of posts, you would use the following:
-
-```html
-{{ range .JSON.Array "posts" }}
-
{{ .String "title" }}
-
{{ .String "content" }}
-{{ end }}
-```
-
-Output:
-
-```html
-
My Title
-
My Content
-
My Title 2
-
My Content 2
-```
-
-Notice the missing `.JSON` when accessing the title and content, this is because the range function sets the context to the current array element.
-
-If you want to access the top-level context within the range, you can use the following:
-
-```html
-{{ range .JSON.Array "posts" }}
-
{{ .String "title" }}
-
{{ .String "content" }}
-
{{ $.JSON.String "author" }}
-{{ end }}
-```
-
-Output:
-
-```html
-
My Title
-
My Content
-
John Doe
-
My Title 2
-
My Content 2
-
John Doe
-```
-
-
-
-JSON response:
-
-```json
-[
- "Apple",
- "Banana",
- "Cherry",
- "Watermelon"
-]
-```
-
-Somewhat awkwardly, when the current context is a basic type that isn't an object, the way you specify its type is to use an empty string as the key. So, to loop through the array of strings, you would use the following:
-
-```html
-{{ range .JSON.Array "" }}
-
{{ .String "" }}
-{{ end }}
-```
-
-Output:
-
-```html
-
Apple
-
Banana
-
Cherry
-
Watermelon
-```
-
-To access an item at a specific index, you could use the following:
-
-```html
-
{{ .JSON.String "0" }}
-```
-
-Output:
-
-```html
-
Apple
-```
-
-
-
-JSON response:
-
-```json
-{
- "user": {
- "address": {
- "city": "New York",
- "state": "NY"
- }
- }
-}
-```
-
-To easily access deeply nested objects, you can use the following dot notation:
-
-```html
-
{{ .JSON.String "user.address.city" }}
-
{{ .JSON.String "user.address.state" }}
-```
-
-Output:
-
-```html
-
New York
-
NY
-```
-
-Using indexes anywhere in the path is also supported:
-
-```json
-{
- "users": [
- {
- "name": "John Doe"
- },
- {
- "name": "Jane Doe"
- }
- ]
-}
-```
-
-```html
-
{{ .JSON.String "users.0.name" }}
-
{{ .JSON.String "users.1.name" }}
-```
-
-Output:
-
-```html
-
John Doe
-
Jane Doe
-```
-
-
-
-JSON response:
-
-```json
-{
- "user": {
- "name": "John Doe",
- "age": 30
- }
-}
-```
-
-To check if a field exists, you can use the following:
-
-```html
-{{ if .JSON.Exists "user.age" }}
-
{{ .JSON.Int "user.age" }}
-{{ else }}
-
Age not provided
-{{ end }}
-```
-
-Output:
-
-```html
-
30
-```
-
-
-
-JSON response:
-
-```json
-{
- "price": 100,
- "discount": 10
-}
-```
-
-Calculations can be performed on either ints or floats. If both numbers are ints, an int will be returned, otherwise a float will be returned. If you try to divide by zero, 0 will be returned. If you provide non-numeric values, `NaN` will be returned.
-
-```html
-
{{ sub (.JSON.Int "price") (.JSON.Int "discount") }}
-```
-
-Output:
-
-```html
-
90
-```
-
-Other operations include `add`, `mul`, and `div`.
-
-
-
-JSON response:
-
-```json
-{
- "posts": [
- {
- "title": "Exploring the Depths of Quantum Computing",
- "date": "2023-10-27T10:00:00Z"
- },
- {
- "title": "A Beginner's Guide to Sustainable Living",
- "date": "2023-11-15T14:30:00+01:00"
- },
- {
- "title": "The Art of Baking Sourdough Bread",
- "date": "2023-12-03T08:45:22-08:00"
- }
- ]
-}
-```
-
-To parse the date and display the relative time (e.g. 2h, 1d, etc), you would use the following:
-
-```
-{{ range .JSON.Array "posts" }}
-
{{ .String "title" }}
-
-{{ end }}
-```
-
-The `parseTime` function takes two arguments: the layout of the date string and the date string itself. The layout can be one of the following: "RFC3339", "RFC3339Nano", "DateTime", "DateOnly", "TimeOnly" or a custom layout in Go's [date format](https://pkg.go.dev/time#pkg-constants).
-
-Output:
-
-```html
-
Exploring the Depths of Quantum Computing
-
-
-
A Beginner's Guide to Sustainable Living
-
-
-
The Art of Baking Sourdough Bread
-
-```
-
-You don't have to worry about the internal implementation, this will then be dynamically populated by Glance on the client side to show the correct relative time.
-
-The important thing to notice here is that the return value of `toRelativeTime` must be used as an attribute in an HTML tag, be it a `div`, `li`, `span`, etc.
-
-
-
-In some instances, you may want to know the status code of the response. This can be done using the following:
-
-```html
-{{ if eq .Response.StatusCode 200 }}
-
Success!
-{{ else }}
-
Failed to fetch data
-{{ end }}
-```
-
-You can also access the response headers:
-
-```html
-
{{ .Response.Header.Get "Content-Type" }}
-```
-
-
-
-JSON response:
-
-```json
-{"name": "Steve", "age": 30}
-{"name": "Alex", "age": 25}
-{"name": "John", "age": 35}
-```
-
-The above format is "[ndjson](https://docs.mulesoft.com/dataweave/latest/dataweave-formats-ndjson)" or "[JSON Lines](https://jsonlines.org/)", where each line is a separate JSON object. To parse this format, you must first disable the JSON validation check in your config, since by default the response is expected to be a single valid JSON object:
-
-```yaml
-- type: custom-api
- skip-json-validation: true
-```
-
-Then, to iterate over each object you can use `.JSONLines`:
-
-```html
-{{ range .JSONLines }}
-
{{ .String "name" }} is {{ .Int "age" }} years old
-{{ end }}
-```
-
-Output:
-
-```html
-
Steve is 30 years old
-
Alex is 25 years old
-
John is 35 years old
-```
-
-For other ways of selecting data from a JSON Lines response, have a look at the docs for [tidwall/gjson](https://github.com/tidwall/gjson/tree/master?tab=readme-ov-file#json-lines). For example, to get an array of all names, you can use the following:
-
-```html
-{{ range .JSON.Array "..#.name" }}
-