From 5a49f3775024d2848fc0d4a48877a6b8e7abe02e Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Fri, 4 Jul 2025 12:24:55 +0200 Subject: [PATCH 1/5] vim moddddeee --- package-lock.json | 57 +++++++++++++++++++++ package.json | 4 ++ src/app/admin/page.tsx | 108 ++++++++++++++++++++++++++++++++-------- src/app/monaco-vim.d.ts | 1 + 4 files changed, 150 insertions(+), 20 deletions(-) create mode 100644 src/app/monaco-vim.d.ts diff --git a/package-lock.json b/package-lock.json index 44edc60..892ac05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "name": "markdownblog", "version": "0.1.0", "dependencies": { + "@fontsource/jetbrains-mono": "^5.2.6", + "@monaco-editor/react": "^4.7.0", "@tailwindcss/typography": "^0.5.16", "@types/node": "^20.11.24", "@types/react": "^18.2.61", @@ -25,6 +27,8 @@ "highlight.js": "^11.11.1", "jsdom": "^24.0.0", "marked": "^12.0.0", + "monaco-editor": "^0.52.2", + "monaco-vim": "^0.4.2", "next": "14.1.0", "pm2": "^6.0.8", "postcss": "^8.4.35", @@ -304,6 +308,15 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fontsource/jetbrains-mono": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-5.2.6.tgz", + "integrity": "sha512-nz//dBr99hXZmHp10wgNI00qThWImkzRR5PQjvRM+rpmuHO5rYBJCqPPWufidCvmkkryXx/GOP/lgqsM3R3Org==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -542,6 +555,29 @@ "node": ">=10" } }, + "node_modules/@monaco-editor/loader": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.5.0.tgz", + "integrity": "sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==", + "license": "MIT", + "dependencies": { + "state-local": "^1.0.6" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz", + "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==", + "license": "MIT", + "dependencies": { + "@monaco-editor/loader": "^1.5.0" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@next/env": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.0.tgz", @@ -5664,6 +5700,21 @@ "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", "license": "MIT" }, + "node_modules/monaco-editor": { + "version": "0.52.2", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz", + "integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==", + "license": "MIT" + }, + "node_modules/monaco-vim": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/monaco-vim/-/monaco-vim-0.4.2.tgz", + "integrity": "sha512-rdbQC3O2rmpwX2Orzig/6gZjZfH7q7TIeB+uEl49sa+QyNm3jCKJOw5mwxBdFzTqbrPD+URfg6A2lEkuL5kymw==", + "license": "MIT", + "peerDependencies": { + "monaco-editor": "*" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -7590,6 +7641,12 @@ "dev": true, "license": "MIT" }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", + "license": "MIT" + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", diff --git a/package.json b/package.json index 7893274..b324d03 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "electron-dev": "concurrently \"npm run dev\" \"npm run electron\"" }, "dependencies": { + "@fontsource/jetbrains-mono": "^5.2.6", + "@monaco-editor/react": "^4.7.0", "@tailwindcss/typography": "^0.5.16", "@types/node": "^20.11.24", "@types/react": "^18.2.61", @@ -28,6 +30,8 @@ "highlight.js": "^11.11.1", "jsdom": "^24.0.0", "marked": "^12.0.0", + "monaco-editor": "^0.52.2", + "monaco-vim": "^0.4.2", "next": "14.1.0", "pm2": "^6.0.8", "postcss": "^8.4.35", diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 56fcfdf..0a23a80 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -14,6 +14,15 @@ import hljs from 'highlight.js'; import matter from 'gray-matter'; import dynamic from 'next/dynamic'; import { Theme } from 'emoji-picker-react'; +import '../highlight-github.css'; +import MonacoEditor from '@monaco-editor/react'; +import { initVimMode, VimMode } from 'monaco-vim'; +import '@fontsource/jetbrains-mono'; + +// @ts-ignore-next-line +// eslint-disable-next-line +// If you want, you can move this to a global.d.ts file +// declare module 'monaco-vim'; interface Post { slug: string; @@ -48,6 +57,17 @@ type Node = Post | Folder; const EmojiPicker = dynamic(() => import('emoji-picker-react'), { ssr: false }); +// Patch marked renderer to always add 'hljs' class to code blocks +const renderer = new marked.Renderer(); +renderer.code = function(code, infostring, escaped) { + const lang = (infostring || '').match(/\S*/)?.[0]; + const highlighted = lang && hljs.getLanguage(lang) + ? hljs.highlight(code, { language: lang }).value + : hljs.highlightAuto(code).value; + const langClass = lang ? `language-${lang}` : ''; + return `
${highlighted}
`; +}; + export default function AdminPage() { const [isAuthenticated, setIsAuthenticated] = useState(false); const [username, setUsername] = useState(''); @@ -97,6 +117,10 @@ export default function AdminPage() { const router = useRouter(); const usernameRef = useRef(null); const passwordRef = useRef(null); + const monacoRef = useRef(null); + const vimStatusRef = useRef(null); + const vimInstanceRef = useRef(null); + const [vimMode, setVimMode] = useState(false); useEffect(() => { // Check if already authenticated @@ -129,13 +153,7 @@ export default function AdminPage() { marked.setOptions({ gfm: true, breaks: true, - highlight: function(code: string, lang: string) { - if (lang && hljs.getLanguage(lang)) { - return hljs.highlight(code, { language: lang }).value; - } else { - return hljs.highlightAuto(code).value; - } - } + renderer, } as any); setPreviewHtml(marked.parse(newPost.content || '') as string); }, [newPost.content]); @@ -752,6 +770,17 @@ export default function AdminPage() { return Theme.LIGHT; }; + // Attach/detach Vim mode when vimMode changes + useEffect(() => { + if (vimMode && monacoRef.current) { + // @ts-ignore + vimInstanceRef.current = initVimMode(monacoRef.current, vimStatusRef.current); + } else if (vimInstanceRef.current) { + vimInstanceRef.current.dispose(); + vimInstanceRef.current = null; + } + }, [vimMode, monacoRef.current]); + return (
{pinFeedback && ( @@ -990,8 +1019,6 @@ export default function AdminPage() { Current folder: {currentPath.join('/') || 'root'}
- - {/* Drag and Drop Zone */}
- {/* Mobile-friendly content editor */} +
+ setVimMode(v => !v)} + className="mr-2" + /> + +
+
- -