Skip to content

Commit

Permalink
feat: pool page (#28)
Browse files Browse the repository at this point in the history
* refactor: move things around to start pool page

* feat: dark mode context and top grid row fit

* fix: header height

* feat: 9 ball rack

* fix: hash links

* feat: vite plugin for rendering markdown

* chore: remove custom css

* fix: router basename

* chore: some basic stylings

* chore: try fetching obsidian vault on build

* chore: try fetching obsidian vault on preview

* fix: not running deploy on branch

* fix: ci

* fix: ci

* fix: ci

* fix: ci

* fix: image base url

* chore: slight layout tweaks

* ci: tweak main deploy
  • Loading branch information
wodeni authored Dec 29, 2024
1 parent af323ca commit 2b75d60
Show file tree
Hide file tree
Showing 28 changed files with 2,844 additions and 396 deletions.
53 changes: 27 additions & 26 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
name: Deploy
on:
pull_request:
push:
branches:
- main
Expand All @@ -9,44 +8,46 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:

- name: Checkout
uses: actions/checkout@v3
- name: Build deps
run: yarn
- name: Build the website
run: yarn build
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
name: Deploy website
with:
submodules: true

- name: Checkout Obsidian Pool Notes
uses: actions/checkout@v4
with:
repository: wodeni/nimo-obsidian-notes-pool
token: ${{ secrets.GH_PAT_OBSIDIAN_POOL }}
path: ./pool-notes/

- name: Log directory structure
run: |
ls -al
ls -al pool-notes/
- name: Install and Build
run: |
yarn
yarn build -- --base /pr-preview/pr-${{ github.event.pull_request.number }}/
- name: Deploy website
uses: JamesIves/github-pages-deploy-action@4.1.4
with:
working-directory: main
branch: gh-pages
folder: dist
target-folder: .

- name: Add .nojekyll
run: |
mkdir extra/
touch extra/.nojekyll
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
name: Deploy .nojekyll
- name: Deploy .nojekyll
uses: JamesIves/github-pages-deploy-action@4.1.4
with:
branch: gh-pages
folder: dist
clean: false
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
name: Deploy to cmu server
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CMU_SSH_PRIVATE_KEY }}
ARGS: "-rlgoDzvc -i"
SOURCE: "dist/"
REMOTE_HOST: ${{ secrets.CMU_HOST }}
REMOTE_USER: ${{ secrets.CMU_USER }}
TARGET: ${{ secrets.CMU_TARGET }}
SCRIPT_BEFORE: |
whoami
ls -al
SCRIPT_AFTER: |
whoami
ls -al
echo $RSYNC_STDOUT
working-directory: main
14 changes: 14 additions & 0 deletions .github/workflows/preview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,24 @@ jobs:
permissions: write-all
runs-on: ubuntu-latest
steps:

- name: Checkout
uses: actions/checkout@v3
with:
submodules: true

- name: Checkout Obsidian Pool Notes
uses: actions/checkout@v4
with:
repository: wodeni/nimo-obsidian-notes-pool
token: ${{ secrets.GH_PAT_OBSIDIAN_POOL }}
path: ./pool-notes/

