Jelajahi Sumber

Merge branch 'main' into dev

Svilen Markov 3 bulan lalu
induk
melakukan
2f50f5ef34

+ 2 - 2
docs/configuration.md

@@ -356,7 +356,7 @@ pages:
 ### Properties
 ### Properties
 | Name | Type | Required | Default |
 | Name | Type | Required | Default |
 | ---- | ---- | -------- | ------- |
 | ---- | ---- | -------- | ------- |
-| title | string | yes | |
+| name | string | yes | |
 | slug | string | no | |
 | slug | string | no | |
 | width | string | no | |
 | width | string | no | |
 | center-vertically | boolean | no | false |
 | center-vertically | boolean | no | false |
@@ -374,7 +374,7 @@ The URL friendly version of the title which is used to access the page. For exam
 #### `width`
 #### `width`
 The maximum width of the page on desktop. Possible values are `slim` and `wide`.
 The maximum width of the page on desktop. Possible values are `slim` and `wide`.
 
 
-* default: `1600px`
+* default: `1600px` (when no value is specified)
 * slim: `1100px`
 * slim: `1100px`
 * wide: `1920px`
 * wide: `1920px`
 
 

TEMPAT SAMPAH
docs/images/themes/gruvbox.png


+ 10 - 0
docs/themes.md

@@ -53,6 +53,16 @@ theme:
   primary-color: 97 13 80
   primary-color: 97 13 80
 ```
 ```
 
 
+### Gruvbox Dark
+![screenshot](images/themes/gruvbox.png)
+```yaml
+theme:
+  background-color: 0 0 16
+  primary-color: 43 59 81
+  positive-color: 61 66 44
+  negative-color: 6 96 59
+```
+
 ### Kanagawa Dark
 ### Kanagawa Dark
 ![screenshot](images/themes/kanagawa-dark.png)
 ![screenshot](images/themes/kanagawa-dark.png)
 ```yaml
 ```yaml

+ 1 - 1
internal/glance/glance.go

@@ -68,7 +68,7 @@ func newApplication(config *config) (*application, error) {
 
 
 			for w := range column.Widgets {
 			for w := range column.Widgets {
 				widget := column.Widgets[w]
 				widget := column.Widgets[w]
-				app.widgetByID[widget.id()] = widget
+				app.widgetByID[widget.GetID()] = widget
 
 
 				widget.setProviders(providers)
 				widget.setProviders(providers)
 			}
 			}

+ 5 - 0
internal/glance/static/js/main.js

@@ -284,7 +284,9 @@ function setupGroups() {
 
 
                 for (let i = 0; i < titles.length; i++) {
                 for (let i = 0; i < titles.length; i++) {
                     titles[i].classList.remove("widget-group-title-current");
                     titles[i].classList.remove("widget-group-title-current");
+                    titles[i].setAttribute("aria-selected", "false");
                     tabs[i].classList.remove("widget-group-content-current");
                     tabs[i].classList.remove("widget-group-content-current");
+                    tabs[i].setAttribute("aria-hidden", "true");
                 }
                 }
 
 
                 if (current < t) {
                 if (current < t) {
@@ -296,7 +298,9 @@ function setupGroups() {
                 current = t;
                 current = t;
 
 
                 title.classList.add("widget-group-title-current");
                 title.classList.add("widget-group-title-current");
+                title.setAttribute("aria-selected", "true");
                 tabs[t].classList.add("widget-group-content-current");
                 tabs[t].classList.add("widget-group-content-current");
+                tabs[t].setAttribute("aria-hidden", "false");
             });
             });
         }
         }
     }
     }
