diff --git a/.ci/build_indices.sh b/.ci/build_indices.sh new file mode 100644 index 0000000000000000000000000000000000000000..ea563f40feb28c4e551695e2621ae4a39aea9017 --- /dev/null +++ b/.ci/build_indices.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +DIRECTORY=build + +# Install lunr to build the index +npm install lunr@2.3.8 + +# Go to the directory... +cd $DIRECTORY + +printf "Found the following build targets inside: \n$(ls -d */)\n\n" + +# ...and loop through all the build targets +for branch in $(ls -d */); do + echo "Entering: $branch"; + + cd "$branch"; + + echo "Generating the index..." + cat documents.js | node $CI_PROJECT_DIR/build_index.js > index.js + rm documents.js build_index.js + + echo "...should be completed. First 50 characters of the index: " + cat index.js | head -c50 + echo "" + + cd .. + +done + +rm $CI_PROJECT_DIR/build_index.js diff --git a/.ci/deploy.sh b/.ci/deploy.sh index 84ab84e9a0ed5f968790fbce1f9a90cb1c3251a5..d6f5cceb7ad6b0dc94884c6f71ceda2aeff5dc9e 100644 --- a/.ci/deploy.sh +++ b/.ci/deploy.sh @@ -1,4 +1,4 @@ -mkdir -p public +mkdir -p build artefact="latest" # loop through all the branches @@ -14,14 +14,15 @@ for branch in $(git for-each-ref --format='%(refname:strip=3)' refs/remotes); do echo $artefact; git checkout -f $branch git reset --hard $branch + git pull # build the website bundle install - bundle exec jekyll build --baseurl="howto-cards/$artefact" -d "public/$artefact" + bundle exec jekyll build --baseurl="howto-cards/$artefact" -d "build/$artefact" if [[ $branch == "master" ]]; then # set the 404 - cp howto-cards/$artefact/404.html public/404.html + cp howto-cards/$artefact/404.html build/404.html fi done @@ -31,4 +32,4 @@ git checkout -f $CI_COMMIT_REF_NAME git reset --hard origin/$CI_COMMIT_REF_NAME # set the auto redirection -cp .ci/.autoRedirect public/index.html +cp .ci/.autoRedirect build/index.html diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f7e6360d8eb7c15052c6dffc8eb5f5ef76ccfc44..b3e0ff1c39f89bab1519e86f9bf3e333bd824844 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,22 +1,52 @@ # In case something goes horribly wrong, you can fall back to `image: ruby:2.5` image: git-r3lab.uni.lu:4567/r3/docker/jekyll-lcsb:1.1 -variables: - JEKYLL_ENV: production +stages: + - build + - generate_index + - deploy + +build_pages: + stage: build + before_script: + - apt-get -qq update + - apt-get install -y -qq git-lfs + - gem install bundler:2.0.2 && bundle install + script: + - bash .ci/deploy.sh + variables: + JEKYLL_ENV: production + artifacts: + expire_in: 1 day + paths: + - build -before_script: - - apt-get -qq update - - apt-get install -y -qq git-lfs - - gem install bundler:2.0.2 && bundle install + +generate the search index: + stage: generate_index + image: node:13.8.0-slim + rules: + - if: $CI_COMMIT_BRANCH == "master" + - if: $CI_COMMIT_BRANCH == "develop" + script: + - bash .ci/build_indices.sh + - mv build processed_build + artifacts: + expire_in: 1 day + paths: + - processed_build pages: + image: alpine:3.11.3 stage: deploy rules: - if: $CI_COMMIT_BRANCH == "master" - if: $CI_COMMIT_BRANCH == "develop" script: - - bash .ci/deploy.sh - + - mv processed_build public + rules: + - if: $CI_COMMIT_BRANCH == "master" + - if: $CI_COMMIT_BRANCH == "develop" artifacts: expire_in: 1 week paths: diff --git a/_config.yml b/_config.yml index 5e2991f53350af4605cbd0a7147420b779412c59..5aac579f64493c33be53e1e916ad451160d8fa05 100644 --- a/_config.yml +++ b/_config.yml @@ -66,6 +66,7 @@ defaults: path: "external/*" values: include_link: true + searchable: 1.0 # Exclude from processing. (no need to touch these) diff --git a/build_index.js b/build_index.js new file mode 100644 index 0000000000000000000000000000000000000000..eeb6c44f9809fc4f005bc8fa5afdeefea4f3b9dc --- /dev/null +++ b/build_index.js @@ -0,0 +1,28 @@ +var lunr = require('lunr'), + stdin = process.stdin, + stdout = process.stdout, + buffer = []; + +stdin.resume(); +stdin.setEncoding('utf8'); + +stdin.on('data', function (data) { + buffer.push(data); +}); + +stdin.on('end', function () { + var documents = JSON.parse(buffer.join('')) + + var idx = lunr(function () { + this.ref('id') + this.field('title', { boost: 10 }) + this.field('url') + this.field('content') + + documents.forEach(function (doc) { + this.add(doc) + }, this) + }) + + stdout.write(JSON.stringify(idx)) +}); diff --git a/documents.js b/documents.js new file mode 100644 index 0000000000000000000000000000000000000000..5d641bc2d4c23487dba72fb9ff938ae2d430ad92 --- /dev/null +++ b/documents.js @@ -0,0 +1,12 @@ +--- +--- + +{% assign the_cards = site.pages | where_exp:"card","card.searchable >= 1.0" %} + +[ {% for card in the_cards %} { + "id": "{{ card.url | slugify }}", + "title": "{{ card.shortcut | xml_escape }}", + "content": {{ card.content | markdownify | strip_html | jsonify }}, + "url": "{{ card.url | xml_escape | relative_url }}" + } {% unless forloop.last %},{% endunless %} {% endfor %} +] diff --git a/external/contribute/markdown/markdown.md b/external/contribute/markdown/markdown.md index 7c64eb2f8a59c8ebd998e7685e300165aabfabad..b8d26dc5c4fcb2ac4d37b10ba371f619564bb2ab 100644 --- a/external/contribute/markdown/markdown.md +++ b/external/contribute/markdown/markdown.md @@ -34,7 +34,7 @@ Markdown is a lightweight markup language with plain text formatting syntax whic ## Tips to write in markdown: -<table> +<table style="table-layout: fixed; width: 95%;white-space: normal"> <thead> <tr> <th>Markdown</th> @@ -44,7 +44,8 @@ Markdown is a lightweight markup language with plain text formatting syntax whic <tbody> <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + # Header 1<br> ## Header 2<br> ### Header 3 <br> @@ -60,7 +61,8 @@ Markdown is a lightweight markup language with plain text formatting syntax whic </tr> <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + To make a text **bold**, use **double asterisk** or __underscores__ before and after a word or phrase. To make a text **italic**, use *one asterisk* or _underscore_. </pre> @@ -72,7 +74,8 @@ Markdown is a lightweight markup language with plain text formatting syntax whic </tr> <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + Use numbers for ordered lists: 1. First item 2. Second item @@ -99,7 +102,8 @@ Markdown is a lightweight markup language with plain text formatting syntax whic </tr> <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + For unordered lists use asterisk, minus or plus - First item - Second item @@ -125,7 +129,8 @@ Markdown is a lightweight markup language with plain text formatting syntax whic </tr> <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + Include links referring to a web [page](https://www.markdownguide.org/) </pre> </td> @@ -136,15 +141,17 @@ Markdown is a lightweight markup language with plain text formatting syntax whic <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + Include local pictures using markdown:  </pre><br> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + Or use HTML tag allowing you to alter the image properties (e.g. size): - <img src="img/r3_logo.png" width="40"> + <img src="img/r3_logo.png" width="40"> </pre> </td> <td> @@ -156,7 +163,8 @@ Markdown is a lightweight markup language with plain text formatting syntax whic </tr> <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + Include code blocks! ``` def myAwesomeFunction(x): @@ -176,7 +184,8 @@ Markdown is a lightweight markup language with plain text formatting syntax whic </tr> <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + Create table: | Tables | Are | Cool | |------------|:------:|:-----:| @@ -272,7 +281,8 @@ Another big advantage of Markdown is that it can contain HTML tags, which makes <tbody> <tr> <td> - <pre> + <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word"> + # DocTitle ### Attendees: ### Location: diff --git a/search.md b/search.md new file mode 100644 index 0000000000000000000000000000000000000000..516507a781354405ae1f56c3f19de90d4ceb3481 --- /dev/null +++ b/search.md @@ -0,0 +1,135 @@ +--- +layout: page +title: Search +permalink: /search +order: 4 +--- + +<link rel="prefetch" href="index.js" /> + +<style> + #search_query { + border: solid 2px #eee; + padding: 8px; + height: 20px; + font-size: 20px; + width: 500px; + min-width: 400px; + } + + button.search[type=submit] { + border: solid 2px #eee; + padding: 1px; + height: 35px; + width: 150px; + font-size: 20px; + color: #4c4c4c; + background: #efefef; + border-radius: 8px; + margin-top: 3px; + } + + #search_header { + margin-top: 50px; + display: none + } + + #search_results_table { + margin-top: 20px; + width: 100%; + } + + #search_results_placeholder_td { + border: none; + } + + h3.result { + font-size: large; + } +</style> + +<form> + <input class="search" placeholder="What are you looking for?" name="search_query" id="search_query" /><br /> + <button class="search" type="submit">Find it</button> +</form> + +<h1 id="search_header">Results of your query:</h1> + +<table id="search_results_table"> + <tbody id="search_results_tbody"> + <tr id="search_results_placeholder" style="display: none"> + <td id="search_results_placeholder_td"><h3>Please wait, search is in progress...</h3></td> + </tr> + </tbody> +</table> + +<script src="https://cdnjs.cloudflare.com/ajax/libs/lunr.js/2.3.8/lunr.min.js" integrity="sha256-34Si1Y6llMBKM3G0jQILVeoQKEwuxjbk4zGWXXMT4ps=" crossorigin="anonymous"></script> + +<script> + var el_table_body = document.getElementById('search_results_tbody'); + var el_input_query = document.getElementById('search_query'); + var el_tr_placeholder = document.getElementById('search_results_placeholder'); + var el_header = document.getElementById('search_header'); + + var url_params = new URLSearchParams(window.location.search); + var search_term = url_params.get('search_query') || ""; + + if (!!search_term.length) { + el_input_query.value = search_term; + el_header.style.display = "block"; + + el_tr_placeholder.style.display = "block"; + } + + var construct_cell = function(title, content, link) { + if (link == '#') { + return '<td><h3 class="result">' + title + '</h3><p>' + content + '</p></td>'; + } else { + return '<td><h3><a href="' + link + '">' + title + '</a></h3><p>' + content + '</p></td>'; + } + } + + var capitalize = function(text) { + return text.charAt(0).toUpperCase() + text.slice(1); + } + + var prettify = function(text) { + return text.split(':').map(capitalize).join(' » '); + } + + {% assign the_cards = site.pages | where_exp:"card","card.searchable >= 1.0" %} + + window.content = { {% for card in the_cards %} + "{{ card.url | slugify }}": { + "title": "{{ card.shortcut | xml_escape }}", + "content": {{ card.content | strip_html | strip_newlines | jsonify }}, + "url": "{{ card.url | xml_escape | relative_url }}" + } {% unless forloop.last %},{% endunless %} {% endfor %} + }; + + fetch('{{ "index.js" | relative_url }}').then(response => response.text()).then((data) => { + var the_index = JSON.parse(data); + window.search_index = lunr.Index.load(the_index); + + if (search_term != "") { + var results = window.search_index.search(search_term); + for (var i = 0; i < results.length; i++) { + var node = document.createElement("tr"); + node.innerHTML = construct_cell(prettify(window.content[results[i].ref].title), + window.content[results[i].ref].content.substring(0, 125) + '...', + window.content[results[i].ref].url); + el_table_body.appendChild(node); + } + if (results.length == 0) { + var node = document.createElement("tr"); + node.innerHTML = construct_cell("No results", + 'Sorry, we were unable to find anything that matches your query', + "#"); + el_table_body.appendChild(node); + } + } + + el_tr_placeholder.style.display = "none"; + }) + +</script>