静的サイトの検索


過去数ヶ月間、私は自分のためにwikiをセットアップする計画がありました.私はどのツールを使用するかについての私のオプションを探求していました.この考えは9月に起きました、そして、これはFossユナイテッドのHackathonのための同じ時間でした.グループの上のポストハッカーソン議論は全く面白かったです、そして、これはADigital Garden 上へ.更なる研究で、これは私が私のメモと考えを組織するために良いオプションのようでした.私は私のオプションを見たRoam Research and Obsidian それはかなり涼しかったが、Roamは支払われました、そして、黒曜石は電子アプリでした😬. 私はまた、それが良いときに、これらの公共利用できるようにしたかったので、それをホストしても私のために必要だったので、私は私の検索を続けた.そこにFoam and TiddlyWiki しかし、悲しげに私のためにこれらのtiddlywikiを除いて以下のhackableです.Then comes zettel これはハッカートンのプロジェクトだった.簡単に言えば、ZettelはMarkdownファイル用のSSG/CLIです.それはWikiLinksをサポートしました[[]] ) 碁で作った😻. 私は、それのコードベースに貢献していました.私はそれに構文強調表示と数学機能を実装していた.
それが私の記事を調べるために私の記事を調べるために私の時間を減らすので、検索は私のための最も欲しかった機能でした.だから私はそれを実装しようとした

検索を設定する


ZettelはGOで作られて以来、私は最初にHugoで検索機能を実装する方法を探しました1 ウェブサイト.私がGoogleから得た結果は、公式hugoからありましたdocs . 商用サービスがいくつかあり、いくつかのハッキングがあった.The fastSearch GISTは非常に興味深く、私のユースケースと一致しました.次のステップはどのようにHugoからZettelにそれをポートすることができました.

インデックス


さらに検索は私にどのように検索機能のアイデアを得た.スターターの場合は、インデックスファイルを必要とします.ここでは、検索インデックスの必要性のためのラフな表現です

それはあなたがインデックスを見て本の中にあるものを見つけることができる本のインデックスと同じようです.インデックスファイルは検索を高速にするので重要です.これは、検索に使用するためのインデックスを作成するために全体のウェブサイトをscrapeするためにかなり時間がかかるし、我々はデータを盗むためにサーバー側を持っていないので、このメソッドは私たちのケースのためのノーゴーとなります.私たちはかなり簡単にビルド時間でインデックスを作成したい.
Zettel接続されたマークダウンページについてのグラフを表示するこの機能があります.これを作成するには、グラフデータ型を使用してフロントエンドでの使用を示すsigma.js . マークダウンファイルはノードであり、接続はエッジです.シグマJSはフロントエンドで生成するJSONファイルを使用します.このJSONファイルまたはgraph.json はビルド時に生成される.
そこで、同じトリックを使って検索用のインデックスファイルを生成しました.検索インデックスの新しい構造を作成しました
type PostData struct {
  Title     string   `json:"title"` // the Title of the page
  Permalink string   `json:"permalink"` // the Permalink/Link of the Page
  Tags      []string `json:"tags"` // the Tags of the page if available
}
ビルド時にこのようなJSONファイルを生成します
[
    {
        "title": "Adguard Telegram Bot",
        "permalink": "posts/adbot.html",
        "tags": [
            "go",
            "code",
            "other"
        ]
    },
    {
        "title": "Config for Zettel local dev with Air",
        "permalink": "posts/air-zettel.html",
        "tags": [
            "code",
            "other"
        ]
    }
]
そして、これはページの検索インデックスとして機能します.次に、いくつかのJSとCSSでフロントエンドで動作するようになりました

フジジン


