335 lines
11 KiB
Nix
335 lines
11 KiB
Nix
{
|
|
description = "org-to-quartz: Convert org notes to Quartz-compatible markdown";
|
|
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
flake-utils.url = "github:numtide/flake-utils";
|
|
};
|
|
|
|
outputs = { self, nixpkgs, flake-utils }:
|
|
flake-utils.lib.eachDefaultSystem (system:
|
|
let
|
|
pkgs = nixpkgs.legacyPackages.${system};
|
|
|
|
python = pkgs.python311;
|
|
pythonPackages = python.pkgs;
|
|
|
|
org-to-quartz = pythonPackages.buildPythonApplication {
|
|
pname = "org-to-quartz";
|
|
version = "0.1.0";
|
|
format = "pyproject";
|
|
|
|
src = ./.;
|
|
|
|
nativeBuildInputs = [
|
|
pythonPackages.setuptools
|
|
pythonPackages.wheel
|
|
];
|
|
|
|
propagatedBuildInputs = [
|
|
pythonPackages.pybtex
|
|
pythonPackages.requests
|
|
pythonPackages.pyyaml
|
|
pkgs.pandoc
|
|
];
|
|
|
|
# Make pandoc available at runtime
|
|
makeWrapperArgs = [
|
|
"--prefix" "PATH" ":" "${pkgs.pandoc}/bin"
|
|
];
|
|
|
|
meta = {
|
|
description = "Convert org notes to Quartz-compatible markdown";
|
|
mainProgram = "org-to-quartz";
|
|
};
|
|
};
|
|
|
|
# Quartz package - builds the Quartz static site generator
|
|
quartz = pkgs.buildNpmPackage {
|
|
pname = "quartz";
|
|
version = "4.5.2";
|
|
|
|
src = pkgs.fetchFromGitHub {
|
|
owner = "jackyzha0";
|
|
repo = "quartz";
|
|
rev = "v4.5.2";
|
|
hash = "sha256-A6ePeNmcsbtKVnm7hVFOyjyc7gRYvXuG0XXQ6fvTLEw=";
|
|
};
|
|
|
|
npmDepsHash = "sha256-xxK9qy04m1olekOJIyYJHfdkYFzpjsgcfyFPuKsHpKE=";
|
|
|
|
# Quartz doesn't have a build step in the traditional sense
|
|
# It's a CLI tool that builds sites at runtime
|
|
dontNpmBuild = true;
|
|
|
|
# Install the quartz CLI
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mkdir -p $out/lib/quartz
|
|
cp -r . $out/lib/quartz
|
|
|
|
mkdir -p $out/bin
|
|
cat > $out/bin/quartz <<'WRAPPER'
|
|
#!/usr/bin/env bash
|
|
# Quartz CLI wrapper - runs quartz from its library directory
|
|
# or from current directory if it contains a quartz config
|
|
QUARTZ_LIB="$out/lib/quartz"
|
|
|
|
if [[ -f "./quartz.config.ts" ]]; then
|
|
# Run from current directory (user's project)
|
|
exec ${pkgs.nodejs}/bin/node "$QUARTZ_LIB/quartz/bootstrap-cli.mjs" "$@"
|
|
else
|
|
# Run from quartz lib directory
|
|
cd "$QUARTZ_LIB"
|
|
exec ${pkgs.nodejs}/bin/node quartz/bootstrap-cli.mjs "$@"
|
|
fi
|
|
WRAPPER
|
|
# Replace $out with actual path
|
|
substituteInPlace $out/bin/quartz --replace-quiet '$out' "$out"
|
|
chmod +x $out/bin/quartz
|
|
|
|
runHook postInstall
|
|
'';
|
|
|
|
meta = {
|
|
description = "A fast, batteries-included static-site generator for digital gardens";
|
|
homepage = "https://quartz.jzhao.xyz";
|
|
mainProgram = "quartz";
|
|
};
|
|
};
|
|
|
|
# Default quartz config that works in Nix sandbox (no network fetches)
|
|
defaultQuartzConfig = pkgs.writeText "quartz.config.ts" ''
|
|
import { QuartzConfig } from "./quartz/cfg"
|
|
import * as Plugin from "./quartz/plugins"
|
|
|
|
const config: QuartzConfig = {
|
|
configuration: {
|
|
pageTitle: "Quartz Notes",
|
|
pageTitleSuffix: "",
|
|
enableSPA: true,
|
|
enablePopovers: true,
|
|
analytics: null,
|
|
locale: "en-US",
|
|
baseUrl: "localhost",
|
|
ignorePatterns: ["private", "templates", ".obsidian"],
|
|
defaultDateType: "modified",
|
|
theme: {
|
|
fontOrigin: "local",
|
|
cdnCaching: false,
|
|
typography: {
|
|
header: "sans-serif",
|
|
body: "sans-serif",
|
|
code: "monospace",
|
|
},
|
|
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: "#161618",
|
|
lightgray: "#393639",
|
|
gray: "#646464",
|
|
darkgray: "#d4d4d4",
|
|
dark: "#ebebec",
|
|
secondary: "#7b97aa",
|
|
tertiary: "#84a59d",
|
|
highlight: "rgba(143, 159, 169, 0.15)",
|
|
textHighlight: "#b3aa0288",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
plugins: {
|
|
transformers: [
|
|
Plugin.FrontMatter(),
|
|
Plugin.CreatedModifiedDate({
|
|
priority: ["frontmatter", "git", "filesystem"],
|
|
}),
|
|
Plugin.SyntaxHighlighting({
|
|
theme: {
|
|
light: "github-light",
|
|
dark: "github-dark",
|
|
},
|
|
keepBackground: false,
|
|
}),
|
|
Plugin.OxHugoFlavouredMarkdown(),
|
|
Plugin.GitHubFlavoredMarkdown(),
|
|
Plugin.TableOfContents(),
|
|
Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }),
|
|
Plugin.Description(),
|
|
Plugin.Latex({ renderEngine: "katex" }),
|
|
],
|
|
filters: [Plugin.RemoveDrafts()],
|
|
emitters: [
|
|
Plugin.AliasRedirects(),
|
|
Plugin.ComponentResources(),
|
|
Plugin.ContentPage(),
|
|
Plugin.FolderPage(),
|
|
Plugin.TagPage(),
|
|
Plugin.ContentIndex({
|
|
enableSiteMap: true,
|
|
enableRSS: true,
|
|
}),
|
|
Plugin.Assets(),
|
|
Plugin.Static(),
|
|
Plugin.Favicon(),
|
|
Plugin.NotFoundPage(),
|
|
// CustomOgImages disabled - requires network access for fonts
|
|
],
|
|
},
|
|
}
|
|
|
|
export default config
|
|
'';
|
|
|
|
# Function to build Quartz pages from a content directory
|
|
# Usage: buildQuartzPages { contentDir = ./my-org-notes; }
|
|
# contentDir: directory containing org files or markdown files
|
|
# quartzConfig: optional path to quartz.config.ts (uses sandbox-friendly default if not provided)
|
|
# quartzLayout: optional path to quartz.layout.ts
|
|
buildQuartzPages = {
|
|
contentDir,
|
|
quartzConfig ? null,
|
|
quartzLayout ? null,
|
|
name ? "quartz-pages"
|
|
}:
|
|
pkgs.stdenv.mkDerivation {
|
|
inherit name;
|
|
|
|
# Don't use src, we copy everything in buildPhase
|
|
dontUnpack = true;
|
|
|
|
nativeBuildInputs = [
|
|
pkgs.nodejs
|
|
org-to-quartz
|
|
];
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
# Set up a writable quartz directory
|
|
cp -r ${quartz}/lib/quartz/* .
|
|
chmod -R u+w .
|
|
|
|
# Remove default content
|
|
rm -rf content
|
|
mkdir -p content
|
|
|
|
# Convert org files to markdown, or copy markdown directly
|
|
if ls ${contentDir}/*.org >/dev/null 2>&1; then
|
|
echo "Converting org notes from ${contentDir}..."
|
|
org-to-quartz ${contentDir} content
|
|
else
|
|
echo "Copying content from ${contentDir}..."
|
|
cp -r ${contentDir}/* content/
|
|
fi
|
|
|
|
# Apply quartz config (use sandbox-friendly default if not provided)
|
|
${if quartzConfig != null then ''
|
|
echo "Using custom quartz.config.ts..."
|
|
cp ${quartzConfig} quartz.config.ts
|
|
'' else ''
|
|
echo "Using default sandbox-friendly quartz.config.ts..."
|
|
cp ${defaultQuartzConfig} quartz.config.ts
|
|
''}
|
|
|
|
${pkgs.lib.optionalString (quartzLayout != null) ''
|
|
echo "Using custom quartz.layout.ts..."
|
|
cp ${quartzLayout} quartz.layout.ts
|
|
''}
|
|
|
|
# Build the static site
|
|
export HOME=$(mktemp -d)
|
|
echo "Building Quartz site..."
|
|
node quartz/bootstrap-cli.mjs build
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mv public $out
|
|
|
|
runHook postInstall
|
|
'';
|
|
};
|
|
|
|
# Script to serve quartz with converted notes (for development)
|
|
quartz-serve = pkgs.writeShellScriptBin "quartz-serve" ''
|
|
set -e
|
|
NOTES_DIR="''${1:-.}"
|
|
PORT="''${2:-8080}"
|
|
WORK_DIR=$(mktemp -d)
|
|
|
|
echo "Setting up Quartz..."
|
|
cp -r ${quartz}/lib/quartz/* "$WORK_DIR/"
|
|
chmod -R u+w "$WORK_DIR"
|
|
|
|
echo "Converting org notes from $NOTES_DIR..."
|
|
rm -rf "$WORK_DIR/content"
|
|
mkdir -p "$WORK_DIR/content"
|
|
${org-to-quartz}/bin/org-to-quartz "$NOTES_DIR" "$WORK_DIR/content" -v
|
|
|
|
cd "$WORK_DIR"
|
|
|
|
echo ""
|
|
echo "Starting Quartz on http://localhost:$PORT"
|
|
${pkgs.nodejs}/bin/node quartz/bootstrap-cli.mjs build --serve --port "$PORT"
|
|
'';
|
|
|
|
# Example: build pages from example-notes directory
|
|
example-pages = buildQuartzPages {
|
|
contentDir = ./example-notes;
|
|
name = "example-quartz-pages";
|
|
};
|
|
|
|
in {
|
|
packages = {
|
|
default = org-to-quartz;
|
|
org-to-quartz = org-to-quartz;
|
|
quartz = quartz;
|
|
example-pages = example-pages;
|
|
};
|
|
|
|
# Export the buildQuartzPages function for use in other flakes
|
|
lib = {
|
|
inherit buildQuartzPages;
|
|
};
|
|
|
|
devShells.default = pkgs.mkShell {
|
|
buildInputs = [
|
|
python
|
|
pythonPackages.pybtex
|
|
pythonPackages.requests
|
|
pythonPackages.pyyaml
|
|
pythonPackages.pytest
|
|
pkgs.pandoc
|
|
pkgs.nodejs
|
|
];
|
|
};
|
|
|
|
apps = {
|
|
default = {
|
|
type = "app";
|
|
program = "${org-to-quartz}/bin/org-to-quartz";
|
|
};
|
|
serve = {
|
|
type = "app";
|
|
program = "${quartz-serve}/bin/quartz-serve";
|
|
};
|
|
};
|
|
}
|
|
);
|
|
}
|