From 28b1ee8408797d0bf47ddcf0780c79778c983deb Mon Sep 17 00:00:00 2001 From: itchyny <itchyny@cybozu.co.jp> Date: Sat, 24 Jun 2023 13:05:39 +0900 Subject: [PATCH] Redesign website * Bump up Bootstrap to v5.3.1, Bootstrap Icon to v1.10.5. * Use autoComplete.js to drop dependency on jQuery and typeahead.js. * Support dark mode. * New svg logo and icon with responsive color mode support. * Normalize section ids to lower kebab-case for easiness of linking. * Use relative paths for links for local development (--root /output). * Various markup cleanups and accessibility improvements. --- .github/workflows/website.yml | 2 +- Makefile.am | 6 +- docs/README.md | 14 +- docs/build_website.py | 37 ++++-- docs/content/download/default.yml | 6 +- docs/content/index.yml | 8 +- docs/content/manual/manual.yml | 5 +- docs/content/manual/v1.3/manual.yml | 2 +- docs/content/manual/v1.4/manual.yml | 2 +- docs/content/manual/v1.5/manual.yml | 2 +- docs/content/manual/v1.6/manual.yml | 2 +- docs/public/css/base.css | 173 ------------------------ docs/public/css/base.scss | 181 -------------------------- docs/public/css/style.css | 99 ++++++++++++++ docs/public/icon.png | Bin 0 -> 4963 bytes docs/public/icon.svg | 1 + docs/public/jq.png | Bin 8195 -> 0 bytes docs/public/jq.svg | 1 + docs/public/js/manual-search.js | 80 +++++------- docs/site.yml | 9 -- docs/templates/default.html.j2 | 41 +++--- docs/templates/index.html.j2 | 91 ++++++------- docs/templates/manual.html.j2 | 179 +++++++++++++------------ docs/templates/shared/_footer.html.j2 | 20 +-- docs/templates/shared/_head.html.j2 | 32 +++-- docs/templates/shared/_navbar.html.j2 | 63 +++++---- 26 files changed, 401 insertions(+), 655 deletions(-) delete mode 100644 docs/public/css/base.css delete mode 100644 docs/public/css/base.scss create mode 100644 docs/public/css/style.css create mode 100644 docs/public/icon.png create mode 100644 docs/public/icon.svg delete mode 100644 docs/public/jq.png create mode 100644 docs/public/jq.svg delete mode 100644 docs/site.yml diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 9de1aa6259..6fc8b8095a 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' cache: pipenv - name: Install pipenv run: pip install pipenv diff --git a/Makefile.am b/Makefile.am index e3b3e5a244..00133f6d87 100644 --- a/Makefile.am +++ b/Makefile.am @@ -197,14 +197,10 @@ endif ### Packaging -docs/site.yml: configure.ac - sed 's/^jq_version: .*/jq_version: "$(VERSION)"/' $@ > $@.new - mv $@.new $@ - install-binaries: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec -DOC_FILES = docs/content docs/public docs/templates docs/site.yml \ +DOC_FILES = docs/content docs/public docs/templates \ docs/Pipfile docs/Pipfile.lock docs/build_manpage.py \ docs/build_mantests.py docs/build_website.py docs/README.md \ docs/validate_manual_schema.py docs/manual_schema.yml diff --git a/docs/README.md b/docs/README.md index 52fdd59b82..3ea88160cc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,16 +11,16 @@ need `python3` and `pipenv`. You can install `pipenv` like so: Though, you may need to say `pip3` instead, depending on your system. Once you have `pipenv` installed, you can install the dependencies by running -`pipenv sync` from the `docs` directory. +`pipenv sync` from the `docs/` directory. Also, you may need to run `virtualenv -p /usr/bin/python3 venv/` and then `source venv/bin/activate`, and only then `pipenv sync`. Once this is done, rerun `./configure` in the jq root directory and then -the Makefile will be able to generate the jq manpage. You can also just -run `pipenv run build_manpage.py` in the `docs` directory to build the -`jq.1` page manually, and `pipenv run build_mantests.py` to build the -contents of `tests/man.test` and `tests/manonig.test`. +the `Makefile` will be able to generate the jq manpage. You can just run +`make jq.1` to build the manpage manually, and `make tests/man.test` to +update the manual tests. -To build the website, run `pipenv run ./build_website.py` from inside -the `docs` directory. +To build the website, run `pipenv run python3 build_website.py --root /output` +in the `docs/` directory. To serve them locally, you can run +`python3 -m http.server`. diff --git a/docs/build_website.py b/docs/build_website.py index 5867f8c0a6..2b3afc77e2 100755 --- a/docs/build_website.py +++ b/docs/build_website.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import argparse import glob import itertools from jinja2 import Environment, FileSystemLoader, select_autoescape, pass_context @@ -10,6 +11,10 @@ import shutil import yaml +parser = argparse.ArgumentParser() +parser.add_argument('--root', default='/jq') +args = parser.parse_args() + env = Environment( loader=FileSystemLoader('templates'), autoescape=select_autoescape(['html.j2']), @@ -21,40 +26,51 @@ def load_yml_file(fn): return yaml.safe_load(f) +env.globals['url'] = 'https://jqlang.github.io/jq' +env.globals['root'] = args.root + env.filters['search_id'] = lambda input: input.replace(r'`', '') -env.filters['section_id'] = lambda input: re.sub(r"[^a-zA-Z0-9_]", '', input) -env.filters['entry_id'] = lambda input: re.sub(r"[ `]", '', input) +env.filters['section_id'] = lambda input: re.sub( + r'[^-a-zA-Z0-9_]', '', input.replace(' ', '-')).lower() +env.filters['entry_id'] = lambda input: re.sub( + r'^(split|first-last-nth)$', + r'\1' + ('-1' if ';' not in input else '-2'), # avoid id conflict + re.sub( + r'\b([^-]+)(?:-\1)+\b', + r'\1', # e.g. range-range-range -> range + re.sub(r' ?/ ?|,? ', '-', + re.sub(r'[`;]|: .*|\(.*?\)| \[.+\]', '', input)))).lower() env.filters['markdownify'] = lambda input: Markup(markdown(input)) -env.filters['no_paragraph'] = lambda input: Markup(re.sub(r"</?p>", '', input)) +env.filters['no_paragraph'] = lambda input: Markup(re.sub(r'</?p>', '', input)) env.globals['unique_id'] = pass_context( lambda ctx: str(next(ctx['unique_ctr']))) -env.globals.update(load_yml_file('site.yml')) -env.globals['navigation'] = ['tutorial', 'download', 'manual'] +def raise_handler(message): + raise Exception(message) + + +env.globals['raise'] = raise_handler -def generate_file(env, fname='content/1.tutorial/default.yml'): +def generate_file(env, fname): path, base = os.path.split(fname) path = os.path.relpath(path, 'content') if path == '.': path = '' - slug = 'index' permalink = '' else: - slug = os.path.basename(path) permalink = path + '/' output_dir = os.path.join('output', path) output_path = os.path.join(output_dir, 'index.html') - template_name = re.sub(r".yml$", '.html.j2', base) + template_name = re.sub(r'.yml$', '.html.j2', base) ctx = load_yml_file(fname) ctx.update(unique_ctr=itertools.count(1), permalink=permalink, - slug=slug, navitem=path) os.makedirs(output_dir, exist_ok=True) env.get_template(template_name).stream(ctx).dump(output_path, @@ -72,6 +88,7 @@ def copy_public_files(root=''): shutil.copyfile(f.path, dst) +os.makedirs('output', exist_ok=True) copy_public_files() for fn in glob.glob('content/**/*.yml', recursive=True): diff --git a/docs/content/download/default.yml b/docs/content/download/default.yml index 4f39c6128c..970f1c85a7 100644 --- a/docs/content/download/default.yml +++ b/docs/content/download/default.yml @@ -196,9 +196,9 @@ body: #### Building the documentation jq's documentation is compiled into static HTML using Python. - To build the docs, run `pipenv run python3 build_website.py` from - the docs/ subdirectory. To serve them locally, you can run - `python3 -m SimpleHTTPServer`. You'll need a few Python dependencies, + To build the docs, run `pipenv run python3 build_website.py --root /output` + in the `docs/` directory. To serve them locally, you can run + `python3 -m http.server`. You'll need a few Python dependencies, which can be installed by following the instructions in `docs/README.md`. The man page is built by `make jq.1`, or just `make`, also from diff --git a/docs/content/index.yml b/docs/content/index.yml index 02ecafe5e7..82dcde9845 100644 --- a/docs/content/index.yml +++ b/docs/content/index.yml @@ -24,7 +24,7 @@ body3: | tail: | - Go read the [tutorial](/jq/tutorial/) for more, or the [manual](/jq/manual/) + Go read the [tutorial](./tutorial/) for more, or the [manual](./manual/) for *way* more. Have a question related to jq? You can seek answers on [Stack Overflow](https://stackoverflow.com/) @@ -34,7 +34,7 @@ tail: | news: - date: 1 November 2018 body: | - jq 1.6 released. See installation options on the [download](/jq/download/) + jq 1.6 released. See installation options on the [download](./download/) page, and the [release notes](https://github.com/jqlang/jq/releases/tag/jq-1.6) for details. @@ -44,7 +44,7 @@ news: jq 1.5 released, including new datetime, math, and regexp functions, try/catch syntax, array and object destructuring, a streaming parser, and a module system. See installation options on the - [download](/jq/download/) page, and the + [download](./download/) page, and the [release notes](https://github.com/jqlang/jq/releases/tag/jq-1.5) for details. @@ -63,7 +63,7 @@ news: - date: 09 June 2014 body: | - jq 1.4 (finally) released! Get it on the [download](/jq/download/) page. + jq 1.4 (finally) released! Get it on the [download](./download/) page. - date: 19 May 2013 body: | diff --git a/docs/content/manual/manual.yml b/docs/content/manual/manual.yml index 89252ac243..e4c8c64bca 100644 --- a/docs/content/manual/manual.yml +++ b/docs/content/manual/manual.yml @@ -3,9 +3,8 @@ headline: jq Manual (development version) history: | - *For released versions, see [jq 1.6](/jq/manual/v1.6), - [jq 1.5](/jq/manual/v1.5), [jq 1.4](/jq/manual/v1.4) - or [jq 1.3](/jq/manual/v1.3).* + *For released versions, see [jq 1.6](./v1.6/), [jq 1.5](./v1.5/), + [jq 1.4](./v1.4/) or [jq 1.3](./v1.3/).* body: | diff --git a/docs/content/manual/v1.3/manual.yml b/docs/content/manual/v1.3/manual.yml index c018e3142c..8cab6204bf 100644 --- a/docs/content/manual/v1.3/manual.yml +++ b/docs/content/manual/v1.3/manual.yml @@ -4,7 +4,7 @@ headline: jq 1.3 Manual history: | *The manual for the development version of jq can be found - [here](/jq/manual).* + [here](../).* body: | diff --git a/docs/content/manual/v1.4/manual.yml b/docs/content/manual/v1.4/manual.yml index 6cc1c5913b..cbfb82631e 100644 --- a/docs/content/manual/v1.4/manual.yml +++ b/docs/content/manual/v1.4/manual.yml @@ -4,7 +4,7 @@ headline: jq 1.4 Manual history: | *The manual for the development version of jq can be found - [here](/jq/manual).* + [here](../).* body: | diff --git a/docs/content/manual/v1.5/manual.yml b/docs/content/manual/v1.5/manual.yml index be2f1c562a..14f70532f4 100644 --- a/docs/content/manual/v1.5/manual.yml +++ b/docs/content/manual/v1.5/manual.yml @@ -4,7 +4,7 @@ headline: jq 1.5 Manual history: | *The manual for the development version of jq can be found - [here](/jq/manual).* + [here](../).* body: | diff --git a/docs/content/manual/v1.6/manual.yml b/docs/content/manual/v1.6/manual.yml index be62cab6cd..0a3d6002a2 100644 --- a/docs/content/manual/v1.6/manual.yml +++ b/docs/content/manual/v1.6/manual.yml @@ -4,7 +4,7 @@ headline: jq 1.6 Manual history: | *The manual for the development version of jq can be found - [here](/jq/manual).* + [here](../).* body: | diff --git a/docs/public/css/base.css b/docs/public/css/base.css deleted file mode 100644 index e9bb818dc6..0000000000 --- a/docs/public/css/base.css +++ /dev/null @@ -1,173 +0,0 @@ -body { - padding-top: 80px; -} - -.container { - max-width: 970px; -} - -/* index.liquid *******************************************/ -#blurb { - padding-top: 40px; -} -#blurb p { - font-size: 1.9em; -} -#blurb .btn-group { - margin: 4px; -} - -#multiblurb { - line-height: 1.7; - text-align: center; - font-size: 12pt; -} -#multiblurb code { - border: 0; - font-size: 12pt; -} - -#news { - font-size: 12pt; -} -#news .date { - font-style: italic; -} - -/* default.liquid *****************************************/ -.tutorial-example { - position: relative; - margin-bottom: 10px; -} -.tutorial-example pre { - margin-bottom: 0px; -} -.tutorial-example a { - position: absolute; - top: 0px; - right: 0px; - padding: 15px 8px; - color: #777777; - font-weight: bold; - line-height: 10px; - font-size: 12px; - border-left: 1px solid #DDDDDD; - display: block; -} -.tutorial-example .accordion-body pre { - margin: 0 4px; - border-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -@media print { - .tutorial-example a { - display: none; - } -} -/* manual.liquid ******************************************/ -section { - padding-top: 24px; -} - -h3 code { - border: 0; - font-size: 20px; -} - -@media (max-width: 991px) { - #navcolumn { - /* Put nav column above manual content */ - position: relative !important; - margin-bottom: 60px; - } -} -@media (min-width: 992px) { - #manualcontent { - /* Put nav column left of manual content */ - padding-left: 280px; - } -} -.nav-pills { - margin-bottom: 20px; -} - .nav-pills li a { - padding: 8px 12px; -} - -.manual-example table { - border-top: 1px solid #E5E5E5; -} -.manual-example table td { - white-space: pre-wrap; - font-family: Monaco, Menlo, Consolas, "Courier New", monospace; -} -.manual-example table td.jqprogram { - font-weight: bold; -} -.manual-example table th { - text-align: right; - padding-right: 10px; -} - -@media print { - #navcolumn { - display: none !important; - } - - .manual-example { - display: block !important; - height: auto !important; - } - - .jqplay-btn { - display: none !important; - } -} -/* shared/_footer.liquid **********************************/ -footer { - background-color: #F5F5F5; - padding: 20px 0; - margin-top: 40px; - color: #999999; - text-align: center; -} -footer p { - margin: 8px 0; -} - -/* typeahead **********************************************/ -.twitter-typeahead { - width: 100%; -} - -.tt-menu { - width: 100%; - background-color: #fff; - padding: 8px 0; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - -webkit-border-radius: 8px; - -moz-border-radius: 8px; - border-radius: 8px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -} - -.tt-suggestion { - padding: 3px 20px; -} -.tt-suggestion:hover { - cursor: pointer; - color: #fff; - background-color: #446e9b; -} -.tt-suggestion.tt-cursor { - color: #fff; - background-color: #446e9b; -} -.tt-suggestion p { - margin: 0; -} diff --git a/docs/public/css/base.scss b/docs/public/css/base.scss deleted file mode 100644 index ffef3de440..0000000000 --- a/docs/public/css/base.scss +++ /dev/null @@ -1,181 +0,0 @@ -@charset "utf-8"; -body { - padding-top: 80px; -} - -.container { - max-width: 970px; -} - -/* index.liquid *******************************************/ - -#blurb { - padding-top: 40px; - p { - font-size: 1.9em; - } - .btn-group { - margin: 4px; - } -} - -#multiblurb { - line-height: 1.7; - text-align: center; - font-size: 12pt; - code { - border: 0; - font-size: 12pt; - } -} - -#news { - font-size: 12pt; - .date { - font-style: italic; - } -} - -/* default.liquid *****************************************/ - -.tutorial-example { - position: relative; - margin-bottom: 10px; - pre { - margin-bottom: 0px; - } - a { - position: absolute; - top: 0px; - right: 0px; - padding: 15px 8px; - color: #777777; - font-weight: bold; - line-height: 10px; - font-size: 12px; - border-left: 1px solid #DDDDDD; - display: block; - } - .accordion-body pre { - margin: 0 4px; - border-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; - } -} - -@media print { - .tutorial-example a { - display: none; - } -} - -/* manual.liquid ******************************************/ - -section { - padding-top: 24px; -} - -h3 code { - border: 0; - font-size: 20px; -} - -@media(max-width: 991px){ - #navcolumn { - /* Put nav column above manual content */ - position: relative !important; - margin-bottom: 60px; - } -} - -@media(min-width: 992px) { - #manualcontent { - /* Put nav column left of manual content */ - padding-left: 280px; - } -} - -.nav-pills { - li a { - padding: 8px 12px; - } - margin-bottom: 20px; -} - -.manual-example table { - border-top: 1px solid #E5E5E5; - td { - white-space: pre-wrap; - font-family: Monaco, Menlo, Consolas, "Courier New", monospace; - } - td.jqprogram { - font-weight: bold; - } - th { - text-align: right; - padding-right: 10px; - } -} - -@media print { - #navcolumn { - display: none !important; - } - .manual-example { - display: block !important; - height: auto !important; - } - .jqplay-btn { - display: none !important; - } -} - -/* shared/_footer.liquid **********************************/ - -footer { - background-color: #F5F5F5; - padding: 20px 0; - margin-top: 40px; - color: #999999; - text-align: center; - p { - margin: 8px 0; - } -} - -/* typeahead **********************************************/ - -.twitter-typeahead { - width: 100%; -} - -.tt-menu { - width: 100%; - background-color: #fff; - padding: 8px 0; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - -webkit-border-radius: 8px; - -moz-border-radius: 8px; - border-radius: 8px; - -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); - -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); - box-shadow: 0 5px 10px rgba(0,0,0,.2); -} - -.tt-suggestion { - padding: 3px 20px; - &:hover { - cursor: pointer; - color: #fff; - background-color: #446e9b; - } - &.tt-cursor { - color: #fff; - background-color: #446e9b; - } - p { - margin: 0; - } -} diff --git a/docs/public/css/style.css b/docs/public/css/style.css new file mode 100644 index 0000000000..d63e828275 --- /dev/null +++ b/docs/public/css/style.css @@ -0,0 +1,99 @@ +main { + padding: 1rem; + + & * { + scroll-margin-top: 4rem; + } + + @media print { + width: 100%!important; + --bs-code-color: --bs-body-color; + } +} + +header { + z-index: 1050!important; /* higher than #contents */ +} + +section[id] { + display: flow-root; + + > :first-child { + .icon-link { + opacity: 0; + + &:focus { + opacity: .8; + } + } + + &:hover .icon-link { + opacity: 1; + } + } +} + +.offcanvas[aria-modal=true] .nav-link { + padding: .7rem; +} +.offcanvas-md { + --bs-offcanvas-width: auto; +} + +ul { + list-style: none; + padding-left: 1rem; +} + +pre { + margin: 0 .5rem 1rem; + padding: .5rem 1rem; + background-color: var(--bs-secondary-bg-subtle); + border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color); +} + +button{ + &[aria-expanded=false] .bi-chevron-down { + display: none; + } + + &[aria-expanded=true] .bi-chevron-right { + display: none; + } +} + +mark { + padding: 0; +} + +.container-searchbox { + position: relative; + + & input:focus ~ kbd { + display: none; + } + + & ul { + position: absolute; + width: 100%; + top: 100%; + padding: 0; + background-color: var(--bs-body-bg); + border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color); + } + + & li { + padding: .3em .6em; + white-space: nowrap; + overflow-x: hidden; + + &[aria-selected=true] { + background-color: var(--bs-secondary-bg); + } + + &:hover { + cursor: pointer; + background-color: var(--bs-secondary-bg-subtle); + } + } +} diff --git a/docs/public/icon.png b/docs/public/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cfdc8ecda9840955ed9b0031693acbe5606842d6 GIT binary patch literal 4963 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 YkV0_R5Mv=?@PZ7YrmU@01-A+NKgP>a@c;k- literal 0 HcmV?d00001 diff --git a/docs/public/icon.svg b/docs/public/icon.svg new file mode 100644 index 0000000000..1f518f047f --- /dev/null +++ b/docs/public/icon.svg @@ -0,0 +1 @@ +<svg width="48" height="48" version="1.0" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"><style>@media(prefers-color-scheme:dark){g[fill]{filter:invert(1)}}</style><g transform="matrix(.011 0 0 .011 1.94 12)"><g fill="#444"><circle cx="220" cy="1570" r="190"/><path d="m1330 312c-30 41-698 1492-710 1528s25 66 100 101c77 36 102 34 124 3s701-1477 716-1525c15-47-20-73-84-104s-116-44-146-3z"/></g><g fill="#111"><circle cx="2410" cy="200" r="190"/><path d="m1830 655c0 129 0 130 70 130h360v423c0 246-5 474-10 506-19 112-88 176-190 176-59 0-120-27-147-66-51-73-65-84-99-84-31 0-40 8-104 93-84 111-86 129-32 189 227 252 692 187 836-118 53-112 56-153 56-795v-514c0-64-30-100-100-100h-490c-149 0-150 0-150 160zM2867 1233c30 302 250 499 438 527 144 19 244 0 375-90v410c0 81 0 100 150 100 136 0 150-20 150-150v-1420c0-99-19-100-150-100s-139 15-139 82c-103-89-351-149-523-49s-342 278-301 690zm803-107c0 292-105 356-237 356-178 0-249-147-273-296-27-168 25-420 262-420 171 0 248 89 248 360z"/></g></g></svg> diff --git a/docs/public/jq.png b/docs/public/jq.png deleted file mode 100644 index 41d6d391dbf86ed4d36559d19f2cd3885b077096..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8195 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 diff --git a/docs/public/jq.svg b/docs/public/jq.svg new file mode 100644 index 0000000000..1f9e2ddf6d --- /dev/null +++ b/docs/public/jq.svg @@ -0,0 +1 @@ +<svg width="400" height="220" version="1.0" viewBox="0 0 400 220" xmlns="http://www.w3.org/2000/svg"><style>@media (prefers-color-scheme:dark){g[fill]{filter:invert(1);stroke:none}}</style><g transform="scale(.1)" stroke="#fff" stroke-width="10"><g fill="#444"><circle cx="220" cy="1570" r="190"/><path d="m1330 312c-30 41-698 1492-710 1528s25 66 100 101c77 36 102 34 124 3s701-1477 716-1525c15-47-20-73-84-104s-116-44-146-3z"/></g><g fill="#111"><circle cx="2410" cy="200" r="190"/><path d="m1830 655c0 129 0 130 70 130h360v423c0 246-5 474-10 506-19 112-88 176-190 176-59 0-120-27-147-66-51-73-65-84-99-84-31 0-40 8-104 93-84 111-86 129-32 189 227 252 692 187 836-118 53-112 56-153 56-795v-514c0-64-30-100-100-100h-490c-149 0-150 0-150 160zM2867 1233c30 302 250 499 438 527 144 19 244 0 375-90v410c0 81 0 100 150 100 136 0 150-20 150-150v-1420c0-99-19-100-150-100s-139 15-139 82c-103-89-351-149-523-49s-342 278-301 690zm803-107c0 292-105 356-237 356-178 0-249-147-273-296-27-168 25-420 262-420 171 0 248 89 248 360z"/></g></g></svg> diff --git a/docs/public/js/manual-search.js b/docs/public/js/manual-search.js index e5d6ee53ab..6c7c72d56e 100644 --- a/docs/public/js/manual-search.js +++ b/docs/public/js/manual-search.js @@ -1,52 +1,34 @@ -var section_names = function(q) { - if (!q) { - return []; - } - var matches = []; - q = q.toLowerCase(); - $.each(section_map, function(k, v) { - if (k.toLowerCase().indexOf(q) != -1) { - matches.push(k); - } - }); - matches.sort(function(a, b) { - // shortest to longest - return a.length - b.length; +(() => { + const searchInput = document.querySelector('input#searchbox'); + const sectionIDs = JSON.parse(document.querySelector('#section-ids').innerText); + const sanitize = (string) => string.replaceAll('<', '<').replaceAll('>', '>'); + new autoComplete({ + selector: `#${searchInput.id}`, + wrapper: false, + data: { + src: Object.keys(sectionIDs), + filter: (list) => list.sort((x, y) => + x.match.indexOf('<') - y.match.indexOf('<') || x.value.length - y.value.length), + }, + searchEngine: (query, value) => { + const index = value.toLowerCase().indexOf(query.toLowerCase()); + if (index >= 0) { + return sanitize(value.substring(0, index)) + + `<mark>${sanitize(value.substring(index, index + query.length))}</mark>` + + sanitize(value.substring(index + query.length)); + } + }, }); - return matches; -} -var section_names_cb = function(q, cb) { - cb(section_names(q)); -} -var go_to_section = function() { - query = $('#searchbox').val(); - results = section_names(query); - if (results.length == 0) { - return; - } - result = results[0]; - location.hash = '#' + section_map[result]; - if (result != query) { - $('#searchbox').val(result); - } -} -$(function(){ - $('#searchbox').typeahead( - {hint: false, highlight: true, minLength: 1}, - {name: "contents", source: section_names_cb, limit: 6} - ).on('typeahead:selected', function(e, data) { - go_to_section(); + searchInput.addEventListener('selection', (event) => { + event.target.value = event.detail.selection.value; + location.hash = `#${sectionIDs[event.detail.selection.value]}`; }); - $('#searchbox').change(go_to_section); -}); -// add "Run" button to execute examples on jqplay.org -$(function() { - $.each($('.manual-example table'), function(index, value) { - $value = $(value) - var j = $value.find('tr:nth-child(2) td:first').text(); - var q = $value.find('.jqprogram').text().replace(/^jq /, '').replace(/(\r\n|\n|\r)/gm," ").replace(/^'(.+)'$/, '$1'); - var url = 'https://jqplay.org/jq?q=' + encodeURIComponent(q) +'&j=' + encodeURIComponent(j) - var $last_tr = $value.find('tr:last'); - $last_tr.after('<tr class="jqplay-btn"><th><a href="' + url + '" class="btn btn-primary btn-sm">Run</a></th><th></th></tr><tr><th></th><th></th></tr>'); + document.addEventListener('keydown', (event) => { + if (event.code === 'Slash' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey && !/^(INPUT|TEXTAREA)$/.test(event.target.nodeName)) { + searchInput.focus(); + searchInput.select(); + event.preventDefault(); + } }); -}); +})(); diff --git a/docs/site.yml b/docs/site.yml deleted file mode 100644 index e4990aeb9e..0000000000 --- a/docs/site.yml +++ /dev/null @@ -1,9 +0,0 @@ -# The key value pairs found below are available within the templates. - -url: https://jqlang.github.io/jq - -# This line is modified by the Makefile. To change the version number, -# edit the Autoconf version number at the top of configure.ac -jq_version: "1.6-159-gcff5336-dirty" - -root: '/jq' diff --git a/docs/templates/default.html.j2 b/docs/templates/default.html.j2 index 7830eb3726..67030e0566 100644 --- a/docs/templates/default.html.j2 +++ b/docs/templates/default.html.j2 @@ -2,32 +2,29 @@ <html lang="en"> {% include "shared/_head.html.j2" %} - <body id="{{slug}}"> + <body> {% include "shared/_navbar.html.j2" %} - <div class="container"> - <div class="row"> - <h1>{{headline}}</h1> - {% for item in body %} - {% if item.text %} - {{ item.text | replace('$JQ_VERSION', jq_version) | markdownify }} - {% endif %} + <main id="main" class="container-lg"> + <h1>{{ headline }}</h1> + {%- for item in body %} + {%- if item.text %} + {{ item.text | markdownify }} + {%- endif %} - {% if item.command %} - {% set resultID = unique_id() %} - <div class="tutorial-example"> - <div class="accordion-heading"> - <pre>{{item.command}}</pre> - <a data-toggle="collapse" href="#result{{resultID}}">Show result</a> - </div> - <div id="result{{resultID}}" class="accordion-body collapse"> - <pre>{{item.result}}</pre> - </div> - </div> - {% endif %} - {% endfor %} + {%- if item.command %} + {%- set resultID = unique_id() %} + <div class="tutorial-example mb-3"> + <div class="d-flex accordion-heading me-2"> + <pre class="flex-grow-1 me-0 mb-0" tabindex="0">{{ item.command }}</pre> + <button type="button" class="btn btn-sm btn-secondary text-body-secondary bg-secondary-subtle link-body-emphasis flex-shrink-0 d-flex align-items-center border border-start-0 d-print-none" + data-bs-toggle="collapse" data-bs-target="#result{{ resultID }}" aria-expanded="false" aria-controls="result{{ resultID }}">Show result</button> + </div> + <pre id="result{{ resultID }}" class="accordion-body collapse p-3 border-top-0 d-print-block" tabindex="0">{{ item.result }}</pre> </div> - </div> + {%- endif %} + {%- endfor %} + </main> {% include "shared/_footer.html.j2" %} </body> diff --git a/docs/templates/index.html.j2 b/docs/templates/index.html.j2 index 4ec30007fb..3fd1566ec4 100644 --- a/docs/templates/index.html.j2 +++ b/docs/templates/index.html.j2 @@ -2,71 +2,54 @@ <html lang="en"> {% include "shared/_head.html.j2" %} - <body id="{{ slug }}"> + <body> {% include "shared/_navbar.html.j2" %} - <div class="container"> + <main id="main" class="container-lg"> <div class="row"> - <div class="jumbotron"> - <div class="row"> - <div class="col-sm-6"> - <img src="{{root}}/jq.png" class="img-responsive" alt="jq logo" - width="400" height="220"> - </div> - <div class="col-sm-6"> - <div id="blurb"> - {{blurb | markdownify}} - - <div class="btn-toolbar" role="toolbar"> - <div class="btn-group" role="group"> - <a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#"> - Download jq 1.6 - <span class="caret"></span> - </a> - <ul class="dropdown-menu"> - <li><a href="https://github.com/jqlang/jq/releases/download/jq-1.6/jq-linux64">Linux (64-bit)</a></li> - <li><a href="https://github.com/jqlang/jq/releases/download/jq-1.6/jq-osx-amd64">macOS (64-bit)</a></li> - <li><a href="https://github.com/jqlang/jq/releases/download/jq-1.6/jq-win64.exe">Windows (64-bit)</a></li> - <li><a href="{{root}}/download/">Other platforms, older versions, and source</a></li> - </ul> - </div> - - <div class="btn-group"> - <a class="btn btn-primary" href="https://jqplay.org"> - Try online at jqplay.org! - </a> - </div> - </div> - </div> - </div> + <div class="col-md-6 text-center p-3"> + <h1><img src="{{ root }}/jq.svg" class="img-fluid" alt="jq" width="400" height="220"></h1> + </div> + <div class="col-md-6 d-flex flex-column justify-content-center text-center align-items-center"> + <h2 class="px-1" style="width:16em">{{ blurb }}</h2> + <div class="btn-group d-print-none" role="group"> + <button type="button" class="btn btn-primary dropdown-toggle text-nowrap" data-bs-toggle="dropdown" aria-expanded="false"> + Download jq 1.6 + <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + <li><a class="dropdown-item" href="https://github.com/jqlang/jq/releases/download/jq-1.6/jq-linux64" aria-label="Link to download executable: Linux (64-bit)"><span class="bi bi-download me-2" aria-hidden="true"></span>Linux (64-bit)</a></li> + <li><a class="dropdown-item" href="https://github.com/jqlang/jq/releases/download/jq-1.6/jq-osx-amd64" aria-label="Link to download executable: macOS (64-bit)"><span class="bi bi-download me-2" aria-hidden="true"></span>macOS (64-bit)</a></li> + <li><a class="dropdown-item" href="https://github.com/jqlang/jq/releases/download/jq-1.6/jq-win64.exe" aria-label="Link to download executable: Windows (64-bit)"><span class="bi bi-download me-2" aria-hidden="true"></span>Windows (64-bit)</a></li> + <li><a class="dropdown-item" href="{{ root }}/download/">Other platforms, older versions, and source</a></li> + </ul> + <a class="btn btn-primary text-nowrap" href="https://jqplay.org" target="_blank" rel="noopener"> + Try online at jqplay.org!<span class="bi bi-box-arrow-up-right ms-1" aria-hidden="true"></span> + </a> </div> </div> </div> - <div class="row" id="multiblurb"> - <div class="col-sm-4">{{body1 | markdownify}}</div> - <div class="col-sm-4">{{body2 | markdownify}}</div> - <div class="col-sm-4">{{body3 | markdownify}}</div> + <div class="row my-3"> + <div class="col-md-4">{{ body1 | markdownify }}</div> + <div class="col-md-4">{{ body2 | markdownify }}</div> + <div class="col-md-4">{{ body3 | markdownify }}</div> </div> - <div class="row" style="text-align:center; margin-top: 30px"> - {{tail | markdownify}} + <div class="text-center my-3"> + {{ tail | markdownify }} </div> - <div class="row"> - <h2>News</h2> - <div id="news"> - <ul> - {% for item in news %} - <li> - <span class="date">{{item.date}}</span> - {{item.body | markdownify}} - </li> - {% endfor %} - </ul> - </div> - </div> - </div> + <h2>News</h2> + <ul> + {%- for item in news %} + <li> + <span class="fst-italic">{{ item.date }}</span> + {{ item.body | markdownify }} + </li> + {%- endfor %} + </ul> + </main> {% include "shared/_footer.html.j2" %} </body> diff --git a/docs/templates/manual.html.j2 b/docs/templates/manual.html.j2 index 21f9ad28e2..9a2540c8b0 100644 --- a/docs/templates/manual.html.j2 +++ b/docs/templates/manual.html.j2 @@ -2,98 +2,109 @@ <html lang="en"> {% include "shared/_head.html.j2" %} - <body id="{{slug}}" data-spy="scroll" data-target="#navcolumn" data-offset="100"> + <body> {% include "shared/_navbar.html.j2" %} - <div class="container"> - <div class="row"> - <div class="affix" id="navcolumn"> + <div class="container-lg row align-items-start mx-auto p-3"> + + <button type="button" class="d-md-none w-auto position-fixed bottom-0 end-0 p-2 m-3 bg-body-secondary border-0 text-body d-print-none" + data-bs-toggle="offcanvas" data-bs-target="#contents" aria-controls="contents" aria-expanded="false" aria-label="Toggle table of contents"> + <span class="bi bi-list" aria-hidden="true"></span> + </button> + <nav id="contents" class="col-md-3 sticky-md-top p-3 overflow-y-auto offcanvas-md offcanvas-end d-print-none" style="top:4.5rem; height:calc(100dvh - 5.5rem);" aria-label="Table of contents"> + <div class="d-flex justify-content-between"> <h4>Contents</h4> - <ul class="nav nav-pills nav-stacked"> - {% for section in sections %} - <li> - <a href="#{{section.title | section_id}}">{{section.title}}</a> - </li> - {% endfor %} - </ul> - <form class="form-group" onsubmit="go_to_section(); return false;"> - <input type="text" - class="form-control" - placeholder="Search" - autocomplete="off" - id="searchbox"> - </form> + <button type="button" class="btn-close d-md-none" data-bs-dismiss="offcanvas" data-bs-target="#contents" aria-label="Close table of contents"></button> </div> + <ul class="offcanvas-md-body nav nav-pills flex-column"> + {%- for section in sections %} + <li class="nav-item" data-bs-dismiss="offcanvas" data-bs-target="#contents"> + <a class="nav-link" href="#{{ section.title | section_id }}">{{ section.title }}</a> + </li> + {%- endfor %} + </ul> + </nav> + {%- set section_ids = {} %} + {%- macro check_section_id(id) -%} + {%- if section_ids.__contains__(id) %} + {{- raise('Duplicate section id: ' ~ id) }} + {%- endif %} + {%- set _ = section_ids.__setitem__(id, true) %} + {%- endmacro %} + <main id="main" class="col-md-9" data-bs-spy="scroll" data-bs-target="#contents" data-bs-threshold="0,1" data-bs-root-margin="-30% 0% -70%"> + <h1>{{ headline }}</h1> + {{ history | markdownify }} + {{ body | markdownify }} + {%- for section in sections %} + <section id="{{ section.title | section_id }}">{{ check_section_id(section.title | section_id) }} + <h2>{{ section.title }} <a href="#{{ section.title | section_id }}" class="icon-link" aria-label="Link to this section: {{ section.title }}"><span class="bi bi-link-45deg" aria-hidden="true"></span></a></h2> + {{ section.body | markdownify if section.body }} + {%- for entry in section.entries %} + <section id="{{ entry.title | entry_id }}">{{ check_section_id(entry.title | entry_id) }} + <h3> + {{ entry.title | markdownify | no_paragraph }} + <a href="#{{ entry.title | entry_id }}" class="icon-link" aria-label="Link to this section: {{ entry.title }}"><span class="bi bi-link-45deg" aria-hidden="true"></span></a> + </h3> + {{ entry.body | markdownify }} + {%- if entry.examples %} + <div class="pb-3"> + {%- set exampleID = unique_id() %} + <button type="button" class="btn btn-sm btn-secondary text-body-secondary bg-transparent link-body-emphasis border-0" data-bs-toggle="collapse" data-bs-target="#example{{ exampleID }}" aria-expanded="false" aria-controls="example{{ exampleID }}"> + <span class="me-1 d-print-none" aria-hidden="true"><span class="bi bi-chevron-right"></span><span class="bi bi-chevron-down"></span></span>Example{% if entry.examples | length > 1 %}s{% endif %} + </button> + <div id="example{{ exampleID }}" class="collapse mx-3 small d-print-block"> + {%- for example in entry.examples %} + <table class="table table-borderless table-sm w-auto"> + <tr> + <th class="pe-3">Command</th> + <td class="font-monospace">jq '{{ example.program }}'</td> + </tr> + <tr> + <th>Input</th> + <td class="font-monospace">{{ example.input }}</td> + </tr> + {%- if not example.output[0] %} + <tr> + <th>Output</th> + <td class="fst-italic">none</td> + </tr> + {%- endif %} + {%- for output in example.output %} + <tr> + <th>{% if loop.first %}Output{% endif %}</th> + <td class="font-monospace">{{ output }}</td> + </tr> + {%- endfor %} + <tr class="d-print-none"> + <th><a href="https://jqplay.org/jq?q={{ example.program | urlencode }}&j={{ example.input | urlencode }}" class="btn btn-outline-primary btn-sm" target="_blank" rel="noopener">Run<span class="bi bi-box-arrow-up-right ms-2" aria-hidden="true"></span></a></th> + <td></td> + </tr> + </table> + {%- endfor %} + </div> + </div> + {%- endif %} + </section> + {%- endfor %} + </section> + {%- endfor %} + </main> - <div id="manualcontent"> - <h1>{{headline}}</h1> - {{ history | markdownify }} - {{ body | markdownify }} - {% for section in sections %} - <section id="{{section.title | section_id}}"> - <h2>{{section.title}}</h2> - {{ (section.body | markdownify) if section.body }} - {% for entry in section.entries %} - <section id="{{entry.title | entry_id}}"> - <h3> - {{entry.title | markdownify | no_paragraph }} - {% if entry.subtitle %}<small>{{entry.subtitle}}</small>{% endif %} - </h3> - {{entry.body | markdownify}} - - {% if entry.examples %} - <div> - {% set exampleID = unique_id() %} - <a data-toggle="collapse" href="#example{{exampleID}}"> - <i class="glyphicon glyphicon-chevron-right"></i> - {% if entry.examples | length > 1 %}Examples{%else%}Example{%endif%} - </a> - <div id="example{{exampleID}}" class="manual-example collapse"> - {% for example in entry.examples %} - <table> - <tr><th></th><td class="jqprogram">jq '{{ example.program }}'</td></tr> - <tr><th>Input</th><td>{{ example.input }}</td></tr> - {% if not example.output[0] %} - <tr> - <th>Output</th> - <td><i>none</i></td> - </tr> - {% endif %} - {% for output in example.output %} - <tr> - {% if loop.first %} - <th>Output</th> - {% else %} - <th></th> - {% endif %} - <td>{{ output }}</td> - </tr> - {% endfor %} - </table> - {% endfor %} - </div> - </div> - {% endif %} - </section> - {% endfor %} - </section> - {% endfor %} - </div> - </div> </div> {% include "shared/_footer.html.j2" %} - <script> - var section_map = { - {% for section in sections %} - {% for entry in section.entries %} - {{entry.title | search_id | tojson }} : {{entry.title | entry_id | tojson }}, - {% endfor %} - {{section.title | search_id | tojson }} : {{section.title | section_id | tojson }} - {% if not loop.last %},{% endif %} - {% endfor %} - }; + <script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.7/dist/autoComplete.min.js" + integrity="sha384-xbzjoN6H5XHmAqoSSR42hZVRninPGx85y+XZQGlWxVu2y91lTmr/oD80i5cjeUBv" crossorigin="anonymous"></script> + <script id="section-ids" type="application/json"> + { + {%- for section in sections %} + {%- for entry in section.entries %} + {{ entry.title | search_id | tojson }}: {{ entry.title | entry_id | tojson }}, + {%- endfor %} + {{ section.title | search_id | tojson }}: {{ section.title | section_id | tojson }}{{ "," if not loop.last }} + {%- endfor %} + } </script> - <script src="{{root}}/js/manual-search.js"></script> + <script src="{{ root }}/js/manual-search.js"></script> </body> </html> diff --git a/docs/templates/shared/_footer.html.j2 b/docs/templates/shared/_footer.html.j2 index 511f0b1fac..dbed4f2759 100644 --- a/docs/templates/shared/_footer.html.j2 +++ b/docs/templates/shared/_footer.html.j2 @@ -1,10 +1,14 @@ - <footer> - <div class="container"> - <p>This website is made with <a href="http://getbootstrap.com">Bootstrap</a>, themed with <a href="https://bootswatch.com">Bootswatch</a>.</p> - <p>jq is licensed under the MIT license (code) and the <a href="https://creativecommons.org/licenses/by/3.0/">CC-BY-3.0</a> license (docs).</p> + <footer class="bd-footer bg-body-tertiary"> + <div class="py-3 text-center"> + <p> + This website is made with <a href="https://getbootstrap.com" target="_blank" rel="noopener">Bootstrap</a>, + themed with <a href="https://bootswatch.com" target="_blank" rel="noopener">Bootswatch</a>. + </p> + <p> + jq is licensed under the MIT license (code) and the + <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank" rel="noopener">CC-BY-3.0</a> license (docs). + </p> </div> </footer> - - <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> - <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha256-Sk3nkD6mLTMOF0EOpNtsIry+s1CsaqQC1rVLTAy+0yc= sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script> - <script src="https://twitter.github.io/typeahead.js/releases/0.11.1/typeahead.bundle.js"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" + integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script> diff --git a/docs/templates/shared/_head.html.j2 b/docs/templates/shared/_head.html.j2 index 96c3c4dc60..7a240307f8 100644 --- a/docs/templates/shared/_head.html.j2 +++ b/docs/templates/shared/_head.html.j2 @@ -1,17 +1,23 @@ <head> - <script> - if ((window.location.host == "jqlang.github.io") && (window.location.protocol != "https:")) - window.location.protocol = "https"; - </script> <meta charset="utf-8"> - <title>{{headline}}</title> + <title>{{ headline }}</title> <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta http-equiv="X-UA-Compatible" content="IE=edge" /> - <link rel="canonical" href="{{ url }}/{{ permalink }}" /> - <link href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/spacelab/bootstrap.min.css" rel="stylesheet" integrity="sha256-j7Dtnd7ZjexEiPNbscbopFn9+Cs0b3TLipKsWAPHZIM= sha512-RFhfi6P8zWMAJrEGU+CPjuxPh3r/UUBGqQ+/o6WKPIVZmQqeOipGotH2ihRULuQ8wsMBoK15TSZqc/7VYWyuIw==" crossorigin="anonymous"> - <link rel="stylesheet" href="{{ root }}/css/base.css" type="text/css"> - <!--[if lt IE 9]> - <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> - <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> - <![endif]--> + <link rel="icon" href="{{ root }}/icon.svg" type="image/svg+xml"> + <link rel="apple-touch-icon" href="{{ root }}/icon.png" type="image/png"> + <link rel="canonical" href="{{ url }}/{{ permalink }}"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.3.1/dist/cosmo/bootstrap.min.css" + integrity="sha384-dulfW0vmzZ638jigSgZXvDxMmd70GCnIv6oa+riKq6Kk4E0MKf7qmBfwP02wltv5" crossorigin="anonymous"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" + integrity="sha384-Ay26V7L8bsJTsX9Sxclnvsn+hkdiwRnrjZJXqKmkIDobPgIIWBOVguEcQQLDuhfN" crossorigin="anonymous"> + <link rel="stylesheet" href="{{ root }}/css/style.css" type="text/css"> + <script> + (function() { + function setTheme(mediaQuery) { + document.documentElement.setAttribute('data-bs-theme', + document.documentElement.style.colorScheme = mediaQuery.matches ? 'dark' : 'light'); + } + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + setTheme(mediaQuery); mediaQuery.addEventListener('change', setTheme); + })(); + </script> </head> diff --git a/docs/templates/shared/_navbar.html.j2 b/docs/templates/shared/_navbar.html.j2 index a3238611e7..92222902fe 100644 --- a/docs/templates/shared/_navbar.html.j2 +++ b/docs/templates/shared/_navbar.html.j2 @@ -1,27 +1,40 @@ - <div class="navbar navbar-default navbar-fixed-top" role="navigation"> - <div class="container"> - <div class="navbar-header"> - <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#nav-collapse"> - <span class="sr-only">Toggle navigation</span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </button> - <a class="navbar-brand" href="{{root}}/">jq</a> - </div> - - <div class="navbar-collapse collapse" id="nav-collapse"> - <ul class="nav navbar-nav"> - {% for item in navigation %} - <li {% if item == navitem %} class="active" {% endif %}> - <a href="{{root}}/{{item}}/">{{item | capitalize}}</a> - </li> - {% endfor %} - <li><a href="https://github.com/jqlang/jq/issues">Issues</a></li> - <li><a href="https://github.com/jqlang/jq">Source</a></li> - <li><a href="https://jqplay.org">Try online!</a></li> - <li><a href="https://raw.githubusercontent.com/jqlang/jq/master/NEWS.md">News</a></li> + <div class="container visually-hidden-focusable"> + <a class="d-inline-flex p-2" href="#main">Skip to main content</a> + {%- if navitem.startswith('manual') %} + <a class="d-inline-flex p-2 m-1" href="#contents">Skip to table of contents</a> + {%- endif %} + </div> + <header class="navbar navbar-expand-md sticky-top bg-body-tertiary d-print-none"> + <nav class="container-lg" aria-label="Page navigation"> + <button type="button" class="navbar-toggler" data-bs-toggle="offcanvas" data-bs-target="#navbar-collapse" + aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle page navigation"> + <span class="navbar-toggler-icon"></span> + </button> + <a class="navbar-brand" href="{{ root }}/" aria-label="Top page"><img src="{{ root }}/jq.svg" alt="jq logo" style="height:1.5rem"></a> + <div id="navbar-collapse" class="offcanvas offcanvas-start navbar-collapse w-auto" aria-labelledby="navbar-title"> + <div class="offcanvas-header"> + <h3 id="navbar-title" class="me-3">jq</h3> + <button type="button" class="d-md-none btn-close" data-bs-dismiss="offcanvas" aria-label="Close page navigation"></button> + </div> + <ul class="offcanvas-body navbar-nav me-auto text-nowrap"> + <li class="nav-item d-md-none"><a class="nav-link{% if not navitem %} active{% endif %}"{% if not navitem %} aria-current="page"{% endif %} href="{{ root }}/">Top page</a></li> + {%- for item in ['tutorial', 'download', 'manual'] %} + <li class="nav-item"><a class="nav-link{% if item == navitem %} active{% endif %}"{% if item == navitem %} aria-current="page"{% endif %} href="{{ root }}/{{ item }}/">{{ item | capitalize }}</a></li> + {%- endfor %} + <li class="nav-item"><a class="nav-link" href="https://github.com/jqlang/jq" target="_blank" rel="noopener">GitHub</a></li> + <li class="nav-item"><a class="nav-link" href="https://github.com/jqlang/jq/issues" target="_blank" rel="noopener">Issues</a></li> + <li class="nav-item"><a class="nav-link" href="https://jqplay.org" target="_blank" rel="noopener">Try online!</a></li> + <li class="nav-item"><a class="nav-link" href="https://raw.githubusercontent.com/jqlang/jq/master/NEWS.md" target="_blank" rel="noopener">News</a></li> </ul> </div> - </div> - </div> + {%- if navitem.startswith('manual') %} + <div class="container-searchbox form-control p-0 d-none d-md-flex d-print-none border" style="width:16rem"> + <span class="bi bi-search my-auto ms-2 me-1" aria-hidden="true"></span> + <input type="text" id="searchbox" class="form-control border-0 px-1" placeholder="Search manual" role="combobox" + aria-label="Search manual" aria-keyshortcuts="/" aria-expanded="false" autocomplete="off" spellcheck="false"> + <kbd class="mx-1 my-auto text-body bg-body rounded border" style="padding:.1rem .2rem" aria-hidden="true">/</kbd> + </div> + {%- endif %} + <a class="d-md-none bi bi-github fs-4 text-body" href="https://github.com/jqlang/jq" target="_blank" rel="noopener" aria-label="GitHub"></a> + </nav> + </header>