インデックスの後にJSONインデックスを解析して結果を返すJSライブラリを使用する必要があります.GISTの使い方Fuze.js 私も同じように使いました.煙霧.JSはJSONインデックスを受け取り、JSONインデックスから返されます.検索作業を行うためのコードはGISTで利用できましたが、現在のユースケースの修正を必要としました.私はjsに慣れていません、しかし、私はコードを読んで、理解することができました.私はコードをAHCKすることができて、それを作動させました.
// Code by Craig Mod under MIT License
// https://gist.github.com/cmod/5410eae147e4318164258742dd053993
var fuse; 
var list = document.getElementById('searchResults');
var first = list.firstChild;
var last = list.lastChild;
var maininput = document.getElementById('searchInput');
var resultsAvailable = false;
var baseURL = window.location.pathname.split("/")[1]
if (baseURL.length === 0 || baseURL.includes("html") || baseURL.includes("posts")) {
    baseURL = window.location.origin
} else {
    baseURL = "/" + baseURL
}
console.log(baseURL)
loadSearch()
document.addEventListener('keydown', function(event) {
  if (event.keyCode == 27) {
      document.activeElement.blur();
      resultsAvailable = false;
      list.style.display="none"
  }
  if (event.keyCode == 40) {
    if (resultsAvailable) {
      event.preventDefault();
      if ( document.activeElement == maininput) { first.focus(); } 
      else if ( document.activeElement == last ) { last.focus(); } 
      else { document.activeElement.parentElement.nextSibling.firstElementChild.focus(); } 
    }
  }
  if (event.keyCode == 38) {
    if (resultsAvailable) {
      event.preventDefault();
      if ( document.activeElement == maininput) { maininput.focus(); } 
      else if ( document.activeElement == first) { maininput.focus(); } 
      else { document.activeElement.parentElement.previousSibling.firstElementChild.focus(); } 
    }
  }
});
document.getElementById("searchInput").onkeyup = function(e) {
    list.style.display=""
  executeSearch(this.value);
}
function fetchJSONFile(path, callback) {
  var httpRequest = new XMLHttpRequest();
  httpRequest.onreadystatechange = function() {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        var data = JSON.parse(httpRequest.responseText);
          if (callback) callback(data);
      }
    }
  };
  httpRequest.open('GET', path);
  httpRequest.send(); 
}
function loadSearch() { 
  fetchJSONFile(baseURL + "/data/search.json", function(data){
    var options = { 
      shouldSort: true,
      location: 0,
      distance: 100,
      threshold: 0.4,
      minMatchCharLength: 2,
      keys: ['title','tags']
    };
    fuse = new Fuse(data, options); 
  });
}
function executeSearch(term) {
  let results = fuse.search(term); 
  let searchitems = ''; 
  if (results.length === 0) { 
    resultsAvailable = false;
    searchitems = '';
  } else { 
    for (let item in results.slice(0,5)) { 
    const title = results[item].title.replace(new RegExp(term, "gi"), (match) => `<mark class="searchHgl">${match}</mark>`);
    tags = results[item].tags.map((value)=>{
      return value.replace(new RegExp(term, "gi"), (match) => `<mark class="searchHgl">${match}</mark>`);
    })
    searchitems = searchitems + '<li><a href="' + baseURL + '/' + results[item].permalink + '" tabindex="0"><span class="title">' + title + "</span> — " + tags + "</a></li>";
    }
    resultsAvailable = true;
  }
  document.getElementById("searchResults").innerHTML = searchitems;
  if (results.length > 0) {
    first = list.firstChild.firstElementChild; 
    last = list.lastChild.firstElementChild; 
  }
}
私もいくつかの楽しい結果を検索用語の強調表示を追加しました<mark> HTMLのタグ🙌). 私は、元のものからJSコードを変更してCMD + / オプションを検索を開始します.インデックスから検索するキーは、タイトルとタグです.内容をインデックスすることは多くのページロード時間を加えます、そして、縮小されるとき、JSONはより大きいサイズです.
CSSの部分はCSSを知りませんでした.私は私の友人から電話をかけて、それがよりよく、よりコンパクトに見えるようにしたいくつかの助けを得た.
最後の結果はこちら👇

私は、JS部分とCSS部分のためにコード全体をAとしましたGitHub Gist 😁 指示も.あなたがデジタルガーデンとZettelに興味があるならば、チェックアウトを確認してください
  • Maggie Appleton's Repo for Digital Gardens
  • エーsubreddit デジタルガーデナー
  • Personal fork of Zettel
  • あなたがそれを役に立つならば、あなたは私の上で私を寄付することができますBMC ☕️ or Paypal そして、私に手を差し伸べることができます
    Hugoはgoの静的サイトジェネレータです.https://gohugo.io