add favicon generation, closes #45

This commit is contained in:
checktheroads 2020-06-21 14:11:23 -07:00
parent 49ec2d8a6f
commit 85e764c661
18 changed files with 3298 additions and 1457 deletions

View file

@ -1,235 +0,0 @@
---
id: ui
title: Web UI
sidebar_label: Web UI
keywords: [hyperglass, looking glass, web ui, gui, theme, colors, branding]
description: hyperglass Web UI Configuration
---
import Link from "@docusaurus/Link";
import R from "../src/components/Required";
import MiniNote from "../src/components/MiniNote";
import Code from "../src/components/JSXCode";
import Color from "../src/components/Color";
import Font from "../src/components/Font";
import PageLink from "../src/components/PageLink";
<div class="table--full-width" />
The `web` subsection contains multiple subsections of its own, should you wish to customize various aspects of the UI:
| Section | Description | All Options |
| :-------------- | :----------------------------- | :-----------------------------------------: |
| `credit` | Developer credit & GitHub Link | <PageLink to="#credit">➡️</PageLink> |
| `dns_provider` | DNS over HTTPS Provider | <PageLink to="#dns_provider">➡️</PageLink> |
| `external_link` | Link to external site | <PageLink to="#external_link">➡️</PageLink> |
| `greeting` | Greeting Modal | <PageLink to="#greeting">➡️</PageLink> |
| `logo` | Logo & Favicons | <PageLink to="#logo">➡️</PageLink> |
| `opengraph` | [OpenGraph](https://ogp.me/) | <PageLink to="#opengraph">➡️</PageLink> |
| `terms` | Terms & Conditions | <PageLink to="#terms">➡️</PageLink> |
| `theme` | Colors & Fonts | <PageLink to="#theme">➡️</PageLink> |
## `credit`
| Parameter | Type | Default | Description |
| :-------- | :-----: | :-----: | :--------------------------------------------------------------------------------------- |
| `enable` | Boolean | `true` | Enable or disable the display of developer credit & link to hyperglass GitHub repository |
:::note From the developer
If your organization's policy allows, and you don't mind, I request that you keep `credit` enabled. Remember: my goal for this project is get more networks to use looking glasses to make all of our lives easier. Because it's primarily other network operators who will use this tool to begin with, I'd love for any operators that use your looking glass to know where they can get their own.
:::
## `dns_provider`
| Parameter | Type | Default | Description |
| :-------- | :----: | :------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | String | `'cloudflare'` | DNS over HTTPS provider for in-browser DNS resolution. Cloudflare & Google supported. <MiniNote>Must be <Code>cloudflare</Code> or <Code>google</Code></MiniNote> |
## `external_link`
| Parameter | Type | Default | Description |
| :-------- | :-----: | :---------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enable` | Boolean | `true` | Enable or disable the display of an external link |
| `title` | String | `'PeeringDB'` | Link title/label |
| `url` | String | `'https://www.peeringdb.com/asn/{primary_asn}'` | Target URL. `{primary_asn}` will be replaced with the `primary_asn` value from <Link to="/docs/configuration#global-settings">Global Settings</Link> |
## `greeting`
| Parameter | Type | Default | Description |
| :--------- | :-----: | :----------- | :------------------------------------------------------------------------------------------- |
| `enable` | Boolean | `false` | Enable or disable the greeting modal. |
| `file` | String | | Path to a [markdown](https://www.markdownguide.org/) file containing the modal body content. |
| `title` | String | `'Welcome'` | Modal title. |
| `button` | String | `'Continue'` | Button text. |
| `required` | Boolean | `false` | If `true` the user must click the button in order to submit a query. |
## `logo`
| Parameter | Type | Default | Description |
| :-------- | :-----: | :------------------------------ | :------------------------------------------- |
| `light` | String | `'images/hyperglass-dark.png'` | Path to logo that will be used in light mode |
| `dark` | String | `'images/hyperglass-light.png'` | Path to logo that will be used in dark mode |
| `width` | Integer | `384` | Maximum logo width in pixels |
| `height` | Integer | | Maximum logo height in pixels |
## `opengraph`
If you're not familiar with [OpenGraph](https://ogp.me/), it's the thing that generates the pretty pictures, titles, and descriptions for links when you post them to sites/tools such as Facebook, Twitter, Slack, etc.
By default, no Opengraph image is set. If you define one with `image`, hyperglass will try to determine the image's dimensions automatically. Or, you can override those dimensions with the `width` and `height` parameters.
| Parameter | Type | Description |
| :-------- | :-----: | :---------------------- |
| `image` | String | Path to opengraph image |
| `width` | Integer | Opengraph image width |
| `height` | Integer | Opengraph image height |
## `terms`
| Parameter | Type | Default | Description |
| :-------- | :-----: | :-------- | :-------------------------------------------------------------------------------------------- |
| `enable` | Boolean | `true` | Enable or display the display of terms & conditions |
| `file` | String | | Path to a plain text or markdown file with content to override the default terms & conditions |
| `title` | String | `'Terms'` | Terms & conditions title |
## `text`
| Parameter | Type | Default | Description |
| :--------------- | :----: | :------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cache_prefix` | String | `'Results cached for '` | Text displayed with the cache timeout countdown. |
| `cache_icon` | String | `'Cached Response from {time}'` | Text displayed when a user hovers over the lightning bolt icon, which is displayed when a response from the server was a cached response. `{time}` is replaced with the _original_ query's timestamp. |
| `completed_time` | String | `'Completed in {seconds}'` | Text displayed when a user hovers over the success icon for a query result. `{seconds}` will be replaced with 'n seconds' where n is the time a query took to complete. |
| `fqdn_tooltip` | String | `'Use {protocol}'` | Text displayed when a user hovers over the IPv4 or IPv6 button on an FQDN target resolved by DNS. `{protocol}` is replaced with the relevant IP protocol. |
| `query_location` | String | `'Location'` | Query Location (router) form label. |
| `query_target` | String | `'Target'` | Query Target (IP/hostname/community/AS Path) form label. |
| `query_type` | String | `'Query Type'` | Query Type (BGP Route, Ping, Traceroute, etc.) form label. |
| `query_vrf` | String | `'Routing Table'` | Query VRF form label. |
| `subtitle` | String | `'Network Looking Glass'` | Subtitle text. value. |
| `title` | String | `'hyperglass'` | Title text. |
| `title_mode` | String | `'text_only'` | Set the title mode. <MiniNote>Must be <Code>text_only</Code>, <Code>logo_only</Code>, <Code>logo_subtitle</Code>, or <Code>all</Code></MiniNote> |
:::note Title Mode
The `title_mode` parameter behaves in the following manner:
| Mode | Behavior |
| --------------- | ------------------------------------------------------------------ |
| `text_only` | Shows the `title` and `subtitle` only. |
| `logo_only` | Shows the <Link to="#logo">`logo`</Link> only. |
| `logo_subtitle` | Shows the <Link to="#logo">`logo`</Link> and `subtitle` only. |
| `all` | Shows the <Link to="#logo">`logo`</Link>, `title`, and `subtitle`. |
:::
## `theme`
### Parameters
| Parameter | Type | Description |
| :------------------- | :----: | :----------------------------------------------------------------------------------------------------------------------------------------------- |
| `default_color_mode` | String | Sets the default color mode. Must be `light` or `dark`. If no default mode is specified, hyperglass will use the browser's preferred color mode. |
### Sections
| Section | Description | All Options |
| :------- | :----------- | :----------------------------------: |
| `colors` | Theme colors | <PageLink to="#colors">➡️</PageLink> |
| `fonts` | Theme fonts | <PageLink to="#fonts">➡️</PageLink> |
#### `colors`
| Parameter | Type | Default | Description |
| :---------- | :----: | :--------------------- | :------------------------------------- |
| `primary` | String | | Primary accent color |
| `secondary` | String | | Secondary accent color |
| `success` | String | | Success message/status color |
| `warning` | String | | Warning message/status color |
| `error` | String | | Error message/status color |
| `danger` | String | | Danger message/status color |
| `black` | String | <Color hex="#262626"/> | Used as background color in dark mode |
| `white` | String | <Color hex="#f7f7f7"/> | Used as background color in light mode |
| `red` | String | <Color hex="#d84b4b"/> | Used as `danger` color if undefined |
| `orange` | String | <Color hex="#ff6b35"/> | Used as `error` color if undefined |
| `yellow` | String | <Color hex="#edae49"/> | Used as `warning` color if undefined |
| `green` | String | <Color hex="#35b246"/> | Used as `success` color if undefined |
| `cyan` | String | <Color hex="#118ab2"/> | Used as `primary` color if undefined |
| `blue` | String | <Color hex="#314cb6"/> | Used as `secondary` color if undefined |
| `teal` | String | <Color hex="#35b299"/> | |
| `pink` | String | <Color hex="#f2607d"/> | |
| `purple` | String | <Color hex="#8d30b5"/> | |
| `gray` | String | <Color hex="#c1c7cc"/> | |
#### `fonts`
Currently, only [Google Fonts](https://fonts.google.com/) are supported.
| Parameter | Type | Default | Description |
| :-------- | :----: | :----------------------- | :-------------------------------------- |
| `body` | String | <Font name='Nunito'/> | Main body font |
| `mono` | String | <Font name='Fira Code'/> | Monospace font, used for command output |
## Example
```yaml title="hyperglass.yaml"
web:
credit:
enable: true
dns_provider:
name: google
url: https://dns.google/resolve
external_link:
enable: true
title: PeeringDB
url: https://www.peeringdb.com/asn/{primary_asn}
help_menu:
enable: true
file: null
title: Help
logo:
dark: /images/hyperglass-light.png
favicons: ui/images/favicons/
height: null
light: /images/hyperglass-dark.png
width: 384
opengraph:
height: 1132
image: /images/hyperglass-opengraph.png
width: 7355
terms:
enable: true
file: null
title: Terms
text:
cache: Results will be cached for 2 minutes.
fqdn_tooltip: "Use {protocol}"
query_location: Location
query_target: Target
query_type: Query Type
query_vrf: Routing Table
subtitle: AS65001
title: hyperglass
title_mode: text_only
theme:
default_color_mode: light
colors:
black: "#262626"
blue: "#314cb6"
cyan: "#118ab2"
danger: "#d84b4b"
error: "#ff6b35"
gray: "#c1c7cc"
green: "#35b246"
orange: "#ff6b35"
pink: "#f2607d"
primary: "#118ab2"
purple: "#8d30b5"
red: "#d84b4b"
secondary: "#314cb6"
success: "#35b246"
teal: "#35b299"
warning: "#edae49"
white: "#f7f7f7"
yellow: "#edae49"
fonts:
body: Nunito
mono: Fira Code
```

View file

@ -0,0 +1,83 @@
---
id: configuration
title: UI Configuration
sidebar_label: Configuration
keywords: [hyperglass, looking glass, web ui, gui, theme, colors, branding]
description: Customize the Web UI
---
import Link from "@docusaurus/Link";
import R from "../../src/components/Required";
import MiniNote from "../../src/components/MiniNote";
import Code from "../../src/components/JSXCode";
import PageLink from "../../src/components/PageLink";
<div class="table--full-width" />
The `web` subsection contains multiple subsections of its own, should you wish to customize various aspects of the UI:
| Section | Description | All Options |
| :-------------- | :----------------------------- | :-----------------------------------------: |
| `credit` | Developer credit & GitHub Link | <PageLink to="#credit">➡️</PageLink> |
| `dns_provider` | DNS over HTTPS Provider | <PageLink to="#dns_provider">➡️</PageLink> |
| `external_link` | Link to external site | <PageLink to="#external_link">➡️</PageLink> |
| `greeting` | Greeting Modal | <PageLink to="#greeting">➡️</PageLink> |
| `logo` | Logo & Favicons | <PageLink to="logo">➡️</PageLink> |
| `opengraph` | [OpenGraph](https://ogp.me/) | <PageLink to="#opengraph">➡️</PageLink> |
| `terms` | Terms & Conditions | <PageLink to="#terms">➡️</PageLink> |
| `text` | Text, title, & names | <PageLink to="text">➡️</PageLink> |
| `theme` | Colors & Fonts | <PageLink to="theme">➡️</PageLink> |
## `credit`
| Parameter | Type | Default | Description |
| :-------- | :-----: | :-----: | :--------------------------------------------------------------------------------------- |
| `enable` | Boolean | `true` | Enable or disable the display of developer credit & link to hyperglass GitHub repository |
:::note From the developer
If your organization's policy allows, and you don't mind, I request that you keep `credit` enabled. Remember: my goal for this project is get more networks to use looking glasses to make all of our lives easier. Because it's primarily other network operators who will use this tool to begin with, I'd love for any operators that use your looking glass to know where they can get their own.
:::
## `dns_provider`
| Parameter | Type | Default | Description |
| :-------- | :----: | :------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | String | `'cloudflare'` | DNS over HTTPS provider for in-browser DNS resolution. Cloudflare & Google supported. <MiniNote>Must be <Code>cloudflare</Code> or <Code>google</Code></MiniNote> |
## `external_link`
| Parameter | Type | Default | Description |
| :-------- | :-----: | :---------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enable` | Boolean | `true` | Enable or disable the display of an external link |
| `title` | String | `'PeeringDB'` | Link title/label |
| `url` | String | `'https://www.peeringdb.com/asn/{primary_asn}'` | Target URL. `{primary_asn}` will be replaced with the `primary_asn` value from <Link to="/docs/configuration#global-settings">Global Settings</Link> |
## `greeting`
| Parameter | Type | Default | Description |
| :--------- | :-----: | :----------- | :------------------------------------------------------------------------------------------- |
| `enable` | Boolean | `false` | Enable or disable the greeting modal. |
| `file` | String | | Path to a [markdown](https://www.markdownguide.org/) file containing the modal body content. |
| `title` | String | `'Welcome'` | Modal title. |
| `button` | String | `'Continue'` | Button text. |
| `required` | Boolean | `false` | If `true` the user must click the button in order to submit a query. |
## `opengraph`
If you're not familiar with [OpenGraph](https://ogp.me/), it's the thing that generates the pretty pictures, titles, and descriptions for links when you post them to sites/tools such as Facebook, Twitter, Slack, etc.
By default, no Opengraph image is set. If you define one with `image`, hyperglass will try to determine the image's dimensions automatically. Or, you can override those dimensions with the `width` and `height` parameters.
| Parameter | Type | Description |
| :-------- | :-----: | :---------------------- |
| `image` | String | Path to opengraph image |
| `width` | Integer | Opengraph image width |
| `height` | Integer | Opengraph image height |
## `terms`
| Parameter | Type | Default | Description |
| :-------- | :-----: | :-------- | :-------------------------------------------------------------------------------------------- |
| `enable` | Boolean | `true` | Enable or display the display of terms & conditions |
| `file` | String | | Path to a plain text or markdown file with content to override the default terms & conditions |
| `title` | String | `'Terms'` | Terms & conditions title |

74
docs/docs/ui/example.mdx Normal file
View file

@ -0,0 +1,74 @@
---
id: example
title: Example UI Configuration
sidebar_label: Example
keywords:
[hyperglass, looking glass, web ui, gui, theme, colors, branding, example]
description: See how to the hyperglass UI should be configured.
---
## Example
```yaml title="hyperglass.yaml"
web:
credit:
enable: true
dns_provider:
name: cloudflare
external_link:
enable: true
title: PeeringDB
url: https://www.peeringdb.com/asn/{primary_asn}
help_menu:
enable: true
file: null
title: Help
logo:
dark: /home/ubuntu/hyperglass/hyperglass-light.png
light: /home/ubuntu/hyperglass/hyperglass-dark.png
favicon: /home/ubuntu/hyperglass/icon.png
height: null
width: 384
opengraph:
height: 1132
image: /images/hyperglass-opengraph.png
width: 7355
terms:
enable: true
file: null
title: Terms
text:
cache: Results will be cached for 2 minutes.
fqdn_tooltip: "Use {protocol}"
query_location: Location
query_target: Target
query_type: Query Type
query_vrf: Routing Table
subtitle: AS65001
title: hyperglass
title_mode: text_only
theme:
default_color_mode: light
colors:
black: "#262626"
blue: "#314cb6"
cyan: "#118ab2"
danger: "#d84b4b"
error: "#ff6b35"
gray: "#c1c7cc"
green: "#35b246"
orange: "#ff6b35"
pink: "#f2607d"
primary: "#118ab2"
purple: "#8d30b5"
red: "#d84b4b"
secondary: "#314cb6"
success: "#35b246"
teal: "#35b299"
warning: "#edae49"
white: "#f7f7f7"
yellow: "#edae49"
fonts:
body: Nunito
mono: Fira Code
```

99
docs/docs/ui/logo.mdx Normal file
View file

@ -0,0 +1,99 @@
---
id: logo
title: Logo
sidebar_label: Logo
keywords: [hyperglass, looking glass, web ui, gui, branding, logo]
description: Customize the Logo & Favicon
---
## `logo`
| Parameter | Type | Default | Description |
| :-------- | :-----: | :-------------- | :-------------------------------------------- |
| `light` | String | hyperglass logo | Path to logo that will be used in light mode |
| `dark` | String | hyperglass logo | Path to logo that will be used in dark mode |
| `favicon` | String | hyperglass icon | Path to logo that will be used as the favicon |
| `width` | Integer | `384` | Maximum logo width in pixels |
| `height` | Integer | | Maximum logo height in pixels |
### Favicon
It's very easy to customize the favicon imaged used by hyperglass. If you're not familiar with the term, the favicon is the icon used by the browser in tabs, windows, or bookmarks:
![](screenshot-favicons.jpg)
During the [UI build process](setup.mdx#ui-build) hyperglass automatically generates favicon files in all of the many formats required for cross-platform, cross-browser support.
#### Supported Formats
- `.jpg`
- `.jpeg`
- `.png`
- `.svg`
:::caution Icon File Size
Generating the favicons is very CPU-intensive, and therefore has the tendency of timing out if the icon file is very large. If you receive a timeout error when starting hyperglass or running the `hyperglass build-ui` command, try reducing the size of the icon file. **File sizes of around 200 MB** have been known to succeed without too much overhead.
:::
The following icons types are generated:
```
android-chrome-36x36.png
android-chrome-48x48.png
android-chrome-72x72.png
android-chrome-96x96.png
android-chrome-144x144.png
android-chrome-192x192.png
android-chrome-256x256.png
android-chrome-384x384.png
android-chrome-512x512.png
apple-touch-icon-57x57.png
apple-touch-icon-60x60.png
apple-touch-icon-72x72.png
apple-touch-icon-76x76.png
apple-touch-icon-114x114.png
apple-touch-icon-120x120.png
apple-touch-icon-144x144.png
apple-touch-icon-152x152.png
apple-touch-icon-167x167.png
apple-touch-icon-180x180.png
apple-touch-icon-1024x1024.png
apple-touch-icon-precomposed.png
apple-touch-icon.png
apple-touch-startup-image-640x1136.png
apple-touch-startup-image-750x1334.png
apple-touch-startup-image-828x1792.png
apple-touch-startup-image-1125x2436.png
apple-touch-startup-image-1136x640.png
apple-touch-startup-image-1242x2208.png
apple-touch-startup-image-1242x2688.png
apple-touch-startup-image-1334x750.png
apple-touch-startup-image-1536x2048.png
apple-touch-startup-image-1620x2160.png
apple-touch-startup-image-1668x2224.png
apple-touch-startup-image-1668x2388.png
apple-touch-startup-image-1792x828.png
apple-touch-startup-image-2048x1536.png
apple-touch-startup-image-2048x2732.png
apple-touch-startup-image-2160x1620.png
apple-touch-startup-image-2208x1242.png
apple-touch-startup-image-2224x1668.png
apple-touch-startup-image-2388x1668.png
apple-touch-startup-image-2436x1125.png
apple-touch-startup-image-2688x1242.png
apple-touch-startup-image-2732x2048.png
coast-228x228.png
favicon-16x16.png
favicon-32x32.png
favicon-48x48.png
favicon.ico
firefox_app_60x60.png
firefox_app_128x128.png
firefox_app_512x512.png
mstile-70x70.png
mstile-144x144.png
mstile-150x150.png
mstile-310x150.png
mstile-310x310.png
yandex-browser-50x50.png
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

36
docs/docs/ui/text.mdx Normal file
View file

@ -0,0 +1,36 @@
---
id: text
title: Text
sidebar_label: Text
keywords: [hyperglass, looking glass, web ui, gui, branding, text, messages]
description: Customize the text used in the web UI
---
## `text`
| Parameter | Type | Default | Description |
| :--------------- | :----: | :------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cache_prefix` | String | `'Results cached for '` | Text displayed with the cache timeout countdown. |
| `cache_icon` | String | `'Cached Response from {time}'` | Text displayed when a user hovers over the lightning bolt icon, which is displayed when a response from the server was a cached response. `{time}` is replaced with the _original_ query's timestamp. |
| `completed_time` | String | `'Completed in {seconds}'` | Text displayed when a user hovers over the success icon for a query result. `{seconds}` will be replaced with 'n seconds' where n is the time a query took to complete. |
| `fqdn_tooltip` | String | `'Use {protocol}'` | Text displayed when a user hovers over the IPv4 or IPv6 button on an FQDN target resolved by DNS. `{protocol}` is replaced with the relevant IP protocol. |
| `query_location` | String | `'Location'` | Query Location (router) form label. |
| `query_target` | String | `'Target'` | Query Target (IP/hostname/community/AS Path) form label. |
| `query_type` | String | `'Query Type'` | Query Type (BGP Route, Ping, Traceroute, etc.) form label. |
| `query_vrf` | String | `'Routing Table'` | Query VRF form label. |
| `subtitle` | String | `'Network Looking Glass'` | Subtitle text. value. |
| `title` | String | `'hyperglass'` | Title text. |
| `title_mode` | String | `'text_only'` | Set the title mode. <MiniNote>Must be <Code>text_only</Code>, <Code>logo_only</Code>, <Code>logo_subtitle</Code>, or <Code>all</Code></MiniNote> |
### Title Mode
The `title_mode` parameter behaves in the following manner:
<div className="table--full-width" />
| Mode | Behavior |
| --------------- | ------------------------------------------------------------------- |
| `text_only` | Shows the [`title`](#text) and [`subtitle`](#text) only. |
| `logo_only` | Shows the [`logo`](ui/logo) only. |
| `logo_subtitle` | Shows the [`logo`](ui/logo) and [`subtitle`](#text) only. |
| `all` | Shows the [`logo`](ui/logo), [`title`](#text), [`subtitle`](#text). |

58
docs/docs/ui/theme.mdx Normal file
View file

@ -0,0 +1,58 @@
---
id: theme
title: Theme
sidebar_label: Theme
keywords: [hyperglass, looking glass, web ui, gui, branding, theme]
description: Customize Theme
---
import Color from "../../src/components/Color";
import Font from "../../src/components/Font";
import PageLink from "../../src/components/PageLink";
## `theme`
### Parameters
| Parameter | Type | Description |
| :------------------- | :----: | :----------------------------------------------------------------------------------------------------------------------------------------------- |
| `default_color_mode` | String | Sets the default color mode. Must be `light` or `dark`. If no default mode is specified, hyperglass will use the browser's preferred color mode. |
### Subsections
| Section | Description | All Options |
| :------- | :----------- | :----------------------------------: |
| `colors` | Theme colors | <PageLink to="#colors">➡️</PageLink> |
| `fonts` | Theme fonts | <PageLink to="#fonts">➡️</PageLink> |
#### `colors`
| Parameter | Type | Default | Description |
| :---------- | :----: | :--------------------- | :------------------------------------- |
| `primary` | String | | Primary accent color |
| `secondary` | String | | Secondary accent color |
| `success` | String | | Success message/status color |
| `warning` | String | | Warning message/status color |
| `error` | String | | Error message/status color |
| `danger` | String | | Danger message/status color |
| `black` | String | <Color hex="#262626"/> | Used as background color in dark mode |
| `white` | String | <Color hex="#f7f7f7"/> | Used as background color in light mode |
| `red` | String | <Color hex="#d84b4b"/> | Used as `danger` color if undefined |
| `orange` | String | <Color hex="#ff6b35"/> | Used as `error` color if undefined |
| `yellow` | String | <Color hex="#edae49"/> | Used as `warning` color if undefined |
| `green` | String | <Color hex="#35b246"/> | Used as `success` color if undefined |
| `cyan` | String | <Color hex="#118ab2"/> | Used as `primary` color if undefined |
| `blue` | String | <Color hex="#314cb6"/> | Used as `secondary` color if undefined |
| `teal` | String | <Color hex="#35b299"/> | |
| `pink` | String | <Color hex="#f2607d"/> | |
| `purple` | String | <Color hex="#8d30b5"/> | |
| `gray` | String | <Color hex="#c1c7cc"/> | |
#### `fonts`
Currently, only [Google Fonts](https://fonts.google.com/) are supported.
| Parameter | Type | Default | Description |
| :-------- | :----: | :----------------------- | :-------------------------------------- |
| `body` | String | <Font name="Nunito"/> | Main body font |
| `mono` | String | <Font name="Fira Code"/> | Monospace font, used for command output |

View file

@ -188,11 +188,15 @@ def setup(unattended):
install_path = user_path
ui_dir = install_path / "static" / "ui"
images_dir = install_path / "static" / "images"
favicon_dir = images_dir / "favicons"
custom_dir = install_path / "static" / "custom"
create_dir(install_path)
create_dir(ui_dir, parents=True)
create_dir(custom_dir, parents=True)
for path in (ui_dir, images_dir, custom_dir, favicon_dir):
create_dir(path, parents=True)
migrate_static_assets(install_path)
example_dir = WORKING_DIR.parent / "examples"

View file

@ -7,13 +7,13 @@ from pathlib import Path
# Third Party
import PIL.Image as PilImage
from pydantic import StrictInt, StrictStr, root_validator
from pydantic import FilePath, StrictInt, root_validator
# Project
from hyperglass.models import HyperglassModel
from hyperglass.configuration.models._utils import validate_image
CONFIG_PATH = Path(os.environ["hyperglass_directory"])
DEFAULT_IMAGES = Path(__file__).parent.parent.parent / "images"
class OpenGraph(HyperglassModel):
@ -21,7 +21,7 @@ class OpenGraph(HyperglassModel):
width: Optional[StrictInt]
height: Optional[StrictInt]
image: Optional[StrictStr]
image: FilePath = DEFAULT_IMAGES / "hyperglass-opengraph.png"
@root_validator
def validate_opengraph(cls, values):
@ -36,21 +36,15 @@ class OpenGraph(HyperglassModel):
supported_extensions = (".jpg", ".jpeg", ".png")
if (
values["image"] is not None
and Path(values["image"]).suffix not in supported_extensions
and values["image"].suffix not in supported_extensions
):
raise ValueError(
"OpenGraph image must be one of {e}".format(
e=", ".join(supported_extensions)
)
)
if values["image"] is None:
values["image"] = "images/hyperglass-opengraph.png"
values["image"] = validate_image(values["image"])
image_file = CONFIG_PATH / "static" / values["image"]
with PilImage.open(image_file) as img:
with PilImage.open(values["image"]) as img:
width, height = img.size
if values["width"] is None:
values["width"] = width
@ -78,4 +72,3 @@ class OpenGraph(HyperglassModel):
"description": "Valid path to a JPG or PNG file to use as the OpenGraph image.",
},
}
schema_extra = {"level": 3}

View file

@ -2,6 +2,7 @@
# Standard Library
from typing import Union, Optional
from pathlib import Path
# Third Party
from pydantic import (
@ -19,9 +20,10 @@ from pydantic.color import Color
# Project
from hyperglass.models import HyperglassModel
from hyperglass.constants import DNS_OVER_HTTPS, FUNC_COLOR_MAP
from hyperglass.configuration.models._utils import validate_image
from hyperglass.configuration.models.opengraph import OpenGraph
DEFAULT_IMAGES = Path(__file__).parent.parent.parent / "images"
class Analytics(HyperglassModel):
"""Validation model for Google Analytics."""
@ -90,31 +92,11 @@ class Greeting(HyperglassModel):
class Logo(HyperglassModel):
"""Validation model for logo configuration."""
light: StrictStr = "images/hyperglass-light.png"
dark: StrictStr = "images/hyperglass-dark.png"
light: FilePath = DEFAULT_IMAGES / "hyperglass-light.png"
dark: FilePath = DEFAULT_IMAGES / "hyperglass-dark.png"
favicon: FilePath = DEFAULT_IMAGES / "icon.svg"
width: Optional[Union[StrictInt, constr(regex=r"^([1-9][0-9]?|100)\%$")]] = "80%"
height: Optional[Union[StrictInt, constr(regex=r"^([1-9][0-9]?|100)\%$")]]
favicons: StrictStr = "ui/images/favicons/"
@validator("favicons")
def favicons_trailing_slash(cls, value):
"""If the favicons path does not end in a '/', append it."""
chars = list(value)
if chars[len(chars) - 1] != "/":
chars.append("/")
return "".join(chars)
@validator("light", "dark")
def validate_logos(cls, value):
"""Convert file path to URL path.
Arguments:
value {FilePath} -- Path to logo file.
Returns:
{str} -- Formatted logo path
"""
return validate_image(value)
class Terms(HyperglassModel):

View file

@ -1,12 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1014 1014" style="enable-background:new 0 0 1014 1014;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FF5E5B;}
</style>
<g transform="translate(0.000000,1014.000000) scale(0.100000,-0.100000)">
<path class="st0" d="M4809,10126c-2-2-51-7-109-10c-92-6-211-18-305-30c-16-3-52-8-80-11c-27-4-138-24-245-46
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1014 1014" style="enable-background:new 0 0 1014 1014;" xml:space="preserve">
<g transform="translate(0.000000,1014.000000) scale(0.100000,-0.100000)">
<path fill="#ff5e5b" d="M4809,10126c-2-2-51-7-109-10c-92-6-211-18-305-30c-16-3-52-8-80-11c-27-4-138-24-245-46
c-516-102-1052-302-1491-556c-48-27-93-53-100-56c-30-14-217-138-333-220c-432-307-811-676-1130-1102c-213-283-391-582-540-905
c-145-311-255-631-331-956c-19-82-37-167-41-189c-3-22-7-42-9-45s-6-24-9-46c-4-22-8-51-11-64c-3-14-14-92-24-175
c-18-134-24-193-37-380c-5-75-5-429,1-520c11-199,29-383,45-470c5-27,11-69,14-92c16-128,97-477,156-668c133-435,341-881,591-1267
@ -28,13 +22,13 @@
c-81,11-389,93-529,141c-413,142-798,346-1145,609c-327,248-663,597-888,926c-376,548-621,1187-692,1805c-3,28-8,64-10,80
c-25,188-25,664,0,840c3,17,7,53,10,80c29,264,110,602,211,880c292,808,844,1513,1560,1993c194,130,481,286,654,356
c36,15,74,31,85,36c110,52,496,172,662,205c133,27,269,49,374,61c30,3,65,8,79,10s86,7,160,10c74,4,136,8,138,9
C4972,9128,5212,9122,5336,9116z"/>
<path class="st0" d="M3445,8398c-84-32-397-246-566-388c-223-187-442-415-652-680c-123-155-312-465-420-690
C4972,9128,5212,9122,5336,9116z" />
<path fill="#ff5e5b" d="M3445,8398c-84-32-397-246-566-388c-223-187-442-415-652-680c-123-155-312-465-420-690
c-74-154-190-440-202-500c-1-3-15-50-32-105c-30-96-77-280-87-337c-3-15-11-63-20-105c-15-79-20-108-31-198c-4-27-8-60-10-73
c-13-79-20-239-20-457c0-280,5-309,70-377c55-60,102-79,191-79c88-1,173,52,217,135c20,38,22,56,23,261c2,262,11,413,34,555
c5,30,12,73,15,94s7,48,10,60s7,33,10,49c12,64,17,88,46,197c124,482,347,931,658,1325c151,191,360,403,534,543c40,31,74,59,77,63
c12,13,222,159,300,208c103,65,136,94,162,145c60,117,16,265-97,332C3602,8407,3497,8418,3445,8398z"/>
<path class="st0" d="M1691,4003c-91-33-161-138-161-241c0-74,135-389,275-641c107-195,164-243,285-244c138-1,246,98,254,232
c4,63-12,111-73,216c-68,117-166,320-226,467c-50,124-86,172-153,204C1842,4020,1745,4023,1691,4003z"/>
</g>
c12,13,222,159,300,208c103,65,136,94,162,145c60,117,16,265-97,332C3602,8407,3497,8418,3445,8398z" />
<path fill="#ff5e5b" d="M1691,4003c-91-33-161-138-161-241c0-74,135-389,275-641c107-195,164-243,285-244c138-1,246,98,254,232
c4,63-12,111-73,216c-68,117-166,320-226,467c-50,124-86,172-153,204C1842,4020,1745,4023,1691,4003z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -21,8 +21,6 @@ export const HyperglassProvider = ({ config, children }) => {
const value = useMemo(() => config, [config]);
const userTheme = value && makeTheme(value.web.theme);
const theme = value ? userTheme : defaultTheme;
// console.log(value);
// console.log(theme);
return (
<HyperglassContext.Provider value={value}>
<ThemeProvider theme={theme}>

View file

@ -0,0 +1,72 @@
const fs = require("fs");
const favicons = require("favicons");
const tempy = require("tempy");
const defaultConfig = {
path: "/images/favicons",
appleStatusBarStyle: "black-translucent",
display: "standalone",
orientation: "any",
scope: "/",
icons: {
android: true,
appleIcon: true,
appleStartup: true,
coast: true,
favicons: true,
firefox: true,
windows: true,
yandex: true
}
};
const handleError = err => {
if (err) {
if (err.message) {
console.error(err.message);
return;
}
console.error(err);
return;
}
return;
};
const writeHtml = (path, data) => {
fs.writeFile(path, data, handleError);
return;
};
const writeFiles = (basePath, files) => {
files.forEach(attrs => {
fs.writeFile(`${basePath}/${attrs.name}`, attrs.contents, handleError);
});
return;
};
const generateFavicons = (config, appPath) => {
const htmlFile = tempy.file({ extension: "json" });
const callback = (err, response) => {
handleError(err);
writeFiles(`${appPath}/static/images/favicons`, response.images);
writeFiles(`${appPath}/static/ui`, response.files);
writeHtml(htmlFile, JSON.stringify(response.html));
return;
};
favicons(
config.web.logo.favicon,
{
appName: config.site_title,
appDescription: config.site_description,
lang: config.language || "en-US",
background: config.web.theme.colors.white,
theme_color: config.web.theme.colors.primary,
...defaultConfig
},
callback
);
return htmlFile;
};
module.exports = generateFavicons;

View file

@ -2,6 +2,12 @@ const aliases = require("./.alias");
const envVars = require("/tmp/hyperglass.env.json");
const { configFile } = envVars;
const config = require(String(configFile));
const generateFavicons = require("./generateFavicons");
const faviconHtmlFile = generateFavicons(
config._HYPERGLASS_CONFIG_,
config._HYPERGLASS_APP_PATH_
);
module.exports = {
webpack(config) {
@ -16,6 +22,7 @@ module.exports = {
env: {
_NODE_ENV_: config.NODE_ENV,
_HYPERGLASS_URL_: config._HYPERGLASS_URL_,
_HYPERGLASS_CONFIG_: config._HYPERGLASS_CONFIG_
_HYPERGLASS_CONFIG_: config._HYPERGLASS_CONFIG_,
_FAVICON_HTML_FILE_: faviconHtmlFile
}
};

View file

@ -24,7 +24,9 @@
"chroma-js": "^2.1.0",
"dayjs": "^1.8.25",
"emotion-theming": "^10.0.27",
"favicons": "^6.1.0",
"framer-motion": "^1.10.0",
"html-to-react": "^1.4.3",
"lodash": "^4.17.15",
"next": "^9.3.1",
"react": "^16.13.1",
@ -39,6 +41,7 @@
"react-textfit": "^1.1.0",
"string-format": "^2.0.0",
"styled-system": "^5.1.5",
"tempy": "^0.5.0",
"use-media": "^1.4.0",
"yup": "^0.28.3"
},

View file

@ -1,16 +1,41 @@
import * as React from "react";
import { createElement } from "react";
import Head from "next/head";
import dynamic from "next/dynamic";
import fs from "fs";
import { Parser } from "html-to-react";
import Meta from "~/components/Meta";
import Loading from "~/components/Loading";
const LookingGlass = dynamic(() => import("~/components/LookingGlass"), {
loading: Loading
});
const Index = () => (
<>
<Meta />
<LookingGlass />
</>
);
const Index = ({ faviconComponents }) => {
return (
<>
<Head>
{faviconComponents.map((comp, i) =>
createElement(comp.type, { key: i, ...comp.props })
)}
</Head>
<Meta />
<LookingGlass />
</>
);
};
export async function getStaticProps(context) {
const htmlToReact = new Parser();
const lines = fs.readFileSync(process.env._FAVICON_HTML_FILE_, "utf-8");
const components = JSON.parse(lines).map(elem => {
const comp = htmlToReact.parse(elem);
return { type: comp.type, props: comp.props };
});
return {
props: {
faviconComponents: components
}
};
}
export default Index;

3844
hyperglass/ui/yarn.lock vendored

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,12 @@
"""Utility functions."""
# Standard Library
import shutil
from queue import Queue
from typing import Iterable
from pathlib import Path
from threading import Thread
# Project
from hyperglass.log import log
@ -37,7 +44,7 @@ def clean_name(_name):
return _scrubbed.lower()
def check_path(path, mode="r"):
def check_path(path, mode="r", create=False):
"""Verify if a path exists and is accessible.
Arguments:
@ -50,14 +57,19 @@ def check_path(path, mode="r"):
Returns:
{Path|None} -- Path object if checks pass, None if not.
"""
from pathlib import Path
try:
if not isinstance(path, Path):
path = Path(path)
if not path.exists():
raise FileNotFoundError(f"{str(path)} does not exist.")
if create:
if path.is_file():
path.parent.mkdir(parents=True)
else:
path.mkdir(parents=True)
else:
raise FileNotFoundError(f"{str(path)} does not exist.")
with path.open(mode):
result = path
@ -95,7 +107,8 @@ async def build_ui(app_path):
RuntimeError: Raised when any other error occurs.
"""
import asyncio
from pathlib import Path
timeout = 60
ui_dir = Path(__file__).parent / "ui"
build_dir = app_path / "static" / "ui"
@ -113,7 +126,7 @@ async def build_ui(app_path):
cwd=ui_dir,
)
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=60)
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=timeout)
messages = stdout.decode("utf-8").strip()
errors = stderr.decode("utf-8").strip()
@ -123,6 +136,9 @@ async def build_ui(app_path):
await proc.wait()
all_messages.append(messages)
except asyncio.TimeoutError:
raise RuntimeError(f"{timeout} second timeout exceeded while building UI")
except Exception as e:
raise RuntimeError(str(e))
@ -140,7 +156,6 @@ async def write_env(variables):
"""
from aiofile import AIOFile
import json
from pathlib import Path
env_file = Path("/tmp/hyperglass.env.json") # noqa: S108
env_vars = json.dumps(variables)
@ -213,8 +228,7 @@ async def move_files(src, dst, files): # noqa: C901
dst {Path} -- Target destination directory
files {Iterable} -- Iterable of files
"""
import shutil
from pathlib import Path
from typing import Iterable
def error(*args, **kwargs):
@ -267,8 +281,7 @@ async def move_files(src, dst, files): # noqa: C901
def migrate_static_assets(app_path):
"""Synchronize the project assets with the installation assets."""
import shutil
from pathlib import Path
from filecmp import dircmp
asset_dir = Path(__file__).parent / "images"
@ -309,7 +322,6 @@ async def check_node_modules():
Returns:
{bool} -- True if exists and has contents.
"""
from pathlib import Path
ui_path = Path(__file__).parent / "ui"
node_modules = ui_path / "node_modules"
@ -334,7 +346,6 @@ async def node_initial(dev_mode=False):
{str} -- Command output
"""
import asyncio
from pathlib import Path
ui_path = Path(__file__).parent / "ui"
@ -378,7 +389,7 @@ async def read_package_json():
Returns:
{dict} -- NPM package.json as dict
"""
from pathlib import Path
import json
package_json_file = Path(__file__).parent / "ui" / "package.json"
@ -396,6 +407,85 @@ async def read_package_json():
return package_json
class FileCopy(Thread):
"""Custom thread for copyfiles() function."""
def __init__(self, src: Path, dst: Path, queue: Queue):
"""Initialize custom thread."""
super().__init__()
if not src.exists():
raise ValueError("{} does not exist", str(src))
self.src = src
self.dst = dst
self.queue = queue
def run(self):
"""Put one object into the queue for each file."""
try:
try:
shutil.copy(self.src, self.dst)
except IOError as err:
self.queue.put(err)
else:
self.queue.put(self.src)
finally:
pass
def copyfiles(src_files: Iterable[Path], dst_files: Iterable[Path]):
"""Copy iterable of files from source to destination with threading."""
queue = Queue()
threads = ()
src_files_len = len(src_files)
dst_files_len = len(dst_files)
if src_files_len != dst_files_len:
raise ValueError(
"The number of source files "
+ "({}) must match the number of destination files ({}).".format(
src_files_len, dst_files_len
)
)
for i, file in enumerate(src_files):
file_thread = FileCopy(src=file, dst=dst_files[i], queue=queue)
threads += (file_thread,)
for thread in threads:
thread.start()
for _file in src_files:
copied = queue.get()
log.success("Copied {}", str(copied))
for thread in threads:
thread.join()
for i, file in enumerate(dst_files):
if not file.exists():
raise RuntimeError("{} was not copied to {}", str(src_files[i]), str(file))
return True
async def migrate_images(app_path, params):
"""Migrate images from source code to install directory."""
images_dir = app_path / "static" / "images"
favicon_dir = images_dir / "favicons"
check_path(favicon_dir, create=True)
src_files = ()
dst_files = ()
for image in ("light", "dark", "favicon"):
src = Path(params["web"]["logo"][image])
dst = images_dir / f"{image + src.suffix}"
src_files += (src,)
dst_files += (dst,)
return copyfiles(src_files, dst_files)
async def build_frontend( # noqa: C901
dev_mode, dev_url, prod_url, params, app_path, force=False
):
@ -426,7 +516,7 @@ async def build_frontend( # noqa: C901
"""
import hashlib
import tempfile
from pathlib import Path
from aiofile import AIOFile
import json
from hyperglass.constants import __version__
@ -439,6 +529,7 @@ async def build_frontend( # noqa: C901
"_HYPERGLASS_CONFIG_": params,
"_HYPERGLASS_VERSION_": __version__,
"_HYPERGLASS_PACKAGE_JSON_": package_json,
"_HYPERGLASS_APP_PATH_": str(app_path),
}
# Set NextJS production/development mode and base URL based on
@ -517,7 +608,7 @@ async def build_frontend( # noqa: C901
elif dev_mode and not force:
log.debug("Running in developer mode, did not build new UI files")
migrate_static_assets(app_path)
await migrate_images(app_path, params)
except Exception as e:
raise RuntimeError(str(e)) from None
@ -528,7 +619,7 @@ async def build_frontend( # noqa: C901
def set_app_path(required=False):
"""Find app directory and set value to environment variable."""
import os
from pathlib import Path
from getpass import getuser
matched_path = None
@ -581,7 +672,6 @@ def import_public_key(app_path, device_name, keystring):
{bool} -- True if file was written
"""
import re
from pathlib import Path
if not isinstance(app_path, Path):
app_path = Path(app_path)