Đồng bộ thư mục Obsidian sang thư mục Publish nội dung lên Github Page

Tiêu đề hơi khó hiểu, đại loại có một câu chuyện như thế này.

Sau thời gian dài không viết thêm gì trên Obsidian, cũng như không đồng bộ nội dung mới từ Local lên web lên khi sử dụng Quartz, khi quay lại có một rắc rối nhỏ.

Khi thêm vài notes và đồng bộ lên github bằng lệnh npx quartz sync, git có trục trặc gì đó, và cũng như chưa nắm rõ về gitflow nên website sau khi đồng bộ bị mất toàn bộ notes cũ.

Cả ở trên web cũng như local.

Vì vậy nên tôi mới tìm cách để giải quyết vấn đề này.

Giải pháp là trong một dự án, ví dụ ở đây là “My” – tức là trang My Universe của tôi, sẽ tạo hai folder riêng.

Một folder A làm gốc chỉ để viết lách, chỉnh sửa bằng Obsidian, một folder B đồng bộ một chiều từ folder A sang, chỉ với mục đích lấy nội dung để chạy Quartz, và sau đó đồng bộ lên web.

Điều này tránh việc chồng chéo như trước, hai thư mục để chỉnh sửa và publish chung nhau dẫn đến việc lỗi này nọ dẫn đến việc mất hết dữ liệu.

Dưới đây là chi tiết.

Cài đặt folder

Mọi bước thực hiện như bài hướng dẫn này, tuy nhiên có khác một chút, tôi sẽ lấy trực tiếp link local của tôi làm ví dụ cho dễ hình dung.

Thư mục dự án D:\0-Drive\My, trong đó có hai folder là Obsidian (D:\0-Drive\My\Obsidian) và Publish (D:\0-Drive\My\Publish).

Sẽ cài Quartz vào Publish (D:\0-Drive\My\Publish). Đường dẫn sau khi cài sẽ là D:\0-Drive\My\Publish\quartz, và thư mục content để đồng bộ lên web là D:\0-Drive\My\Publish\quartz\content. Ta sẽ lấy địa chỉ đường dẫn cuối cùng này.

Hỏi Chat GPT như sau: “Tôi có hai folder trên window, gọi là A và B, tôi muốn thực hiện tất cả các chỉnh sửa ở folder A và định kỳ cập nhật sang B. Chỉ cập nhật một chiều A sang B, B bị xóa thì cập nhật lại từ A. Với A là D:\0-Drive\My\Obsidian và B là D:\0-Drive\My\Publish\quartz\content

Nó sẽ trả lời với việc sử dụng công cụ Robocopy được tích hợp sẵn trong Window.

Cụ thể, chạy câu lệnh sau với cmd robocopy "D:\0-Drive\My\Obsidian" "D:\0-Drive\My\Publish\quartz\content" /MIR /E /Z /R:2 /W:2 /LOG:D:\0-Drive\My\SyncLog.txt /PURGE

Giải thích:

  • Nguồn: "D:\0-Drive\My\Obsidian" là folder A.
  • Đích: "D:\0-Drive\My\Publish\quartz\content" là folder B.
  • Các tùy chọn:
    • /MIR: Đồng bộ một chiều, xóa file ở folder B nếu không tồn tại trong A.
    • /E: Bao gồm cả các thư mục rỗng.
    • /Z: Hỗ trợ tiếp tục nếu bị gián đoạn.
    • /R:2: Thử lại tối đa 2 lần nếu xảy ra lỗi.
    • /W:2: Chờ 2 giây trước mỗi lần thử lại.
    • /LOG:D:\0-Drive\My\SyncLog.txt: Ghi log kết quả vào file SyncLog.txt trong thư mục D:\0-Drive\My.
    • /PURGE: Xóa các file và thư mục trong thư mục đích không có trong thư mục nguồn.

Vậy là ok.

Để ngắn gọn hơn ta có thể tạo shortcut, câu lệnh trên sẽ tự chạy khi nhấn vào shortcut.

Chuột phải vào folder bất kỳ để bạn dễ nhớ > New > Shortcut.

Điền vào “Type the location of the item:cmd.exe /c robocopy "D:\folder-a" "D:\folder-b" /E /Z /R:2 /W:2 /LOG:"D:\folder-a\SyncLog.txt"

Thay địa chỉ đường dẫn A, B thành của bạn. /LOG:D:\folder-a\SyncLog.txt đoạn này là vị trí đặt file log, cũng sửa lại luôn cho dễ theo dõi. Ấn Next.

Chọn tên dễ nhớ và Finish. Từ bây giờ mỗi khi click đúp vào, nó sẽ tự động đồng bộ sang folder để publish.

Đoạn sau là cách thiết lập đồng bộ định kỳ hoặc tạo thủ công bằng shortcut hơi dài, tôi sẽ viết chi tiết sau. Đây là link chat GPT, xem tại đây.

Cài đặt Quartz

Về đây thì cài đặt như trong bài viết này, kết thúc luôn ở đây vì hơi bận bịu, có thời gian tôi sẽ cập nhật chi tiết hơn sau.

Ngoài ra, để tùy chỉnh giao diện sao cho đẹp hơn, gần giống với Obsidian Publish thì bạn có thể tham khảo cách tôi đã làm như tại on.io.vn

