Adam 5 сар өмнө
parent
commit
daee7bd802

+ 62 - 0
package-lock.json

@@ -9,6 +9,7 @@
       "version": "0.0.0",
       "dependencies": {
         "@digitalocean/do-markdownit": "^1.16.1",
+        "chokidar": "^4.0.3",
         "dompurify": "^3.2.6",
         "markdown-it": "^14.1.0",
         "markdown-it-abbr": "^2.0.0",
@@ -18,6 +19,7 @@
         "markdown-it-footnote": "^4.0.0",
         "markdown-it-ins": "^4.0.0",
         "markdown-it-mark": "^4.0.0",
+        "markdown-it-spoiler": "^1.1.1",
         "markdown-it-sub": "^2.0.0",
         "markdown-it-sup": "^2.0.0",
         "marked": "^16.2.1",
@@ -1396,6 +1398,28 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@types/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
+      "license": "MIT"
+    },
+    "node_modules/@types/markdown-it": {
+      "version": "14.1.2",
+      "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
+      "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/linkify-it": "^5",
+        "@types/mdurl": "^2"
+      }
+    },
+    "node_modules/@types/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
+      "license": "MIT"
+    },
     "node_modules/@types/react": {
       "version": "19.1.12",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz",
@@ -1605,6 +1629,21 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
     },
+    "node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
     "node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2441,6 +2480,16 @@
       "integrity": "sha512-YLhzaOsU9THO/cal0lUjfMjrqSMPjjyjChYM7oyj4DnyaXEzA8gnW6cVJeyCrCVeyesrY2PlEdUYJSPFYL4Nkg==",
       "license": "MIT"
     },
+    "node_modules/markdown-it-spoiler": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/markdown-it-spoiler/-/markdown-it-spoiler-1.1.1.tgz",
+      "integrity": "sha512-4lGEJqgcc5aD2MVkOjQdWwPOn+QFfU5v0j2lRcOFjMiPxID/cQxdcpRHdZck5JF2+Ze8bDCcORkGO7o4KKZaGA==",
+      "deprecated": "transfer to @traptitech/markdown-it-spoiler",
+      "license": "MIT",
+      "dependencies": {
+        "@types/markdown-it": "*"
+      }
+    },
     "node_modules/markdown-it-sub": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-2.0.0.tgz",
@@ -2725,6 +2774,19 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/readdirp": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.18.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
     "node_modules/resolve-from": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",

+ 2 - 0
package.json

@@ -11,6 +11,7 @@
   },
   "dependencies": {
     "@digitalocean/do-markdownit": "^1.16.1",
+    "chokidar": "^4.0.3",
     "dompurify": "^3.2.6",
     "markdown-it": "^14.1.0",
     "markdown-it-abbr": "^2.0.0",
@@ -20,6 +21,7 @@
     "markdown-it-footnote": "^4.0.0",
     "markdown-it-ins": "^4.0.0",
     "markdown-it-mark": "^4.0.0",
+    "markdown-it-spoiler": "^1.1.1",
     "markdown-it-sub": "^2.0.0",
     "markdown-it-sup": "^2.0.0",
     "marked": "^16.2.1",

+ 10 - 3
public/posts/TEST.md

@@ -1,6 +1,6 @@
-title:Test
-desc:Test1
----
+title:Markdown Test Page
+desc:I'm testing my impl for md rendering.
+
 __Advertisement :)__
 
 - __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image
@@ -245,3 +245,10 @@ It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on.
 ::: info
 *here be dragons*
 :::
+
+Here’s a spoiler block:
+
+::: spoiler Click to reveal
+This text is hidden until you expand it.
+:::
+

+ 1 - 1
public/posts/index.json

@@ -1,4 +1,4 @@
 [
   "20250715.md",
   "TEST.md"
-]
+]

+ 14 - 1
src/App.jsx

@@ -10,6 +10,7 @@ import sub from "markdown-it-sub";
 import sup from "markdown-it-sup";
 import ins from "markdown-it-ins";
 import doMarkdownit from "@digitalocean/do-markdownit";
+import spoiler from "markdown-it-spoiler";
 import DOMPurify from 'dompurify';
 
 const scrollableTablesPlugin = (md) => {
@@ -30,7 +31,6 @@ const scrollableTablesPlugin = (md) => {
   };
 };
 
-// **FIX: Instantiate markdown-it outside the component.**
 const md = new MarkdownIt({
   html: true,
   linkify: true,
@@ -45,8 +45,21 @@ md.use(scrollableTablesPlugin)
   .use(mark)
   .use(deflist)
   .use(footnote)
+  .use(spoiler)
   //.use(doMarkdownit)
   .use(container, "info")
+  .use(container, "spoiler", {
+    render(tokens, idx) {
+      const token = tokens[idx];
+      if (token.nesting === 1) {
+        const m = token.info.trim().match(/^spoiler\s+(.*)$/);
+        const title = m ? m[1] : "Spoiler";
+        return `<details class="spoiler"><summary>${title}</summary>\n`;
+      } else {
+        return "</details>\n";
+      }
+    },
+  })
   .use(container, "warning");
 
 function App() {

+ 12 - 0
src/index.css

@@ -261,3 +261,15 @@ body {
   border-radius: 0.5rem;
   margin: 1rem 0;
 }
+
+.markdown-content details.spoiler {
+  @apply bg-gray-800/40 border border-gray-600 rounded-lg p-3 my-4;
+}
+
+.markdown-content details.spoiler summary {
+  @apply cursor-pointer font-semibold text-purple-400;
+}
+
+.markdown-content details.spoiler[open] {
+  @apply bg-gray-900/60;
+}

+ 37 - 1
vite.config.js

@@ -1,7 +1,43 @@
 import { defineConfig } from 'vite'
 import react from '@vitejs/plugin-react'
+import fs from "fs";
+import path from "path";
+import chokidar from "chokidar";
 
 // https://vite.dev/config/
+
+function generateIndex(postsDir, outputFile) {
+  const files = fs.readdirSync(postsDir)
+    .filter(f => f.endsWith(".md"));
+  fs.writeFileSync(outputFile, JSON.stringify(files, null, 2));
+  console.log(`Complete: index.json updated (${files.length} posts)`);
+}
+
+function generateIndexPlugin() {
+  const postsDir = path.resolve("public/posts");
+  const outputFile = path.resolve("public/posts/index.json"); 
+  return {
+    name: "generate-index-json",
+    buildStart() {
+      generateIndex(postsDir, outputFile);
+    },
+    configureServer(server) {
+      const watcher = chokidar.watch(postsDir, { ignoreInitial: true });
+      const update = () => {
+        generateIndex(postsDir, outputFile);
+        server.ws.send({
+          type: "full-reload",
+          path: "/posts/index.json"
+        });
+      };
+      watcher.on("add", update);
+      watcher.on("unlink", update);
+      watcher.on("change", update);
+      server.httpServer.on("close", () => watcher.close());
+    }
+  };
+}
+
 export default defineConfig({
-  plugins: [react()],
+  plugins: [react(),generateIndexPlugin()],
 })