@@ -670,6 +674,7 @@ async function setupPage() {
         setupLazyImages();
         setupLazyImages();
     } finally {
     } finally {
         pageElement.classList.add("content-ready");
         pageElement.classList.add("content-ready");
+        pageElement.setAttribute("aria-busy", "false");
 
 
         for (let i = 0; i < contentReadyCallbacks.length; i++) {
         for (let i = 0; i < contentReadyCallbacks.length; i++) {
             contentReadyCallbacks[i]();
             contentReadyCallbacks[i]();

+ 17 - 4
internal/glance/static/main.css

@@ -110,7 +110,7 @@
 .visited-indicator:not(.text-truncate)::after,
 .visited-indicator:not(.text-truncate)::after,
 .visited-indicator.text-truncate::before,
 .visited-indicator.text-truncate::before,
 .bookmarks-link:not(.bookmarks-link-no-arrow)::after {
 .bookmarks-link:not(.bookmarks-link-no-arrow)::after {
-    content: '↗';
+    content: '↗' / "";
     margin-left: 0.5em;
     margin-left: 0.5em;
     display: inline-block;
     display: inline-block;
     position: relative;
     position: relative;
@@ -189,7 +189,7 @@
 }
 }
 
 
 .expand-toggle-button-icon::before {
 .expand-toggle-button-icon::before {
-    content: '';
+    content: '' / "";
     font-size: 0.8rem;
     font-size: 0.8rem;
     transform: rotate(90deg);
     transform: rotate(90deg);
     line-height: 1;
     line-height: 1;
@@ -341,6 +341,19 @@ html, body, .body-content {
     height: 100%;
     height: 100%;
 }
 }
 
 
+h1, h2, h3, h4, h5 {
+    font: inherit;
+}
+
+.visually-hidden {
+    clip-path: inset(50%);
+    height: 1px;
+    overflow: hidden;
+    position: absolute;
+    white-space: nowrap;
+    width: 1px;
+}
+
 a {
 a {
     text-decoration: none;
     text-decoration: none;
     color: inherit;
     color: inherit;
@@ -563,7 +576,7 @@ kbd:active {
 }
 }
 
 
 .summary::after {
 .summary::after {
-    content: "◀";
+    content: "◀" / "";
     font-size: 1.2em;
     font-size: 1.2em;
     position: absolute;
     position: absolute;
     top: 0;
     top: 0;
@@ -822,7 +835,7 @@ details[open] .summary::after {
 }
 }
 
 
 .list-horizontal-text > *:not(:last-child)::after {
 .list-horizontal-text > *:not(:last-child)::after {
-    content: '•';
+    content: '•' / "";
     color: var(--color-text-subdue);
     color: var(--color-text-subdue);
     margin: 0 0.4rem;
     margin: 0 0.4rem;
     position: relative;
     position: relative;

+ 1 - 1
internal/glance/templates/dns-stats.html

@@ -76,7 +76,7 @@
         <summary class="summary">Top blocked domains</summary>
         <summary class="summary">Top blocked domains</summary>
         <ul class="list list-gap-4 list-with-transition size-h5">
         <ul class="list list-gap-4 list-with-transition size-h5">
             {{ range .Stats.TopBlockedDomains }}
             {{ range .Stats.TopBlockedDomains }}
-            <li class="flex justify-between">
+            <li class="flex justify-between gap-10">
                 <div class="text-truncate rtl">{{ .Domain }}</div>
                 <div class="text-truncate rtl">{{ .Domain }}</div>
                 <div class="text-right" style="width: 4rem;"><span class="color-highlight">{{ .PercentBlocked }}</span>%</div>
                 <div class="text-right" style="width: 4rem;"><span class="color-highlight">{{ .PercentBlocked }}</span>%</div>
             </li>
             </li>

+ 9 - 8
internal/glance/templates/group.html

@@ -4,17 +4,18 @@
 
 
 {{ define "widget-content" }}
 {{ define "widget-content" }}
 <div class="widget-group-header">
 <div class="widget-group-header">
-    <div class="widget-header gap-20">
-        {{ range $i, $widget := .Widgets }}
-            <button class="widget-group-title{{ if eq $i 0 }} widget-group-title-current{{ end }}"{{ if ne "" .TitleURL }} data-title-url="{{ .TitleURL }}"{{ end }}>{{ $widget.Title }}</button>
-        {{ end }}
+    <div class="widget-header gap-20" role="tablist">
+        {{- range $i, $widget := .Widgets }}
+        <button class="widget-group-title{{ if eq $i 0 }} widget-group-title-current{{ end }}"{{ if ne "" .TitleURL }} data-title-url="{{ .TitleURL }}"{{ end }} aria-selected="{{ if eq $i 0 }}true{{ else }}false{{ end }}" arial-level="2" role="tab" aria-controls="widget-{{ .GetID }}-tabpanel-{{ $i }}" id="widget-{{ .GetID }}-tab-{{ $i }}">{{ $widget.Title }}</button>
+        {{- end }}
     </div>
     </div>
 </div>
 </div>
 
 
 <div class="widget-group-contents">
 <div class="widget-group-contents">
-{{ range $i, $widget := .Widgets }}
-    <div class="widget-group-content{{ if eq $i 0 }} widget-group-content-current{{ end }}">{{ .Render }}</div>
-{{ end }}
+{{- range $i, $widget := .Widgets }}
+    <div class="widget-group-content{{ if eq $i 0 }} widget-group-content-current{{ end }}" id="widget-{{ .GetID }}-tabpanel-{{ $i }}" role="tabpanel" aria-labelledby="widget-{{ .GetID }}-tab-{{ $i }}" aria-hidden="{{ if eq $i 0 }}false{{ else }}true{{ end }}">
+        {{- .Render -}}
+    </div>
+{{- end }}
 </div>
 </div>
-
 {{ end }}
 {{ end }}

+ 11 - 9
internal/glance/templates/page.html

@@ -25,7 +25,7 @@
 
 
 {{ define "navigation-links" }}
 {{ define "navigation-links" }}
 {{ range .App.Config.Pages }}
 {{ range .App.Config.Pages }}
-<a href="{{ $.App.Config.Server.BaseURL }}/{{ .Slug }}" class="nav-item{{ if eq .Slug $.Page.Slug }} nav-item-current{{ end }}">{{ .Title }}</a>
+<a href="{{ $.App.Config.Server.BaseURL }}/{{ .Slug }}" class="nav-item{{ if eq .Slug $.Page.Slug }} nav-item-current{{ end }}"{{ if eq .Slug $.Page.Slug }} aria-current="page"{{ end }}>{{ .Title }}</a>
 {{ end }}
 {{ end }}
 {{ end }}
 {{ end }}
 
 
@@ -35,10 +35,10 @@
     <div class="header-container content-bounds">
     <div class="header-container content-bounds">
         <div class="header flex padding-inline-widget widget-content-frame">
         <div class="header flex padding-inline-widget widget-content-frame">
             <!-- TODO: Replace G with actual logo, first need an actual logo -->
             <!-- TODO: Replace G with actual logo, first need an actual logo -->
-            <div class="logo">{{ if ne "" .App.Config.Branding.LogoURL }}<img src="{{ .App.Config.Branding.LogoURL }}" alt="">{{ else if ne "" .App.Config.Branding.LogoText }}{{ .App.Config.Branding.LogoText }}{{ else }}G{{ end }}</div>
-            <div class="nav flex grow">
+            <div class="logo" aria-hidden="true">{{ if ne "" .App.Config.Branding.LogoURL }}<img src="{{ .App.Config.Branding.LogoURL }}" alt="">{{ else if ne "" .App.Config.Branding.LogoText }}{{ .App.Config.Branding.LogoText }}{{ else }}G{{ end }}</div>
+            <nav class="nav flex grow">
                 {{ template "navigation-links" . }}
                 {{ template "navigation-links" . }}
-            </div>
+            </nav>
         </div>
         </div>
     </div>
     </div>
     {{ end }}
     {{ end }}
@@ -57,17 +57,19 @@
     </div>
     </div>
 
 
     <div class="content-bounds grow">
     <div class="content-bounds grow">
-        <div class="page" id="page">
+        <main class="page" id="page" aria-live="polite" aria-busy="true">
+            <h1 class="visually-hidden">{{ .Page.Title }}</h1>
             <div class="page-content" id="page-content"></div>
             <div class="page-content" id="page-content"></div>
             <div class="page-loading-container">
             <div class="page-loading-container">
                 <!-- TODO: add a bigger/better loading indicator -->
                 <!-- TODO: add a bigger/better loading indicator -->
-                <div class="loading-icon"></div>
+                 <div class="visually-hidden">Loading</div>
+                <div class="loading-icon" aria-hidden="true"></div>
             </div>
             </div>
-        </div>
+        </main>
     </div>
     </div>
 
 
     {{ if not .App.Config.Branding.HideFooter }}
     {{ if not .App.Config.Branding.HideFooter }}
-    <div class="footer flex items-center flex-column">
+    <footer class="footer flex items-center flex-column">
     {{ if eq "" .App.Config.Branding.CustomFooter }}
     {{ if eq "" .App.Config.Branding.CustomFooter }}
         <div>
         <div>
             <a class="size-h3" href="https://github.com/glanceapp/glance" target="_blank" rel="noreferrer">Glance</a> {{ if ne "dev" .App.Version }}<a class="visited-indicator" title="Release notes" href="https://github.com/glanceapp/glance/releases/tag/{{ .App.Version }}" target="_blank" rel="noreferrer">{{ .App.Version }}</a>{{ else }}({{ .App.Version }}){{ end }}
             <a class="size-h3" href="https://github.com/glanceapp/glance" target="_blank" rel="noreferrer">Glance</a> {{ if ne "dev" .App.Version }}<a class="visited-indicator" title="Release notes" href="https://github.com/glanceapp/glance/releases/tag/{{ .App.Version }}" target="_blank" rel="noreferrer">{{ .App.Version }}</a>{{ else }}({{ .App.Version }}){{ end }}
@@ -75,7 +77,7 @@
     {{ else }}
     {{ else }}
         {{ .App.Config.Branding.CustomFooter }}
         {{ .App.Config.Branding.CustomFooter }}
     {{ end }}
     {{ end }}
-    </div>
+    </footer>
     {{ end }}
     {{ end }}
 
 
     <div class="mobile-navigation-offset"></div>
     <div class="mobile-navigation-offset"></div>

+ 2 - 2
internal/glance/templates/widget-base.html

@@ -2,9 +2,9 @@
     {{- if not .HideHeader}}
     {{- if not .HideHeader}}
     <div class="widget-header">
     <div class="widget-header">
         {{- if ne "" .TitleURL }}
         {{- if ne "" .TitleURL }}
-        <a href="{{ .TitleURL | safeURL }}" target="_blank" rel="noreferrer" class="uppercase">{{ .Title }}</a>
+        <h2><a href="{{ .TitleURL | safeURL }}" target="_blank" rel="noreferrer" class="uppercase">{{ .Title }}</a></h2>
         {{- else }}
         {{- else }}
-        <div class="uppercase">{{ .Title }}</div>
+        <h2 class="uppercase">{{ .Title }}</h2>
         {{- end }}
         {{- end }}
         {{- if .IsWIP }}
         {{- if .IsWIP }}
         <div data-popover-type="html" data-popover-position="above">
         <div data-popover-type="html" data-popover-position="above">

+ 1 - 2
internal/glance/widget-markets.go

@@ -166,8 +166,7 @@ func fetchMarketsDataFromYahoo(marketRequests []marketRequest) (marketList, erro
 
 
 		points := svgPolylineCoordsFromYValues(100, 50, maybeCopySliceWithoutZeroValues(prices))
 		points := svgPolylineCoordsFromYValues(100, 50, maybeCopySliceWithoutZeroValues(prices))
 
 
-		currency, exists := currencyToSymbol[response.Chart.Result[0].Meta.Currency]
-
+		currency, exists := currencyToSymbol[strings.ToUpper(response.Chart.Result[0].Meta.Currency)]
 		if !exists {
 		if !exists {
 			currency = response.Chart.Result[0].Meta.Currency
 			currency = response.Chart.Result[0].Meta.Currency
 		}
 		}

+ 2 - 2
internal/glance/widget.go

@@ -125,13 +125,13 @@ type widget interface {
 	// These need to be exported because they get called in templates
 	// These need to be exported because they get called in templates
 	Render() template.HTML
 	Render() template.HTML
 	GetType() string
 	GetType() string
+	GetID() uint64
 
 
 	initialize() error
 	initialize() error
 	requiresUpdate(*time.Time) bool
 	requiresUpdate(*time.Time) bool
 	setProviders(*widgetProviders)
 	setProviders(*widgetProviders)
 	update(context.Context)
 	update(context.Context)
 	setID(uint64)
 	setID(uint64)
-	id() uint64
 	handleRequest(w http.ResponseWriter, r *http.Request)
 	handleRequest(w http.ResponseWriter, r *http.Request)
 	setHideHeader(bool)
 	setHideHeader(bool)
 }
 }
@@ -188,7 +188,7 @@ func (w *widgetBase) update(ctx context.Context) {
 
 
 }
 }
 
 
-func (w *widgetBase) id() uint64 {
+func (w *widgetBase) GetID() uint64 {
 	return w.ID
 	return w.ID
 }
 }