Chỉnh sửa file config, đường dẫn quartz/quartz.config.ts, thêm vào đoạn code sau:

import { QuartzConfig } from "./quartz/cfg"
import * as Plugin from "./quartz/plugins"

/**
 * Quartz 4.0 Configuration
 *
 * See https://quartz.jzhao.xyz/configuration for more information.
 */
const config: QuartzConfig = {
  configuration: {
    pageTitle: "On's Universe",
    pageTitleSuffix: "",
    enableSPA: true,
    enablePopovers: true,
    analytics: {
      provider: 'google', tagId: '<your-google-tag>',
    },
    locale: "en-US",
    baseUrl: "my.nguyenthanhtuyen.com",
    ignorePatterns: ["private", "templates", ".obsidian"],
    defaultDateType: "created",
    theme: {
      fontOrigin: "googleFonts",
      cdnCaching: true,
      typography: {
        header: "Roboto",
        body: "Roboto",
        code: "IBM Plex Mono",
      },
      colors: {
        lightMode: {
          light: "#faf8f8",
          lightgray: "#e5e5e5",
          gray: "#b8b8b8",
          darkgray: "#4e4e4e",
          dark: "#2b2b2b",
          secondary: "#284b63",
          tertiary: "#84a59d",
          highlight: "rgba(143, 159, 169, 0.15)",
          textHighlight: "#fff23688",
        },
        darkMode: {
          light: "#100e17",
          lightgray: "#191621",
          gray: "#646464",
          darkgray: "#bebebe",
          dark: "#f8fcff",
          secondary: "#dadada",
          tertiary: "#a882ff",
          highlight: "#6439c77a",
          textHighlight: "#b3aa0288",
        },
      },
    },
  },
  plugins: {
    transformers: [
      Plugin.FrontMatter(),
      Plugin.CreatedModifiedDate({
        priority: ["filesystem"],
      }),
      Plugin.SyntaxHighlighting({
        theme: {
          light: "github-light",
          dark: "github-dark",
        },
        keepBackground: false,
      }),
      Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }),
      Plugin.GitHubFlavoredMarkdown(),
      Plugin.TableOfContents(),
      Plugin.CrawlLinks({ 
        markdownLinkResolution: "shortest",
        openLinksInNewTab: true,
       }),
      Plugin.Description(),
      Plugin.Latex({ renderEngine: "katex" }),
    ],
    filters: [Plugin.RemoveDrafts()],
    emitters: [
      Plugin.AliasRedirects(),
      Plugin.ComponentResources(),
      Plugin.ContentPage(),
      Plugin.FolderPage(),
      Plugin.TagPage(),
      Plugin.ContentIndex({
        enableSiteMap: false,
        enableRSS: false,
      }),
      Plugin.Assets(),
      Plugin.Static(),
      Plugin.NotFoundPage(),
    ],
  },
}

export default config

Một số dòng tùy chỉnh như sau:

pageTitle: thay vào bằng tiêu đề website bạn
analytics: {
      provider: ‘google’, tagId: ‘<your-google-tag>’,
    },
thay <your-google-tag> bằng ID Analytics của bạn.

Chỉnh sửa file CSS, đường dẫn quartz/quartz/styles/custom.css, thêm vào đoạn code sau:

@use "./base.scss";

// put your custom CSS here!
//Bỏ margin top cả layout
.page>#quartz-body .sidebar
 {
    padding-top: 1rem;
}
.page>#quartz-body .page-header {
    margin: 0;
}

//Modify heading

article h2 {
    border-bottom: 1px solid #191621;
    padding-bottom: 0.3em;
}

//Màu ô tìm kiếm
.search-button p {
    color: #7aa2f7;
}
.search>.search-button svg .search-path {
    stroke: #7aa2f7;
}

//In nghiêng, đậm
strong,
footer a,
.breadcrumb-container a {
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    padding: 0;
    color: #7aa2f7;
    background-color: #7aa2f7;
    background-image: linear-gradient(62deg, #87c2fd 0%, #dcb9fc 100%) !important;
}
em {
    color: #bb9af7;
}

//Link
article a.internal,
article a.external {
    border-bottom: 1px solid #764cd5d1;
    background-color: transparent;
    border-radius: 0;
    color: #a68af9;
    font-weight: normal;
}
article a.internal:hover,
article a.external:hover {
    border-bottom: 1px solid #764cd5d1;
    background-color: transparent;
    border-radius: 0;
    color: #c5b6fc !important;
}

//Explorer styles
#explorer-content ul li>a,
.breadcrumb-container,
.folder-container div>button span,
#toc-content ul>li>a,
.backlinks>ul>li>a {
    font-weight: normal;
    font-size: 14px;
}
.folder-container div>button:hover {
    color: #a882ff;
}

//Meta
.content-meta {
    font-size: 14px;
}

.breadcrumb-container {
    margin: 1.5rem 0 0;
}

//li
li::marker {
    color: #666;
}
//blockquote
blockquote {
    border-left: 5px solid #764cd5d1;
    margin: 0 1em;
    background-color: #1c1536;
    padding: 5px 20px;
}

blockquote p {
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    color: #7aa2f7;
    margin: 0;
    font-style: italic;
    background-color: #7aa2f7;
    background-image: linear-gradient(62deg, #87c2fd 0%, #dcb9fc 100%) !important;
}

Tận hưởng thành quả thôi!

Viết một bình luận