- name: Log directory structure
run: |
ls -al
ls -al pool-notes/
- name: Install and Build
run: |
yarn
Expand All @@ -29,3 +42,4 @@ jobs:
uses: rossjrw/pr-preview-action@v1
with:
source-dir: ./dist/

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ node_modules
dist
.DS_Store
publish-cmu.sh
pool-notes
public/pool-notes-images
26 changes: 24 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,40 @@
},
"license": "MIT",
"devDependencies": {
"@portaljs/remark-wiki-link": "^1.2.0",
"@types/node": "^22.10.2",
"@types/react": "^18.0.37",
"@types/react-dom": "^18.0.11",
"@types/react-router-hash-link": "^2.4.6",
"@types/three": "^0.152.1",
"@vitejs/plugin-react": "^4.0.0",
"autoprefixer": "^10.4.16",
"chalk": "^5.4.1",
"fast-glob": "^3.3.2",
"fs-extra": "^11.2.0",
"postcss": "^8.4.32",
"prettier": "^2.8.8",
"rehype-autolink-headings": "^7.1.0",
"rehype-infer-title-meta": "^2.0.0",
"rehype-raw": "^7.0.0",
"rehype-slug": "^6.0.0",
"rehype-stringify": "^10.0.1",
"remark": "^15.0.1",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0",
"remark-html": "^16.0.1",
"remark-parse": "^11.0.0",
"remark-parse-frontmatter": "^1.0.3",
"remark-rehype": "^11.1.1",
"remark-wiki-link": "^2.0.1",
"tailwindcss": "^3.4.0",
"typescript": "^4.9.5",
"vite": "^4.1.1",
"vite-plugin-virtual-plain-text": "^1.4.2"
"unified": "^11.0.5",
"unist-util-visit": "^5.0.0",
"vite": "^4.5.5",
"vite-plugin-markdown": "^2.2.0",
"vite-plugin-virtual-plain-text": "^1.4.5",
"vite-remark-html": "^1.1.1"
},
"dependencies": {
"@react-three/cannon": "^6.5.2",
Expand Down
178 changes: 178 additions & 0 deletions plugins/vite-remark.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// plugins/vite-plugin-remark-wikilinks.mjs
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkGfm from "remark-gfm";
import remarkWikiLink from "remark-wiki-link";
import remarkFrontmatter from "remark-frontmatter";
import remarkParseFrontmatter from "remark-parse-frontmatter";
import remarkRehype from "remark-rehype";
import rehypeSlug from "rehype-slug";
import rehypeRaw from "rehype-raw";
import rehypeStringify from "rehype-stringify";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeInferTitleMeta from "rehype-infer-title-meta";
import { visit } from "unist-util-visit";
import fs from "fs/promises";
import path from "path";
import chalk from "chalk";
import fastGlob from "fast-glob";

// Utility: Check if URL is external (http or //)
function isUrl(url) {
return /^https?:\/\//.test(url) || url.startsWith("//");
}

function normalizePath(str: string): string {
return str.replace(/\ /g, "-").toLowerCase();
}

export default function vitePluginRemarkMarkdown(
options: { imageDir?: string; publicDir?: string; mdGlob?: string } = {}
) {
const {
imageDir = "images",
publicDir = "public",
mdGlob = "**/*.md", // you can customize the glob
} = options;
let baseUrl = "/"; // fallback

// The absolute folder where we copy images
const absPublicImages = path.resolve(process.cwd(), publicDir, imageDir);

// This will hold all known .md “slugs” (so remarkWikiLink doesn’t mark them as new)
let knownPages = [];

return {
name: "vite-plugin-remark-markdown",
configResolved(config) {
// At this stage, you have the final resolved Vite config
baseUrl = config.base;
console.log("Resolved base:", baseUrl);
},

// 1) In buildStart (or configResolved), gather all .md files
async buildStart() {
// Use fastGlob to find all .md files
const allMdPaths = await fastGlob(mdGlob, {
cwd: process.cwd(), // or a subfolder if you want
absolute: false, // we just need relative
});

// Convert something like "docs/intro.md" -> "docs/intro"
knownPages = allMdPaths.map((file) => {
const base = path.basename(file, ".md");
return normalizePath(base);
});
},

async transform(code, id) {
// Only run on .md files
if (!id.endsWith(".md")) return null;

// Create the output folder for images if needed
await fs.mkdir(absPublicImages, { recursive: true }).catch(() => {});

const mdDir = path.dirname(id);

// 2) Build the unified pipeline
const processor = unified()
.use(remarkParse)
.use(remarkFrontmatter)
.use(remarkParseFrontmatter)

// Tell remarkWikiLink about your known pages
.use(remarkWikiLink, {
// If a user writes [[SomePage]], check if 'SomePage' is in knownPages
// If it is, remark-wiki-link won't mark it as new.
permalinks: knownPages,

// For the .md -> .html rewriting
pageResolver: (name) => {
// returns an array of possible matches
// e.g. if user wrote [[docs/intro]], we might have 'docs/intro' in knownPages
const normalizedName = normalizePath(name);
return [normalizedName];
},
// If the final link is "docs/intro", produce "docs/intro.html" in the href
hrefTemplate: (permalink) => `${permalink}`,
})
.use(remarkGfm)

// Rewrites .md links -> .html
.use(() => (tree) => {
visit(tree, "link", (node) => {
const u = node.url;
if (!isUrl(u) && u.endsWith(".md")) {
node.url = normalizePath(u).replace(/\.md$/, ".html");
}
});
})

.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeRaw)
.use(rehypeSlug)
// Copy local images -> public/images
.use(() => async (tree) => {
const promises = [];
visit(tree, ["image", "element"], (node) => {
const isImg =
(node.type === "element" && node.tagName === "img") ||
node.type === "image";

if (!isImg) return;

const src = node.properties?.src || node.url;
if (src && !isUrl(src)) {
const decodedUrl = decodeURI(src);
const publicPathRel = path.join(baseUrl, imageDir, decodedUrl);
const absPublicPath = path.join(absPublicImages, decodedUrl);
const originalFile = path.join(
mdDir.replace(/^file:\/\//, ""),
decodedUrl
);

promises.push(
fs
.mkdir(path.dirname(absPublicPath), { recursive: true })
.then(() => fs.copyFile(originalFile, absPublicPath))
.catch((err) => {
console.error(
chalk.red(
`[vite-plugin-remark-markdown] Error copying image from ${originalFile} to ${absPublicPath}: ${err.message}`
)
);
})
);
// Rewrite <img src> to a path from the final HTML
if (node.properties) {
node.properties.src = `${publicPathRel}`;
} else {
node.url = `/${publicPathRel}`;
}
}
});
await Promise.all(promises);
})
.use(rehypeAutolinkHeadings, { behavior: "append" })
.use(rehypeInferTitleMeta)
.use(rehypeStringify, { allowDangerousHtml: true });

// 3) Process the content
const file = await processor.process(code);
const frontmatter = file.data.frontmatter || {};
const html = String(file.value);

// Return a JSON object with frontmatter + html
const output = {
frontmatter,
html,
};

// Export as ESM
return {
code: `export default ${JSON.stringify(output)}`,
map: null,
};
},
};
}
Loading

0 comments on commit 2b75d60

Please sign in to comment.