summaryrefslogtreecommitdiff
path: root/internal/web
diff options
context:
space:
mode:
Diffstat (limited to 'internal/web')
-rw-r--r--internal/web/server.go32
-rw-r--r--internal/web/static/base.css31
-rw-r--r--internal/web/templates/index.html38
3 files changed, 88 insertions, 13 deletions
diff --git a/internal/web/server.go b/internal/web/server.go
index 7d9dfe5..f02bc12 100644
--- a/internal/web/server.go
+++ b/internal/web/server.go
@@ -219,6 +219,10 @@ type indexData struct {
Display string
Mono bool
Reading template.HTML
+ // MonthOpts/YearOpts populate the "pobierz" panel's month-calendar
+ // download pickers (localised month names + a year window around the
+ // shown date).
+ MonthOpts, YearOpts []calOpt
// L holds the localised control labels (lectionary/layout/theme/...),
// set from i18n.Get(cfg.UILanguage) -- index.html references its
// fields (e.g. {{.L.Lectionary}}) instead of hardcoded Polish text.
@@ -232,6 +236,13 @@ type versionOpt struct {
Checked bool
}
+// calOpt is one <option> in the pobierz panel's month or year picker.
+type calOpt struct {
+ Val int
+ Label string
+ Sel bool
+}
+
type themeOpt struct {
Name string
Selected bool
@@ -276,6 +287,23 @@ func indexHandler(cfg config.Config) http.HandlerFunc {
themeOpts = append(themeOpts, themeOpt{Name: name, Selected: name == theme})
}
+ // Month/year pickers for the "pobierz" panel's month-calendar download.
+ // Selected from the shown date; the year list is a small window around
+ // it so the shown year is always present and pre-selected.
+ labels := i18n.Get(cfg.UILanguage)
+ selYear, selMonth := 0, 0
+ if t, err := time.Parse("2006-01-02", date); err == nil {
+ selYear, selMonth = t.Year(), int(t.Month())
+ }
+ monthOpts := make([]calOpt, 0, 12)
+ for i, name := range labels.Months {
+ monthOpts = append(monthOpts, calOpt{Val: i + 1, Label: name, Sel: i+1 == selMonth})
+ }
+ yearOpts := make([]calOpt, 0, 6)
+ for y := selYear - 2; y <= selYear+3; y++ {
+ yearOpts = append(yearOpts, calOpt{Val: y, Label: strconv.Itoa(y), Sel: y == selYear})
+ }
+
data := indexData{
Date: date,
PrevDate: shiftDate(date, -1),
@@ -288,7 +316,9 @@ func indexHandler(cfg config.Config) http.HandlerFunc {
Display: display,
Mono: queryBool(r, "mono", cfg.WebMono),
Reading: reading,
- L: i18n.Get(cfg.UILanguage),
+ MonthOpts: monthOpts,
+ YearOpts: yearOpts,
+ L: labels,
Lang: cfg.UILanguage,
}
diff --git a/internal/web/static/base.css b/internal/web/static/base.css
index 757e935..b5f4f13 100644
--- a/internal/web/static/base.css
+++ b/internal/web/static/base.css
@@ -322,9 +322,34 @@ a {
gap: var(--space-2);
}
-/* Export links (download the readings). */
-.export { font-family: var(--font-ui); font-size: 0.85rem; }
-.export a { margin: 0 0.15rem; }
+/* "pobierz" disclosure: a summary styled as a nav link that reveals a small
+ * floating panel of download options (a month calendar with its own month/year
+ * pickers, and the shown day's txt/md/pdf export). The panel is absolutely
+ * positioned under the link so opening it never reflows the controls bar.
+ * Colour (border/background) is the theme's, via the shared --bg/--fg tokens. */
+.export { position: relative; font-family: var(--font-ui); font-size: 0.85rem; }
+.export > summary { cursor: pointer; list-style: none; }
+.export > summary::-webkit-details-marker { display: none; }
+.export > summary::after { content: " \25be"; } /* down caret */
+.export[open] > summary::after { content: " \25b4"; } /* up caret */
+.export-panel {
+ position: absolute;
+ right: 0;
+ top: calc(100% + 0.35rem);
+ z-index: 10;
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-1);
+ padding: var(--space-2);
+ border-width: 1px;
+ border-style: solid;
+ background: var(--bg);
+ white-space: nowrap;
+}
+.export-row { display: flex; align-items: center; gap: 0.5rem; }
+.export-row .export-label { font-weight: 600; }
+.export-panel select { font: inherit; }
+.export-panel a { margin: 0; }
/* Bookmark marker: a red "*" flagging a bookmarked verse in the reader. A fixed
* semantic red (not a theme colour), visible on light and dark themes alike. */
diff --git a/internal/web/templates/index.html b/internal/web/templates/index.html
index 3379dc1..b20131d 100644
--- a/internal/web/templates/index.html
+++ b/internal/web/templates/index.html
@@ -32,6 +32,8 @@ function stepDate(n){
<form id="controls" class="controls" hx-get="/readings" hx-target="#pane" hx-trigger="change">
<div class="controls-main">
+ {{/* The reader entry point is the primary action, so it leads the bar. */}}
+ <a class="nav-link nav-reader" href="/reader">{{.L.NavReader}} &rarr;</a>
{{/* Always-present marker so the server can tell a form submit with every
version unchecked (show nothing) from a fresh visit (config default). */}}
<input type="hidden" name="vset" value="1">
@@ -65,17 +67,35 @@ function stepDate(n){
</label>
</div>
- {{/* Utility links, pinned to the top-right (see #controls / .controls-side).
- The export URLs are built from the live control values at click time. */}}
+ {{/* Utility cluster, pinned to the top-right (see #controls / .controls-side):
+ settings, then a "pobierz" disclosure that opens two download options --
+ a month calendar (its own month/year pickers) and the shown day's
+ readings as txt/md/pdf. Both URLs are built from live values at click
+ time (the readings export from the whole control form, the calendar from
+ its own pickers plus the hidden lectionary field). */}}
<span class="controls-side">
- <a class="nav-link nav-reader" href="/reader">{{.L.NavReader}} &rarr;</a>
<a class="nav-link" href="/settings">{{.L.NavSettings}}</a>
- <span class="export">{{.L.Export}}:
- <a href="#" onclick="location='/export?fmt=txt&'+new URLSearchParams(new FormData(document.getElementById('controls'))).toString();return false;">txt</a>
- <a href="#" onclick="location='/export?fmt=md&'+new URLSearchParams(new FormData(document.getElementById('controls'))).toString();return false;">md</a>
- <a href="#" onclick="location='/export?fmt=pdf&'+new URLSearchParams(new FormData(document.getElementById('controls'))).toString();return false;">pdf</a>
- ยท <a href="#" onclick="var d=(document.querySelector('#controls [name=date]').value||'').slice(0,7);location='/calendar?month='+d+'&lectionary='+document.querySelector('#controls [name=lectionary]').value;return false;">{{.L.Calendar}}</a>
- </span>
+ <details class="export">
+ <summary class="nav-link">{{.L.Export}}</summary>
+ <div class="export-panel">
+ <div class="export-row">
+ <span class="export-label">{{.L.Calendar}}</span>
+ <select id="cal-month" aria-label="{{.L.Calendar}}">
+ {{range .MonthOpts}}<option value="{{.Val}}"{{if .Sel}} selected{{end}}>{{.Label}}</option>{{end}}
+ </select>
+ <select id="cal-year">
+ {{range .YearOpts}}<option value="{{.Val}}"{{if .Sel}} selected{{end}}>{{.Label}}</option>{{end}}
+ </select>
+ <a href="#" onclick="var m=document.getElementById('cal-month').value,y=document.getElementById('cal-year').value;location='/calendar?month='+y+'-'+('0'+m).slice(-2)+'&lectionary='+document.querySelector('#controls [name=lectionary]').value;return false;">PDF</a>
+ </div>
+ <div class="export-row">
+ <span class="export-label">{{.Date}}</span>
+ <a href="#" onclick="location='/export?fmt=txt&'+new URLSearchParams(new FormData(document.getElementById('controls'))).toString();return false;">txt</a>
+ <a href="#" onclick="location='/export?fmt=md&'+new URLSearchParams(new FormData(document.getElementById('controls'))).toString();return false;">md</a>
+ <a href="#" onclick="location='/export?fmt=pdf&'+new URLSearchParams(new FormData(document.getElementById('controls'))).toString();return false;">pdf</a>
+ </div>
+ </div>
+ </details>
</span>
</form>