diff --git a/config.yaml b/config.yaml index 118ac7a8b..6545e91ce 100644 --- a/config.yaml +++ b/config.yaml @@ -100,3 +100,15 @@ related: weight: 100 threshold: 80 toLower: false + +outputFormats: + JSON: + mediaType: "application/json" + baseName: "search-index" # This ensures the output file is named search-index.json + isPlainText: true + +outputs: + home: + - HTML + - JSON + diff --git a/content/english/search/_index.md b/content/english/search/_index.md new file mode 100644 index 000000000..978d64630 --- /dev/null +++ b/content/english/search/_index.md @@ -0,0 +1,4 @@ +--- +title: "Search the Site" +description: "Find what you're looking for quickly and easily." +--- diff --git a/content/svenska/search/_index.md b/content/svenska/search/_index.md new file mode 100644 index 000000000..b66458643 --- /dev/null +++ b/content/svenska/search/_index.md @@ -0,0 +1,4 @@ +--- +title: "Sök på webbplatsen" +description: "Hitta snabbt och enkelt det du letar efter." +--- diff --git a/layouts/_default/index.json b/layouts/_default/index.json new file mode 100644 index 000000000..f519b06cd --- /dev/null +++ b/layouts/_default/index.json @@ -0,0 +1,14 @@ +[ + {{- $pages := .Site.RegularPages -}} + {{- range $index, $page := $pages -}} + {{- if $index }},{{ end }} + { + "title": {{ $page.Title | jsonify }}, + "url": {{ $page.RelPermalink | jsonify }}, + "tags": {{ $page.Params.tags | jsonify }}, + "keywords": {{ $page.Params.keywords | jsonify }}, + "language": {{ $page.Lang | jsonify }} + } + {{- end -}} + ] + \ No newline at end of file diff --git a/layouts/partials/head.html b/layouts/partials/head.html index ceff9a7f1..d7f33f5f5 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -32,6 +32,9 @@ + + + {{ if or (eq .Section "data_types") (eq .Section "research_projects") (eq .Section "funding") (eq .Section "publications") (eq .Section "dashboards") (.Params.datatables) (eq .Section "datasets") }} diff --git a/layouts/partials/navbar.html b/layouts/partials/navbar.html index 9e5fad935..b38546699 100644 --- a/layouts/partials/navbar.html +++ b/layouts/partials/navbar.html @@ -62,6 +62,11 @@ + @@ -97,6 +102,11 @@ {{ end }} +
diff --git a/layouts/search/list.html b/layouts/search/list.html new file mode 100644 index 000000000..6a2f215f7 --- /dev/null +++ b/layouts/search/list.html @@ -0,0 +1,29 @@ +{{ define "main" }} +
+ +
+

{{ .Title }}

+

{{ .Params.description }}

+
+ + +
+ + + + +
+ + +
+

+ Start typing to see results... +

+ +
+
+{{ end }} + + + diff --git a/static/css/styles.css b/static/css/styles.css index 3274c26cc..cd09dfd07 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -786,3 +786,55 @@ iframe#matoOpOut { height: 250px; } } +/* Search Input */ +#search-input { + padding: 10px; + font-size: 16px; + color: rgb(85, 88, 90); /* Dark Gray */ + border-radius: 0; + outline: none; +} + +#search-input:focus { + border-color: rgb(41, 89, 134); /* Dark Blue */ + box-shadow: 0 0 5px rgba(41, 89, 134, 0.4); +} + +/* Search Results Container */ +#search-results-container { + background-color: rgb(216, 216, 216); /* Accent Gray */ + border-radius: 5px; + border: 1px solid rgb(216, 216, 216); + min-height: 200px; + max-height: 400px; + overflow-y: auto; +} + +/* Search Results List */ +#search-results { + list-style: none; + padding: 0; + margin: 0; +} + +#search-results .list-group-item { + border-bottom: 1px solid rgb(216, 216, 216); /* Accent Gray */ + color: rgb(85, 88, 90); /* Dark Gray */ + padding: 10px; +} + +#search-results .list-group-item:hover { + background-color: rgb(41, 89, 134); /* Dark Blue */ + color: white; + cursor: pointer; +} + +#search-results .list-group-item a { + text-decoration: none; + color: inherit; +} + +#search-results .list-group-item a:hover { + color: white; +} + diff --git a/static/js/fuse-search.js b/static/js/fuse-search.js new file mode 100644 index 000000000..9b2ca7b95 --- /dev/null +++ b/static/js/fuse-search.js @@ -0,0 +1,45 @@ +document.addEventListener("DOMContentLoaded", function () { + const lang = document.documentElement.lang || "en"; // Detect active language + const searchFile = lang === "sv" ? "/sv/search-index.json" : "/search-index.json"; + + fetch(searchFile) + .then((response) => response.json()) + .then((data) => { + const options = { + keys: ["title", "tags", "keywords"], // Fields to search + threshold: 0.4, // Fuzzy matching sensitivity + }; + const fuse = new Fuse(data, options); + + const searchInput = document.getElementById("search-input"); + const searchResultsContainer = document.getElementById("search-results-container"); + const searchResultsList = document.getElementById("search-results"); + const searchResultsMessage = document.getElementById("search-results-message"); + + if (searchInput && searchResultsList && searchResultsMessage) { + searchInput.addEventListener("input", function () { + const query = searchInput.value.trim(); + const results = fuse.search(query); + + if (results.length > 0) { + searchResultsMessage.style.display = "none"; + searchResultsList.innerHTML = results + .map( + (result) => ` +
  • + + ${result.item.title} + +
  • + ` + ) + .join(""); + } else { + searchResultsMessage.style.display = "block"; + searchResultsList.innerHTML = ""; + } + }); + } + }) + .catch((err) => console.error("Error loading search index:", err)); +});