├── .nvmrc ├── public ├── upload │ └── .gitkeep ├── diagram.png ├── favicon.ico ├── mpmd │ ├── icon-256.png │ └── logo.svg └── assets │ ├── icons │ ├── macos.png │ ├── ubuntu.png │ ├── windows.png │ └── github.svg │ └── images │ ├── logo.png │ ├── logo-2.png │ ├── loading.jpg │ ├── Snipaste_2025-03-07_14-10-08.png │ ├── Snipaste_2025-03-07_14-11-26.png │ ├── Snipaste_2025-03-07_14-12-20.png │ ├── Snipaste_2025-03-07_14-12-58.png │ └── Snipaste_2025-03-07_14-16-31.png ├── src ├── utils │ ├── toast │ │ └── index.ts │ ├── MDKatex.d.ts │ ├── fetch.ts │ ├── tauri-fs.ts │ └── MDKatex.js ├── vite-env.d.ts ├── components │ ├── ui │ │ ├── input │ │ │ ├── index.ts │ │ │ └── Input.vue │ │ ├── label │ │ │ ├── index.ts │ │ │ └── Label.vue │ │ ├── sonner │ │ │ ├── index.ts │ │ │ └── Sonner.vue │ │ ├── switch │ │ │ ├── index.ts │ │ │ └── Switch.vue │ │ ├── back-top │ │ │ ├── index.ts │ │ │ └── BackTop.vue │ │ ├── textarea │ │ │ ├── index.ts │ │ │ └── Textarea.vue │ │ ├── separator │ │ │ ├── index.ts │ │ │ └── Separator.vue │ │ ├── popover │ │ │ ├── index.ts │ │ │ ├── PopoverTrigger.vue │ │ │ ├── Popover.vue │ │ │ └── PopoverContent.vue │ │ ├── hover-card │ │ │ ├── index.ts │ │ │ ├── HoverCardTrigger.vue │ │ │ ├── HoverCard.vue │ │ │ └── HoverCardContent.vue │ │ ├── tabs │ │ │ ├── index.ts │ │ │ ├── Tabs.vue │ │ │ ├── TabsList.vue │ │ │ ├── TabsContent.vue │ │ │ └── TabsTrigger.vue │ │ ├── tooltip │ │ │ ├── index.ts │ │ │ ├── TooltipTrigger.vue │ │ │ ├── TooltipProvider.vue │ │ │ ├── Tooltip.vue │ │ │ └── TooltipContent.vue │ │ ├── dialog │ │ │ ├── DialogClose.vue │ │ │ ├── DialogTrigger.vue │ │ │ ├── DialogHeader.vue │ │ │ ├── Dialog.vue │ │ │ ├── DialogFooter.vue │ │ │ ├── index.ts │ │ │ ├── DialogDescription.vue │ │ │ ├── DialogTitle.vue │ │ │ ├── DialogScrollContent.vue │ │ │ └── DialogContent.vue │ │ ├── menubar │ │ │ ├── MenubarMenu.vue │ │ │ ├── MenubarGroup.vue │ │ │ ├── MenubarShortcut.vue │ │ │ ├── MenubarLabel.vue │ │ │ ├── MenubarSub.vue │ │ │ ├── MenubarRadioGroup.vue │ │ │ ├── MenubarSeparator.vue │ │ │ ├── Menubar.vue │ │ │ ├── MenubarTrigger.vue │ │ │ ├── index.ts │ │ │ ├── MenubarItem.vue │ │ │ ├── MenubarSubTrigger.vue │ │ │ ├── MenubarRadioItem.vue │ │ │ ├── MenubarCheckboxItem.vue │ │ │ ├── MenubarContent.vue │ │ │ └── MenubarSubContent.vue │ │ ├── select │ │ │ ├── SelectValue.vue │ │ │ ├── SelectItemText.vue │ │ │ ├── SelectLabel.vue │ │ │ ├── Select.vue │ │ │ ├── SelectSeparator.vue │ │ │ ├── SelectGroup.vue │ │ │ ├── index.ts │ │ │ ├── SelectScrollUpButton.vue │ │ │ ├── SelectScrollDownButton.vue │ │ │ ├── SelectTrigger.vue │ │ │ ├── SelectItem.vue │ │ │ └── SelectContent.vue │ │ ├── context-menu │ │ │ ├── ContextMenuGroup.vue │ │ │ ├── ContextMenuPortal.vue │ │ │ ├── ContextMenuShortcut.vue │ │ │ ├── ContextMenuTrigger.vue │ │ │ ├── ContextMenu.vue │ │ │ ├── ContextMenuSub.vue │ │ │ ├── ContextMenuRadioGroup.vue │ │ │ ├── ContextMenuSeparator.vue │ │ │ ├── ContextMenuLabel.vue │ │ │ ├── index.ts │ │ │ ├── ContextMenuItem.vue │ │ │ ├── ContextMenuSubTrigger.vue │ │ │ ├── ContextMenuSubContent.vue │ │ │ ├── ContextMenuRadioItem.vue │ │ │ ├── ContextMenuCheckboxItem.vue │ │ │ └── ContextMenuContent.vue │ │ ├── dropdown-menu │ │ │ ├── DropdownMenuGroup.vue │ │ │ ├── DropdownMenuShortcut.vue │ │ │ ├── DropdownMenuTrigger.vue │ │ │ ├── DropdownMenu.vue │ │ │ ├── DropdownMenuSub.vue │ │ │ ├── DropdownMenuRadioGroup.vue │ │ │ ├── DropdownMenuSeparator.vue │ │ │ ├── DropdownMenuLabel.vue │ │ │ ├── DropdownMenuItem.vue │ │ │ ├── DropdownMenuSubTrigger.vue │ │ │ ├── index.ts │ │ │ ├── DropdownMenuSubContent.vue │ │ │ ├── DropdownMenuRadioItem.vue │ │ │ ├── DropdownMenuCheckboxItem.vue │ │ │ └── DropdownMenuContent.vue │ │ ├── alert-dialog │ │ │ ├── AlertDialogTrigger.vue │ │ │ ├── AlertDialogHeader.vue │ │ │ ├── AlertDialog.vue │ │ │ ├── AlertDialogFooter.vue │ │ │ ├── AlertDialogTitle.vue │ │ │ ├── index.ts │ │ │ ├── AlertDialogAction.vue │ │ │ ├── AlertDialogDescription.vue │ │ │ ├── AlertDialogCancel.vue │ │ │ └── AlertDialogContent.vue │ │ ├── alert │ │ │ ├── AlertDescription.vue │ │ │ ├── AlertTitle.vue │ │ │ ├── Alert.vue │ │ │ └── index.ts │ │ ├── number-field │ │ │ ├── index.ts │ │ │ ├── NumberFieldContent.vue │ │ │ ├── NumberFieldInput.vue │ │ │ ├── NumberField.vue │ │ │ ├── NumberFieldDecrement.vue │ │ │ └── NumberFieldIncrement.vue │ │ └── button │ │ │ ├── Button.vue │ │ │ └── index.ts │ ├── CodemirrorEditor │ │ ├── EditorHeader │ │ │ ├── EditDropdown.vue │ │ │ ├── HelpDropdown.vue │ │ │ ├── FileDropdown.vue │ │ │ ├── ContactInfo.vue │ │ │ ├── StyleOptionMenu.vue │ │ │ ├── AboutDialog.vue │ │ │ ├── PostTaskDialog.vue │ │ │ └── StyleDropdown.vue │ │ └── InsertFormDialog.vue │ ├── FormItem.vue │ ├── PreviewModeSwitch.vue │ ├── RunLoading.vue │ ├── CustomUploadForm.vue │ └── Preview.vue ├── assets │ ├── images │ │ └── favicon.png │ ├── less │ │ ├── app.less │ │ └── theme.less │ ├── index.css │ └── example │ │ ├── theme-css.txt │ │ └── markdown.md ├── lib │ └── utils.ts ├── entrypoints │ ├── popup │ │ ├── popup.ts │ │ ├── index.html │ │ └── App.vue │ └── background.ts ├── config │ ├── index.ts │ └── api.ts ├── types │ ├── preview.ts │ └── index.ts ├── main.ts └── App.vue ├── src-tauri ├── build.rs ├── icons │ ├── icon.ico │ ├── icon.png │ ├── 32x32.png │ ├── icon.icns │ ├── 128x128.png │ └── 128x128@2x.png ├── .gitignore ├── src │ ├── lib.rs │ └── main.rs ├── capabilities │ └── default.json ├── Cargo.toml ├── build-aux │ ├── bundle_dmg.sh │ └── convert_icon.cjs └── tauri.conf.json ├── .vscode ├── extensions.json └── settings.json ├── postcss.config.js ├── uno.config.ts ├── example ├── README.md └── worker.js ├── tsconfig.json ├── .editorconfig ├── tsconfig.node.json ├── components.json ├── eslint.config.mjs ├── .github ├── workflows │ └── code-review.yml └── actions │ ├── load-os-config │ └── action.yml │ ├── create-release │ └── action.yml │ └── process-artifacts │ └── action.yml ├── .gitignore ├── tsconfig.app.json ├── wxt.config.ts ├── LICENSE ├── docs └── changelog.md ├── vite.config.ts ├── README.md ├── index.html ├── tailwind.config.cjs ├── README_en.md └── package.json /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 2 | -------------------------------------------------------------------------------- /public/upload/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/toast/index.ts: -------------------------------------------------------------------------------- 1 | export { toast } from 'vue-sonner' 2 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /src/components/ui/input/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Input } from './Input.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/label/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Label } from './Label.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/sonner/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Toaster } from './Sonner.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/switch/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Switch } from './Switch.vue' 2 | -------------------------------------------------------------------------------- /public/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/diagram.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/components/ui/back-top/index.ts: -------------------------------------------------------------------------------- 1 | export { default as BackTop } from './BackTop.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/textarea/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Textarea } from './Textarea.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/separator/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Separator } from './Separator.vue' 2 | -------------------------------------------------------------------------------- /public/mpmd/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/mpmd/icon-256.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /public/assets/icons/macos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/icons/macos.png -------------------------------------------------------------------------------- /public/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/images/logo.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /src/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/src/assets/images/favicon.png -------------------------------------------------------------------------------- /public/assets/icons/ubuntu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/icons/ubuntu.png -------------------------------------------------------------------------------- /public/assets/icons/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/icons/windows.png -------------------------------------------------------------------------------- /public/assets/images/logo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/images/logo-2.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/assets/images/loading.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/images/loading.jpg -------------------------------------------------------------------------------- /src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | /gen/schemas 5 | -------------------------------------------------------------------------------- /public/assets/images/Snipaste_2025-03-07_14-10-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/images/Snipaste_2025-03-07_14-10-08.png -------------------------------------------------------------------------------- /public/assets/images/Snipaste_2025-03-07_14-11-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/images/Snipaste_2025-03-07_14-11-26.png -------------------------------------------------------------------------------- /public/assets/images/Snipaste_2025-03-07_14-12-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/images/Snipaste_2025-03-07_14-12-20.png -------------------------------------------------------------------------------- /public/assets/images/Snipaste_2025-03-07_14-12-58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/images/Snipaste_2025-03-07_14-12-58.png -------------------------------------------------------------------------------- /public/assets/images/Snipaste_2025-03-07_14-16-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyMrYan/md-tauri/HEAD/public/assets/images/Snipaste_2025-03-07_14-16-31.png -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /uno.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, presetMini } from 'unocss' 2 | 3 | export default defineConfig({ 4 | presets: [ 5 | presetMini({ 6 | preflight: false, 7 | }), 8 | ], 9 | }) 10 | -------------------------------------------------------------------------------- /src-tauri/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg_attr(mobile, tauri::mobile_entry_point)] 2 | pub fn run() { 3 | tauri::Builder::default() 4 | .run(tauri::generate_context!()) 5 | .expect("error while running tauri application"); 6 | } 7 | -------------------------------------------------------------------------------- /src/components/ui/popover/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Popover } from './Popover.vue' 2 | export { default as PopoverContent } from './PopoverContent.vue' 3 | export { default as PopoverTrigger } from './PopoverTrigger.vue' 4 | -------------------------------------------------------------------------------- /src/utils/MDKatex.d.ts: -------------------------------------------------------------------------------- 1 | import type { MarkedExtension } from 'marked' 2 | 3 | export interface MarkedKatexOptions { 4 | nonStandard?: boolean 5 | } 6 | 7 | export function MDKatex(options?: MarkedKatexOptions): MarkedExtension 8 | -------------------------------------------------------------------------------- /src/components/ui/hover-card/index.ts: -------------------------------------------------------------------------------- 1 | export { default as HoverCard } from './HoverCard.vue' 2 | export { default as HoverCardContent } from './HoverCardContent.vue' 3 | export { default as HoverCardTrigger } from './HoverCardTrigger.vue' 4 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | ## worker.js 4 | 5 | 公众号openapi接口代理服务示例,该项目将请求转发至微信公众号api。 6 | 7 | 开发调试: 8 | 9 | ``` 10 | cd example 11 | npx wrangler dev worker.js 12 | ``` 13 | 14 | 部署: 15 | 16 | 请将其部署到cloudflare workers。 17 | -------------------------------------------------------------------------------- /src/components/ui/tabs/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tabs } from './Tabs.vue' 2 | export { default as TabsContent } from './TabsContent.vue' 3 | export { default as TabsList } from './TabsList.vue' 4 | export { default as TabsTrigger } from './TabsTrigger.vue' 5 | -------------------------------------------------------------------------------- /src/entrypoints/popup/popup.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | import 'virtual:uno.css' 5 | 6 | /* 每个页面公共css */ 7 | import '@/assets/index.css' 8 | import '@/assets/less/theme.less' 9 | 10 | createApp(App).mount(`#app`) 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { 4 | "path": "./tsconfig.app.json" 5 | }, 6 | { 7 | "path": "./tsconfig.node.json" 8 | } 9 | ], 10 | "files": [], 11 | "compilerOptions": { 12 | "types": ["node", "@tauri-apps/api"] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src-tauri/capabilities/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../gen/schemas/desktop-schema.json", 3 | "identifier": "default", 4 | "description": "enables the default permissions", 5 | "windows": [ 6 | "main" 7 | ], 8 | "permissions": [ 9 | "core:default" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/components/ui/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tooltip } from './Tooltip.vue' 2 | export { default as TooltipContent } from './TooltipContent.vue' 3 | export { default as TooltipProvider } from './TooltipProvider.vue' 4 | export { default as TooltipTrigger } from './TooltipTrigger.vue' 5 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogClose.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/menubar/MenubarMenu.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/select/SelectValue.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/menubar/MenubarGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | tauri::Builder::default() 6 | .run(tauri::generate_context!()) 7 | .expect("error while running tauri application"); 8 | } 9 | -------------------------------------------------------------------------------- /src/components/ui/popover/PopoverTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/select/SelectItemText.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/tooltip/TooltipTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/tooltip/TooltipProvider.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenuGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/hover-card/HoverCardTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenuPortal.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu/DropdownMenuGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | max_line_length = 80 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | 17 | [COMMIT_EDITMSG] 18 | max_line_length = 0 19 | -------------------------------------------------------------------------------- /src/components/ui/alert/AlertDescription.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/alert/AlertTitle.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "strict": true, 8 | "noEmit": true, 9 | "allowSyntheticDefaultImports": true, 10 | "skipLibCheck": true 11 | }, 12 | "include": ["vite.config.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /src/components/ui/number-field/index.ts: -------------------------------------------------------------------------------- 1 | export { default as NumberField } from './NumberField.vue' 2 | export { default as NumberFieldContent } from './NumberFieldContent.vue' 3 | export { default as NumberFieldDecrement } from './NumberFieldDecrement.vue' 4 | export { default as NumberFieldIncrement } from './NumberFieldIncrement.vue' 5 | export { default as NumberFieldInput } from './NumberFieldInput.vue' 6 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu/DropdownMenuShortcut.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/menubar/MenubarShortcut.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogHeader.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenuShortcut.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogHeader.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /src/entrypoints/popup/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 公众号内容编辑器 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenuTrigger.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /src/components/ui/dialog/Dialog.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://shadcn-vue.com/schema.json", 3 | "style": "default", 4 | "typescript": true, 5 | "tsConfigPath": "./tsconfig.json", 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/assets/index.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "framework": "vite", 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import antfu from '@antfu/eslint-config' 2 | 3 | export default antfu({ 4 | vue: true, 5 | unocss: true, 6 | typescript: true, 7 | formatters: true, 8 | ignores: [`.github`, `scripts`, `docker`, `src/assets`, `example`], 9 | }, { 10 | rules: { 11 | 'semi': [`error`, `never`], 12 | 'quotes': [`error`, `backtick`], 13 | 'no-unused-vars': `off`, 14 | 'no-console': `off`, 15 | 'no-debugger': `off`, 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu/DropdownMenuTrigger.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /src/components/ui/tabs/Tabs.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/ui/tooltip/Tooltip.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './api' 2 | export * from './style' 3 | export * from './theme' 4 | 5 | export const prefix = `MD` 6 | 7 | const isMac = /Mac/i.test(navigator.userAgent) 8 | 9 | export const ctrlKey = isMac ? `Cmd` : `Ctrl` 10 | export const altKey = `Alt` 11 | export const shiftKey = `Shift` 12 | 13 | export const ctrlSign = isMac ? `⌘` : `Ctrl` 14 | export const altSign = isMac ? `⌥` : `Alt` 15 | export const shiftSign = isMac ? `⇧` : `Shift` 16 | -------------------------------------------------------------------------------- /src/components/ui/alert/Alert.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogFooter.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | -------------------------------------------------------------------------------- /src/components/ui/number-field/NumberFieldContent.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/select/SelectLabel.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialog.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/hover-card/HoverCard.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/select/Select.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/ui/popover/Popover.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/types/preview.ts: -------------------------------------------------------------------------------- 1 | export enum PreviewMode { 2 | Adaptive = 'adaptive', // 自适应宽度 3 | Mobile = 'mobile', // 手机预览 4 | FullScreen = 'full' // 全屏预览 5 | } 6 | 7 | export interface PreviewConfig { 8 | mode: PreviewMode; 9 | mobileWidth: number; // 手机预览宽度 10 | adaptiveWidth: number; // 自适应预览最大宽度 11 | } 12 | 13 | export const DEFAULT_PREVIEW_CONFIG: PreviewConfig = { 14 | mode: PreviewMode.Adaptive, 15 | mobileWidth: 375, // iPhone 标准宽度 16 | adaptiveWidth: 800 // 默认最大宽度 17 | }; -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogFooter.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu/DropdownMenu.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/menubar/MenubarLabel.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenu.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenuSub.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu/DropdownMenuSub.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/components/ui/menubar/MenubarSub.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/components/ui/menubar/MenubarRadioGroup.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenuRadioGroup.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/components/ui/dialog/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Dialog } from './Dialog.vue' 2 | export { default as DialogClose } from './DialogClose.vue' 3 | export { default as DialogContent } from './DialogContent.vue' 4 | export { default as DialogDescription } from './DialogDescription.vue' 5 | export { default as DialogFooter } from './DialogFooter.vue' 6 | export { default as DialogHeader } from './DialogHeader.vue' 7 | export { default as DialogScrollContent } from './DialogScrollContent.vue' 8 | export { default as DialogTitle } from './DialogTitle.vue' 9 | export { default as DialogTrigger } from './DialogTrigger.vue' 10 | -------------------------------------------------------------------------------- /src/components/ui/select/SelectSeparator.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /src/components/ui/select/SelectGroup.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/entrypoints/background.ts: -------------------------------------------------------------------------------- 1 | import { browser } from 'wxt/browser' 2 | import { defineBackground } from 'wxt/sandbox' 3 | 4 | export default defineBackground({ 5 | type: `module`, 6 | main() { 7 | browser.runtime.onInstalled.addListener((detail) => { 8 | if (import.meta.env.COMMAND === `serve`) { 9 | browser.runtime.openOptionsPage() 10 | return 11 | } 12 | if (detail.reason === `install`) { 13 | browser.tabs.create({ url: `https://mpmd.pages.dev/welcome` }) 14 | } 15 | else if (detail.reason === `update`) { 16 | browser.runtime.openOptionsPage() 17 | } 18 | }) 19 | }, 20 | }) 21 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenuSeparator.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu/DropdownMenuSeparator.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogTitle.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 23 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/index.ts: -------------------------------------------------------------------------------- 1 | export { default as AlertDialog } from './AlertDialog.vue' 2 | export { default as AlertDialogAction } from './AlertDialogAction.vue' 3 | export { default as AlertDialogCancel } from './AlertDialogCancel.vue' 4 | export { default as AlertDialogContent } from './AlertDialogContent.vue' 5 | export { default as AlertDialogDescription } from './AlertDialogDescription.vue' 6 | export { default as AlertDialogFooter } from './AlertDialogFooter.vue' 7 | export { default as AlertDialogHeader } from './AlertDialogHeader.vue' 8 | export { default as AlertDialogTitle } from './AlertDialogTitle.vue' 9 | export { default as AlertDialogTrigger } from './AlertDialogTrigger.vue' 10 | -------------------------------------------------------------------------------- /src/components/ui/menubar/MenubarSeparator.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogAction.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /src/components/ui/number-field/NumberFieldInput.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /src/components/ui/tabs/TabsList.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | -------------------------------------------------------------------------------- /src/utils/fetch.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | // 创建axios实例 4 | const service = axios.create({ 5 | baseURL: ``, 6 | timeout: 30 * 1000, // 请求超时时间 7 | }) 8 | 9 | service.interceptors.request.use( 10 | (config) => { 11 | if (/^(?:post|put|delete)$/i.test(`${config.method}`)) { 12 | if (config.data && config.data.upload) { 13 | config.headers[`Content-Type`] = `multipart/form-data` 14 | } 15 | } 16 | return config 17 | }, 18 | (error) => { 19 | Promise.reject(error) 20 | }, 21 | ) 22 | 23 | service.interceptors.response.use( 24 | (res) => { 25 | return res.data ? res.data : Promise.reject(res) 26 | }, 27 | error => Promise.reject(error), 28 | ) 29 | 30 | export default service 31 | -------------------------------------------------------------------------------- /src/components/ui/label/Label.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 28 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogDescription.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /src/components/ui/button/Button.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 27 | -------------------------------------------------------------------------------- /src/components/ui/select/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Select } from './Select.vue' 2 | export { default as SelectContent } from './SelectContent.vue' 3 | export { default as SelectGroup } from './SelectGroup.vue' 4 | export { default as SelectItem } from './SelectItem.vue' 5 | export { default as SelectItemText } from './SelectItemText.vue' 6 | export { default as SelectLabel } from './SelectLabel.vue' 7 | export { default as SelectScrollDownButton } from './SelectScrollDownButton.vue' 8 | export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue' 9 | export { default as SelectSeparator } from './SelectSeparator.vue' 10 | export { default as SelectTrigger } from './SelectTrigger.vue' 11 | export { default as SelectValue } from './SelectValue.vue' 12 | -------------------------------------------------------------------------------- /src/components/ui/tabs/TabsContent.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 23 | -------------------------------------------------------------------------------- /.github/workflows/code-review.yml: -------------------------------------------------------------------------------- 1 | name: Code Review 2 | on: 3 | pull_request_target: 4 | types: 5 | - opened # Triggers when a PR is opened 6 | - reopened # Triggers when a PR is reopened 7 | - synchronize # Triggers when a commit is pushed to the PR 8 | 9 | # fix: GraphQL: Resource not accessible by integration (addComment) error 10 | permissions: 11 | pull-requests: write 12 | 13 | jobs: 14 | setup-deepseek-review: 15 | runs-on: ubuntu-latest 16 | name: Code Review 17 | steps: 18 | - name: DeepSeek Code Review 19 | uses: hustcer/deepseek-review@v1 20 | with: 21 | chat-token: ${{ secrets.CHAT_TOKEN }} 22 | base-url: ${{ secrets.BASE_URL }} 23 | model: ${{ secrets.CHAT_MODEL }} 24 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogDescription.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | -------------------------------------------------------------------------------- /src/components/ui/context-menu/ContextMenuLabel.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | -------------------------------------------------------------------------------- /src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "md-tauri" 3 | version = "1.1.0" 4 | description = "Markdown Editor" 5 | authors = ["you"] 6 | license = "" 7 | repository = "" 8 | edition = "2021" 9 | rust-version = "1.77.2" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [lib] 14 | name = "app_lib" 15 | crate-type = ["staticlib", "cdylib", "rlib"] 16 | 17 | [build-dependencies] 18 | tauri-build = { version = "1.5.1", features = [] } 19 | 20 | [dependencies] 21 | serde_json = "1.0" 22 | serde = { version = "1.0", features = ["derive"] } 23 | log = "0.4" 24 | tauri = { version = "1.5.4", features = [ "shell-open", "dialog-all", "fs-all"] } 25 | 26 | [features] 27 | default = ["custom-protocol"] 28 | custom-protocol = ["tauri/custom-protocol"] 29 | -------------------------------------------------------------------------------- /src/components/ui/sonner/Sonner.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | -------------------------------------------------------------------------------- /src/components/CodemirrorEditor/EditorHeader/EditDropdown.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 25 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu/DropdownMenuLabel.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogTitle.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 30 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogCancel.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 28 | -------------------------------------------------------------------------------- /src/components/ui/number-field/NumberField.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia' 2 | import { createApp } from 'vue' 3 | import App from './App.vue' 4 | 5 | import 'virtual:uno.css' 6 | import 'codemirror/lib/codemirror.css' 7 | import 'codemirror/theme/xq-light.css' 8 | import 'codemirror/theme/darcula.css' 9 | 10 | /* 每个页面公共css */ 11 | import '@/assets/index.css' 12 | import '@/assets/less/theme.less' 13 | 14 | import 'codemirror/mode/css/css' 15 | import 'codemirror/mode/javascript/javascript' 16 | import 'codemirror/mode/markdown/markdown' 17 | import 'codemirror/addon/edit/closebrackets' 18 | import 'codemirror/addon/edit/matchbrackets' 19 | import 'codemirror/addon/selection/active-line' 20 | import 'codemirror/addon/hint/show-hint' 21 | import 'codemirror/addon/hint/css-hint' 22 | 23 | const app = createApp(App) 24 | 25 | app.use(createPinia()) 26 | 27 | app.mount(`#app`) 28 | -------------------------------------------------------------------------------- /src/components/CodemirrorEditor/EditorHeader/HelpDropdown.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 24 | -------------------------------------------------------------------------------- /src/components/ui/select/SelectScrollUpButton.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 25 | -------------------------------------------------------------------------------- /src/components/ui/alert/index.ts: -------------------------------------------------------------------------------- 1 | import { cva, type VariantProps } from 'class-variance-authority' 2 | 3 | export { default as Alert } from './Alert.vue' 4 | export { default as AlertDescription } from './AlertDescription.vue' 5 | export { default as AlertTitle } from './AlertTitle.vue' 6 | 7 | export const alertVariants = cva( 8 | `relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground`, 9 | { 10 | variants: { 11 | variant: { 12 | default: `bg-background text-foreground`, 13 | destructive: 14 | `border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive`, 15 | }, 16 | }, 17 | defaultVariants: { 18 | variant: `default`, 19 | }, 20 | }, 21 | ) 22 | 23 | export type AlertVariants = VariantProps 24 | -------------------------------------------------------------------------------- /src/components/ui/select/SelectScrollDownButton.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 25 | -------------------------------------------------------------------------------- /src/components/ui/menubar/Menubar.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | dist 26 | 27 | node_modules 28 | 29 | # Log files 30 | npm-debug.log* 31 | yarn-debug.log* 32 | yarn-error.log* 33 | 34 | # Editor directories and files 35 | .idea 36 | *.suo 37 | *.ntvs* 38 | *.njsproj 39 | *.sln 40 | *.sw? 41 | 42 | # mockm 43 | httpData 44 | 45 | public/upload/** 46 | !public/upload/*.gitkeep 47 | .history 48 | 49 | # Package manager lock file 50 | # yarn.lock 51 | pnpm-lock.yaml 52 | auto-imports.d.ts 53 | components.d.ts 54 | 55 | .wxt 56 | .output 57 | web-ext.config.ts 58 | package-lock.json 59 | .vscode 60 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | "target": "ES2020", 6 | "jsx": "preserve", 7 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 8 | "moduleDetection": "force", 9 | "useDefineForClassFields": true, 10 | "baseUrl": "./", 11 | "module": "ESNext", 12 | 13 | /* Bundler mode */ 14 | "moduleResolution": "bundler", 15 | "paths": { 16 | "@/*": ["src/*"] 17 | }, 18 | "resolveJsonModule": true, 19 | "allowImportingTsExtensions": true, 20 | 21 | /* Linting */ 22 | "strict": true, 23 | "noFallthroughCasesInSwitch": true, 24 | "noUnusedLocals": true, 25 | "noUnusedParameters": true, 26 | "noEmit": true, 27 | "isolatedModules": true, 28 | "skipLibCheck": true 29 | }, 30 | "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "components.d.ts", "auto-imports.d.ts"] 31 | } 32 | -------------------------------------------------------------------------------- /src/components/ui/number-field/NumberFieldDecrement.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 26 | -------------------------------------------------------------------------------- /src/components/ui/number-field/NumberFieldIncrement.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 26 | -------------------------------------------------------------------------------- /src/components/ui/textarea/Textarea.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 |