Установка Quartz

Клонирование quartz

https://quartz.jzhao.xyz

git clone https://github.com/jackyzha0/quartz.git hub.zlonov.ru
cd hub.zlonov.ru
npm i
npx quartz create

Выбираем последовательно опции:

  • Empty Quartz
  • Treat links as shortest path (for most Obsidian vaults)

Создание репозитория

https://quartz.jzhao.xyz/setting-up-your-GitHub-repository

Then, create a new repository on GitHub.com. Do not initialize the new repository with README, license, or gitignore files.

На выходе: https://github.com/zlonov/hub.zlonov.ru.git

Настройка репозитория

https://quartz.jzhao.xyz/setting-up-your-GitHub-repository

Отредактировать файл hub.zlonov.ru/.git/config

[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true
[remote "origin"]
	url = https://github.com/zlonov/hub.zlonov.ru.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "v4"]
	remote = origin
	merge = refs/heads/v4
[remote "upstream"]
	url = https://github.com/jackyzha0/quartz.git
	fetch = +refs/heads/*:refs/remotes/upstream/*

To verify that you set the remote URL correctly, run the following command.

git remote -v

Then, you can sync the content to upload it to your repository.

npx quartz sync --no-pull

Добавление репозитория в GitHub Desktop

Add Add Existing Repository... Choose... hub.zlonov.ru

Commit to v4

Добавление внешнего подмодуля

https://git-scm.com/book/ru/v2/Инструменты-Git-Подмодули

Удалить папку hub.zlonov.ru/content/

Добавить подмодуль

git submodule add https://gitflic.ru/project/zlonov/catalog.git content

Отправить обновление в репозиторий через GitHub Desktop:

Commit to v4 с комментарием “Добавлен подмодуль”

Можно убедиться, что подмодуль корректно добавлен: https://github.com/zlonov/hub.zlonov.ru

Обновление контента и Хаба

Обновление данных в подмодуле

Один раз создаём удобный псевдоним для проверки и обновления подмодуля:

git config alias.sup 'submodule update --remote --merge'

Теперь вместо этой длинной команды можно писать просто: git sup

  • Вносим изменения
  • Выполняем в GitHub Desktop Commit to master и Push
  • Обновляем репозиторий с учётом изменений подмодуля git sup
  • Выполняем в GitHub Desktop Commit to v4 и Push

Можно посмотреть как выполняются Actions: https://github.com/zlonov/hub.zlonov.ru/actions

Вариант для командной строки: https://git-scm.com/book/ru/v2/Основы-Git-Запись-изменений-в-репозиторий

  • Вносим изменения
  • Выполняем в GitHub Desktop Commit to master и Push
  • Обновляем репозиторий с учётом изменений подмодуля git sup
  • Выполняем git commit -a -m "Update content" (благодаря опции -a не нужно выполнять git add ИМЯ.ФАЙЛА)
  • Отправляем изменения на сервер git push

Вариант для командной строки с использованием псевдонимов https://git-scm.com/book/ru/v2/Основы-Git-Псевдонимы-в-Git

  • Один раз создаём короткий псевдоним: git config alias.up '!git submodule update --remote --merge && git commit -a -m "Update content" && git push'
  • Далее его используем: git up

Настройки после клонирования на другой компьютер

Сначала инициировать: npm i

Локальный предпросмотр Хаба

npx quartz build --serve

Сбор статистики

Счётчики

Umami

<script defer src="https://eu.umami.is/script.js" data-website-id="e080cafe-f61b-48c1-9cb2-0d744e043a53"></script>

Google

<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-120278956-1"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
 
  gtag('config', 'UA-120278956-1');
</script>

Яндекс старый

<!-- Yandex.Metrika counter -->
<script src="https://mc.yandex.ru/metrika/watch.js" type="text/javascript" ></script>
<script type="text/javascript" >
try {
    var yaCounter96251472 = new Ya.Metrika({
        id:96251472,
        clickmap:true,
        trackLinks:true,
        accurateTrackBounce:true
    });
} catch(e) { }
</script>
<!-- /Yandex.Metrika counter -->

Яндекс новый (не ясно, как установить)

<!-- Yandex.Metrika counter -->
<script type="text/javascript" >
   (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
   m[i].l=1*new Date();
   for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
   k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
   (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
 
   ym(96251472, "init", {
        clickmap:true,
        trackLinks:true,
        accurateTrackBounce:true
   });
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/96251472" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->

Дефолтные способы вызовов

if (cfg.analytics?.provider === "google") {
    const tagId = cfg.analytics.tagId
    staticResources.js.push({
      src: `https://www.googletagmanager.com/gtag/js?id=${tagId}`,
      contentType: "external",
      loadTime: "afterDOMReady",
    })
    componentResources.afterDOMLoaded.push(`
      window.dataLayer = window.dataLayer || [];
      function gtag() { dataLayer.push(arguments); }
      gtag("js", new Date());
      gtag("config", "${tagId}", { send_page_view: false });
 
      document.addEventListener("nav", () => {
        gtag("event", "page_view", {
          page_title: document.title,
          page_location: location.href,
        });
      });`)
  } else if (cfg.analytics?.provider === "plausible") {
    const plausibleHost = cfg.analytics.host ?? "https://plausible.io"
    componentResources.afterDOMLoaded.push(`
      const plausibleScript = document.createElement("script")
      plausibleScript.src = "${plausibleHost}/js/script.manual.js"
      plausibleScript.setAttribute("data-domain", location.hostname)
      plausibleScript.defer = true
      document.head.appendChild(plausibleScript)
 
      window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }
 
      document.addEventListener("nav", () => {
        plausible("pageview")
      })
    `)
  } else if (cfg.analytics?.provider === "umami") {
    componentResources.afterDOMLoaded.push(`
      const umamiScript = document.createElement("script")
      umamiScript.src = "https://analytics.umami.is/script.js"
      umamiScript.setAttribute("data-website-id", "${cfg.analytics.websiteId}")
      umamiScript.async = true
 
      document.head.appendChild(umamiScript)
    `)
  } 

Вариант со старым счётчиком Яндекса, который должен сработать (не работает)

  else if (cfg.analytics?.provider === "yandex") {
    const ymId = cfg.analytics.ymId
    staticResources.js.push({
      src: `https://mc.yandex.ru/metrika/watch.js`,
      contentType: "external",
      loadTime: "afterDOMReady",
    })
    componentResources.afterDOMLoaded.push(`
      try {
    var yaCounter96251472 = new Ya.Metrika({
        id:${ymId},
        clickmap:true,
        trackLinks:true,
        accurateTrackBounce:true
    });
        } catch(e) { };
    `)
  }

Вариант через вставку в Head.tsx (не сработало)

Создаём константу:

const YaMetrics = `<!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date(); for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(96251472, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true }); </script> <noscript><div><img src="https://mc.yandex.ru/watch/96251472" style="position:absolute; left:-9999px;" alt="" /></div></noscript> <!-- /Yandex.Metrika counter -->`

Добавляем её в вывод в составе результата

export default (() => {
  function Head({ cfg, fileData, externalResources }: QuartzComponentProps) {
    const title = fileData.frontmatter?.title ?? "Untitled"
    const description = fileData.description?.trim() ?? "No description provided"
    const { css, js } = externalResources
 
    const url = new URL(`https://${cfg.baseUrl ?? "example.com"}`)
    const path = url.pathname as FullSlug
    const baseDir = fileData.slug === "404" ? path : pathToRoot(fileData.slug!)
 
    const iconPath = joinSegments(baseDir, "static/icon.png")
    const ogImagePath = `https://${cfg.baseUrl}/static/og-image.png`
 
    const YaMetrics = `<!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date(); for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(96251472, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true }); </script> <noscript><div><img src="https://mc.yandex.ru/watch/96251472" style="position:absolute; left:-9999px;" alt="" /></div></noscript> <!-- /Yandex.Metrika counter -->`
 
    return (
      <head>
        <title>{title}</title>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta property="og:title" content={title} />
        <meta property="og:description" content={description} />
        {cfg.baseUrl && <meta property="og:image" content={ogImagePath} />}
        <meta property="og:width" content="1200" />
        <meta property="og:height" content="675" />
        <link rel="icon" href={iconPath} />
        <meta name="description" content={description} />
        <meta name="generator" content="Quartz" />
        <link rel="preconnect" href="https://fonts.googleapis.com" />
        <link rel="preconnect" href="https://fonts.gstatic.com" />
        {css.map((href) => (
          <link key={href} href={href} rel="stylesheet" type="text/css" spa-preserve />
        ))}
        {js
          .filter((resource) => resource.loadTime === "beforeDOMReady")
          .map((res) => JSResourceToScriptElement(res, true))}
        {YaMetrics}
      </head>
    )
  }
 
  return Head
})

Альтернатива на umami:

provider: "umami", websiteId: "e080cafe-f61b-48c1-9cb2-0d744e043a53",