├── .github ├── article-view.png ├── logo-mark.svg └── screen.png ├── .gitignore ├── MANIFEST.in ├── README.md ├── dashboard ├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ ├── img │ │ └── icons │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── android-chrome-maskable-192x192.png │ │ │ ├── android-chrome-maskable-512x512.png │ │ │ ├── apple-touch-icon-120x120.png │ │ │ ├── apple-touch-icon-152x152.png │ │ │ ├── apple-touch-icon-180x180.png │ │ │ ├── apple-touch-icon-60x60.png │ │ │ ├── apple-touch-icon-76x76.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── msapplication-icon-144x144.png │ │ │ ├── mstile-150x150.png │ │ │ └── safari-pinned-tab.svg │ ├── index.html │ └── robots.txt ├── src │ ├── App.vue │ ├── assets │ │ ├── call.js │ │ ├── logo.png │ │ └── style.css │ ├── components │ │ ├── ArticlePreview.vue │ │ ├── Bookmark.vue │ │ ├── Logo.vue │ │ ├── Navbar.vue │ │ ├── NavbarNew.vue │ │ └── Search.vue │ ├── main.js │ ├── registerServiceWorker.js │ ├── router │ │ └── index.js │ └── views │ │ └── Home.vue ├── tailwind.config.js ├── vue.config.js └── yarn.lock ├── license.txt ├── markd ├── __init__.py ├── config │ ├── __init__.py │ ├── desktop.py │ └── docs.py ├── hooks.py ├── markd │ ├── __init__.py │ ├── api.py │ ├── doctype │ │ ├── __init__.py │ │ ├── bookmark │ │ │ ├── __init__.py │ │ │ ├── bookmark.js │ │ │ ├── bookmark.json │ │ │ ├── bookmark.py │ │ │ └── test_bookmark.py │ │ ├── bookmark_tags │ │ │ ├── __init__.py │ │ │ ├── bookmark_tags.js │ │ │ ├── bookmark_tags.json │ │ │ ├── bookmark_tags.py │ │ │ └── test_bookmark_tags.py │ │ ├── markd_settings │ │ │ ├── __init__.py │ │ │ ├── markd_settings.js │ │ │ ├── markd_settings.json │ │ │ ├── markd_settings.py │ │ │ └── test_markd_settings.py │ │ └── tag_label │ │ │ ├── __init__.py │ │ │ ├── tag_label.js │ │ │ ├── tag_label.json │ │ │ ├── tag_label.py │ │ │ └── test_tag_label.py │ └── search.py ├── modules.txt ├── patches.txt ├── public │ └── dashboard │ │ ├── css │ │ └── app.ece821f8.css │ │ ├── favicon.ico │ │ ├── img │ │ └── icons │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── android-chrome-maskable-192x192.png │ │ │ ├── android-chrome-maskable-512x512.png │ │ │ ├── apple-touch-icon-120x120.png │ │ │ ├── apple-touch-icon-152x152.png │ │ │ ├── apple-touch-icon-180x180.png │ │ │ ├── apple-touch-icon-60x60.png │ │ │ ├── apple-touch-icon-76x76.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── msapplication-icon-144x144.png │ │ │ ├── mstile-150x150.png │ │ │ └── safari-pinned-tab.svg │ │ ├── js │ │ ├── app.5d3fe79f.js │ │ ├── app.5d3fe79f.js.map │ │ ├── chunk-vendors.448aa4f4.js │ │ └── chunk-vendors.448aa4f4.js.map │ │ ├── manifest.json │ │ ├── precache-manifest.32359028ecd51c22af442873dfd2c924.js │ │ ├── robots.txt │ │ └── service-worker.js ├── templates │ ├── __init__.py │ └── pages │ │ └── __init__.py └── www │ ├── __init__.py │ ├── dashboard.html │ └── dashboard.py ├── node_modules └── .yarn-integrity ├── requirements.txt ├── setup.py ├── yarn-error.log └── yarn.lock /.github/article-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/.github/article-view.png -------------------------------------------------------------------------------- /.github/logo-mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/.github/screen.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg-info 4 | *.swp 5 | tags 6 | markd/docs/current 7 | markd/www/dashboard 8 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include requirements.txt 3 | include *.json 4 | include *.md 5 | include *.py 6 | include *.txt 7 | recursive-include markd *.css 8 | recursive-include markd *.csv 9 | recursive-include markd *.html 10 | recursive-include markd *.ico 11 | recursive-include markd *.js 12 | recursive-include markd *.json 13 | recursive-include markd *.md 14 | recursive-include markd *.png 15 | recursive-include markd *.py 16 | recursive-include markd *.svg 17 | recursive-include markd *.txt 18 | recursive-exclude markd *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Logo 4 | 5 |

6 | A simple bookmarking app that you can host yourself. 7 |
8 | View Demo 9 | · 10 | Report Bug 11 | · 12 | Request Feature 13 |

14 |

15 | 16 | Supported by FOSSUnited 17 | 18 |

19 |

20 | 21 | 22 | 23 | ## Table of Contents 24 | 25 | - [About the Project](#about-the-project) 26 | - [Built With](#built-with) 27 | - [Installation](#installation) 28 | - [License](#license) 29 | - [Acknowledgements](#acknowledgements) 30 | 31 | 32 | 33 | ## About The Project 34 | 35 | A simple bookmarking app that you can host yourself. 36 | 37 | ### List View 38 | 39 | Screen 40 | 41 | ### Article Preview 42 | 43 | Logo 44 | 45 | ### Built With 46 | 47 | - [Frappe Framework](https://github.com/frappe/frappe) 48 | - [Vue JS](https://vuejs.org) 49 | 50 | ### Installation 51 | 52 | You can install this using [bench](https://github.com/frappe/bench), read the instructions [here](https://frappeframework.com/docs/user/en/installation). 53 | 54 | 55 | 56 | ## Usage 57 | 58 | Use this space to show useful examples of how a project can be used. Additional screenshots, code examples and demos work well in this space. You may also link to more resources. 59 | 60 | _For more examples, please refer to the [Documentation](https://example.com)_ 61 | 62 | 63 | 64 | ## Contributing 65 | 66 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. 67 | 68 | 1. Fork the Project 69 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 70 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 71 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 72 | 5. Open a Pull Request 73 | 74 | 75 | 76 | ## License 77 | 78 | Distributed under the MIT License. See `LICENSE` for more information. 79 | 80 | 81 | 82 | ## Acknowledgements 83 | 84 | - [Readme Template](https://github.com/othneildrew/Best-README-Template) 85 | - [Frappe Framework](https://frappeframework.com) 86 | - [FOSS United](https://fossunited.org) 87 | -------------------------------------------------------------------------------- /dashboard/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /dashboard/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | 'eslint:recommended' 9 | ], 10 | parserOptions: { 11 | parser: 'babel-eslint' 12 | }, 13 | rules: { 14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /dashboard/README.md: -------------------------------------------------------------------------------- 1 | # Long live the Mono-repo -------------------------------------------------------------------------------- /dashboard/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /dashboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboard", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@tailwindcss/typography": "^0.2.0", 12 | "core-js": "^3.6.5", 13 | "portal-vue": "^2.1.7", 14 | "register-service-worker": "^1.7.1", 15 | "tailwindcss": "^1.8.8", 16 | "vue": "^2.6.11", 17 | "vue-debounce": "^2.5.7", 18 | "vue-router": "^3.2.0", 19 | "vue-string-filter": "^2.1.0", 20 | "vue-tippy": "^4.7.0", 21 | "vue-unicons": "^2.3.0" 22 | }, 23 | "devDependencies": { 24 | "@vue/cli-plugin-babel": "~4.5.0", 25 | "@vue/cli-plugin-eslint": "~4.5.0", 26 | "@vue/cli-plugin-pwa": "~4.5.0", 27 | "@vue/cli-plugin-router": "~4.5.0", 28 | "@vue/cli-service": "~4.5.0", 29 | "babel-eslint": "^10.1.0", 30 | "eslint": "^6.7.2", 31 | "eslint-plugin-vue": "^6.2.2", 32 | "node-sass": "^4.12.0", 33 | "sass-loader": "^8.0.2", 34 | "vue-cli-plugin-chakra-ui": "~1.0.3", 35 | "vue-template-compiler": "^2.6.11" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /dashboard/postcss.config.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const tailwindcss = require('tailwindcss'); 3 | 4 | module.exports = { 5 | plugins: [ 6 | tailwindcss, 7 | autoprefixer, 8 | ], 9 | }; -------------------------------------------------------------------------------- /dashboard/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/favicon.ico -------------------------------------------------------------------------------- /dashboard/public/img/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/android-chrome-maskable-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/android-chrome-maskable-192x192.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/android-chrome-maskable-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/android-chrome-maskable-512x512.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/public/img/icons/mstile-150x150.png -------------------------------------------------------------------------------- /dashboard/public/img/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dashboard/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= htmlWebpackPlugin.options.title %> 10 | 11 | 12 | 13 | 17 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /dashboard/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /dashboard/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /dashboard/src/assets/call.js: -------------------------------------------------------------------------------- 1 | export default async function call(method, args) { 2 | if (!args) { 3 | args = {}; 4 | } 5 | 6 | const headers = { 7 | Accept: 'application/json', 8 | 'Content-Type': 'application/json; charset=utf-8', 9 | 'X-Frappe-Site-Name': window.location.hostname 10 | } 11 | 12 | if (window.csrf_token && window.csrf_token !== '{{ csrf_token }}') { 13 | headers['X-Frappe-CSRF-Token'] = window.csrf_token; 14 | } 15 | 16 | const res = await fetch(`/api/method/markd.markd.api.${method}`, { 17 | method: 'POST', 18 | headers, 19 | body: JSON.stringify(args) 20 | }); 21 | 22 | if (res.ok) { 23 | const data = await res.json(); 24 | console.log(data) 25 | if (data.docs) { 26 | return data; 27 | } 28 | return data.message; 29 | } else { 30 | let error = null; 31 | let data = null; 32 | try { 33 | data = await res.json(); 34 | if (data.exc) { 35 | error = JSON.parse(data.exc)[0]; 36 | } 37 | } catch (e) { 38 | error = await res.text(); 39 | } 40 | console.error(error); 41 | return { 42 | error: true, 43 | data 44 | }; 45 | } 46 | } -------------------------------------------------------------------------------- /dashboard/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/dashboard/src/assets/logo.png -------------------------------------------------------------------------------- /dashboard/src/assets/style.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/ArticlePreview.vue: -------------------------------------------------------------------------------- 1 | 101 | 102 | 145 | 146 | 151 | -------------------------------------------------------------------------------- /dashboard/src/components/Bookmark.vue: -------------------------------------------------------------------------------- 1 | 20 | 44 | -------------------------------------------------------------------------------- /dashboard/src/components/Logo.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 42 | -------------------------------------------------------------------------------- /dashboard/src/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /dashboard/src/components/NavbarNew.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /dashboard/src/components/Search.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 72 | 73 | 90 | -------------------------------------------------------------------------------- /dashboard/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import './registerServiceWorker' 4 | import router from './router' 5 | import './assets/style.css'; 6 | import call from './assets/call'; 7 | import VueStringFilter from 'vue-string-filter'; 8 | import PortalVue from 'portal-vue' 9 | import VueTippy, { TippyComponent } from "vue-tippy"; 10 | import Unicon from 'vue-unicons'; 11 | import { uniExternalLinkAlt, uniTrashAlt, uniTimes } from 'vue-unicons/src/icons' 12 | import vueDebounce from 'vue-debounce' 13 | 14 | Unicon.add([uniExternalLinkAlt, uniTrashAlt, uniTimes]) 15 | Vue.use(Unicon) 16 | 17 | Vue.use(vueDebounce) 18 | 19 | 20 | Vue.use(VueTippy, { 21 | directive: "tippy", // => v-tippy 22 | flipDuration: 0, 23 | arrow: true, 24 | animation: 'scale', 25 | popperOptions: { 26 | // modifiers: { 27 | // preventOverflow: { 28 | // enabled: false 29 | // } 30 | // } 31 | } 32 | }); 33 | 34 | Vue.component("tippy", TippyComponent); 35 | 36 | Vue.use(PortalVue) 37 | 38 | Vue.use(VueStringFilter); 39 | Vue.prototype.$call = call; 40 | Vue.config.productionTip = false 41 | 42 | Vue.prototype.$eventHub = new Vue(); // Global event bus 43 | 44 | 45 | new Vue({ 46 | router, 47 | render: h => h(App) 48 | }).$mount('#app') 49 | -------------------------------------------------------------------------------- /dashboard/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import { register } from 'register-service-worker' 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | register(`${process.env.BASE_URL}service-worker.js`, { 7 | ready () { 8 | console.log( 9 | 'App is being served from cache by a service worker.\n' + 10 | 'For more details, visit https://goo.gl/AFskqB' 11 | ) 12 | }, 13 | registered () { 14 | console.log('Service worker has been registered.') 15 | }, 16 | cached () { 17 | console.log('Content has been cached for offline use.') 18 | }, 19 | updatefound () { 20 | console.log('New content is downloading.') 21 | }, 22 | updated () { 23 | console.log('New content is available; please refresh.') 24 | }, 25 | offline () { 26 | console.log('No internet connection found. App is running in offline mode.') 27 | }, 28 | error (error) { 29 | console.error('Error during service worker registration:', error) 30 | } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /dashboard/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | const routes = [ 8 | { 9 | path: '/', 10 | name: 'Home', 11 | component: Home 12 | }, 13 | // { 14 | // path: '/about', 15 | // name: 'About', 16 | // // route level code-splitting 17 | // // this generates a separate chunk (about.[hash].js) for this route 18 | // // which is lazy-loaded when the route is visited. 19 | // component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') 20 | // } 21 | ] 22 | 23 | const router = new VueRouter({ 24 | routes 25 | }) 26 | 27 | export default router 28 | -------------------------------------------------------------------------------- /dashboard/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 43 | -------------------------------------------------------------------------------- /dashboard/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: [ 3 | './public/**/*.html', 4 | './src/**/*.vue', 5 | ], 6 | theme: { 7 | extend: {}, 8 | }, 9 | variants: {}, 10 | plugins: [ 11 | require('@tailwindcss/typography'), 12 | ], 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const sites_path = path.resolve('../../../sites'); 4 | const common_site_config = require('../../../sites/common_site_config.json'); 5 | const { webserver_port } = common_site_config; 6 | const sites = fs 7 | .readdirSync(sites_path) 8 | .filter( 9 | folder_name => 10 | ![ 11 | '.build', 12 | 'apps.txt', 13 | 'assets', 14 | 'common_site_config', 15 | 'currentsite' 16 | ].includes(folder_name) 17 | ); 18 | 19 | // FRAPPE_ENV will be either undefined, 'development' or 'production' 20 | if (process.env.FRAPPE_ENV) { 21 | process.env.NODE_ENV = process.env.FRAPPE_ENV; 22 | } 23 | 24 | const serverProxy = { 25 | target: `http://localhost:${webserver_port}`, 26 | ws: true, 27 | changeOrigin: true, 28 | router: function (req) { 29 | const site_name = req.headers.host.split(':')[0]; 30 | return `http://${site_name}:${webserver_port}`; 31 | } 32 | } 33 | 34 | module.exports = { 35 | publicPath: 36 | process.env.NODE_ENV === 'production' ? '/assets/markd/dashboard/' : '/', 37 | outputDir: path.resolve('../markd/public/dashboard'), 38 | indexPath: path.resolve('../markd/www/dashboard.html'), 39 | devServer: { 40 | allowedHosts: sites, 41 | proxy: { 42 | '^/api': serverProxy, 43 | '^/assets': serverProxy, 44 | '^/files': serverProxy 45 | } 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | License: MIT -------------------------------------------------------------------------------- /markd/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | __version__ = '0.0.1' 5 | 6 | -------------------------------------------------------------------------------- /markd/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/config/__init__.py -------------------------------------------------------------------------------- /markd/config/desktop.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | from frappe import _ 4 | 5 | def get_data(): 6 | return [ 7 | { 8 | "module_name": "Markd", 9 | "color": "grey", 10 | "icon": "octicon octicon-file-directory", 11 | "type": "module", 12 | "label": _("Markd") 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /markd/config/docs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Configuration for docs 3 | """ 4 | 5 | # source_link = "https://github.com/[org_name]/markd" 6 | # docs_base_url = "https://[org_name].github.io/markd" 7 | # headline = "App that does everything" 8 | # sub_heading = "Yes, you got that right the first time, everything" 9 | 10 | def get_context(context): 11 | context.brand_html = "Markd" 12 | -------------------------------------------------------------------------------- /markd/hooks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | from . import __version__ as app_version 4 | 5 | app_name = "markd" 6 | app_title = "Markd" 7 | app_publisher = "Shivam Mishra" 8 | app_description = "A simple bookmarking app" 9 | app_icon = "octicon octicon-file-directory" 10 | app_color = "grey" 11 | app_email = "shivam@frappe.io" 12 | app_license = "MIT" 13 | 14 | # Includes in 15 | # ------------------ 16 | 17 | # include js, css files in header of desk.html 18 | # app_include_css = "/assets/markd/css/markd.css" 19 | # app_include_js = "/assets/markd/js/markd.js" 20 | 21 | # include js, css files in header of web template 22 | # web_include_css = "/assets/markd/css/markd.css" 23 | # web_include_js = "/assets/markd/js/markd.js" 24 | 25 | # include js, css files in header of web form 26 | # webform_include_js = {"doctype": "public/js/doctype.js"} 27 | # webform_include_css = {"doctype": "public/css/doctype.css"} 28 | 29 | # include js in page 30 | # page_js = {"page" : "public/js/file.js"} 31 | 32 | # include js in doctype views 33 | # doctype_js = {"doctype" : "public/js/doctype.js"} 34 | # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} 35 | # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} 36 | # doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} 37 | 38 | # Home Pages 39 | # ---------- 40 | 41 | # application home page (will override Website Settings) 42 | # home_page = "login" 43 | 44 | # website user home page (by Role) 45 | # role_home_page = { 46 | # "Role": "home_page" 47 | # } 48 | 49 | # Generators 50 | # ---------- 51 | 52 | # automatically create page for each record of this doctype 53 | # website_generators = ["Web Page"] 54 | 55 | # Installation 56 | # ------------ 57 | 58 | # before_install = "markd.install.before_install" 59 | # after_install = "markd.install.after_install" 60 | 61 | # Desk Notifications 62 | # ------------------ 63 | # See frappe.core.notifications.get_notification_config 64 | 65 | # notification_config = "markd.notifications.get_notification_config" 66 | 67 | # Permissions 68 | # ----------- 69 | # Permissions evaluated in scripted ways 70 | 71 | # permission_query_conditions = { 72 | # "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions", 73 | # } 74 | # 75 | # has_permission = { 76 | # "Event": "frappe.desk.doctype.event.event.has_permission", 77 | # } 78 | 79 | # Document Events 80 | # --------------- 81 | # Hook on document methods and events 82 | 83 | # doc_events = { 84 | # "*": { 85 | # "on_update": "method", 86 | # "on_cancel": "method", 87 | # "on_trash": "method" 88 | # } 89 | # } 90 | 91 | # Scheduled Tasks 92 | # --------------- 93 | 94 | # scheduler_events = { 95 | # "all": [ 96 | # "markd.tasks.all" 97 | # ], 98 | # "daily": [ 99 | # "markd.tasks.daily" 100 | # ], 101 | # "hourly": [ 102 | # "markd.tasks.hourly" 103 | # ], 104 | # "weekly": [ 105 | # "markd.tasks.weekly" 106 | # ] 107 | # "monthly": [ 108 | # "markd.tasks.monthly" 109 | # ] 110 | # } 111 | 112 | # Testing 113 | # ------- 114 | 115 | # before_tests = "markd.install.before_tests" 116 | 117 | # Overriding Methods 118 | # ------------------------------ 119 | # 120 | # override_whitelisted_methods = { 121 | # "frappe.desk.doctype.event.event.get_events": "markd.event.get_events" 122 | # } 123 | # 124 | # each overriding function accepts a `data` argument; 125 | # generated from the base implementation of the doctype dashboard, 126 | # along with any modifications made in other Frappe apps 127 | # override_doctype_dashboards = { 128 | # "Task": "markd.task.get_dashboard_data" 129 | # } 130 | 131 | # exempt linked doctypes from being automatically cancelled 132 | # 133 | # auto_cancel_exempted_doctypes = ["Auto Repeat"] 134 | 135 | -------------------------------------------------------------------------------- /markd/markd/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/markd/__init__.py -------------------------------------------------------------------------------- /markd/markd/api.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from functools import wraps 3 | from markd.markd.search import BookmarkSearch 4 | 5 | def check_demo(): 6 | if frappe.session.user == "Guest": 7 | if not frappe.db.get_single_value("Markd Settings", "enable_demo_mode"): 8 | raise frappe.PermissionError 9 | 10 | @frappe.whitelist(allow_guest=True) 11 | def get_bookmarks(): 12 | check_demo() 13 | marks = frappe.get_all("Bookmark", limit=20) 14 | return [frappe.get_doc("Bookmark", mark['name']) for mark in marks] 15 | 16 | @frappe.whitelist() 17 | def save_mark(url): 18 | mark = frappe.new_doc("Bookmark") 19 | mark.url = url 20 | mark.insert() 21 | return mark 22 | 23 | @frappe.whitelist() 24 | def delete_mark(mark): 25 | mark = frappe.delete_doc("Bookmark", mark) 26 | 27 | @frappe.whitelist(allow_guest=True) 28 | def search(query, limit=10): 29 | check_demo() 30 | limit = frappe.utils.cint(limit) 31 | ws = BookmarkSearch(index_name="bookmark-index") 32 | return ws.search(query, limit=limit) -------------------------------------------------------------------------------- /markd/markd/doctype/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/markd/doctype/__init__.py -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/markd/doctype/bookmark/__init__.py -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark/bookmark.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Shivam Mishra and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Bookmark', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark/bookmark.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "autoname": "format:MARK-{######}", 4 | "creation": "2020-09-12 12:20:56.485167", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "url", 10 | "column_break_2", 11 | "tags", 12 | "meta_info_section", 13 | "meta_title", 14 | "meta_name", 15 | "description", 16 | "website", 17 | "column_break_8", 18 | "favicon", 19 | "image", 20 | "section_break_11", 21 | "readable" 22 | ], 23 | "fields": [ 24 | { 25 | "fieldname": "url", 26 | "fieldtype": "Data", 27 | "label": "URL" 28 | }, 29 | { 30 | "fieldname": "meta_info_section", 31 | "fieldtype": "Section Break", 32 | "label": "Meta Info" 33 | }, 34 | { 35 | "fieldname": "tags", 36 | "fieldtype": "Table MultiSelect", 37 | "label": "Tags", 38 | "options": "Bookmark Tags" 39 | }, 40 | { 41 | "fieldname": "column_break_2", 42 | "fieldtype": "Column Break" 43 | }, 44 | { 45 | "fieldname": "meta_name", 46 | "fieldtype": "Data", 47 | "label": "Name" 48 | }, 49 | { 50 | "fieldname": "description", 51 | "fieldtype": "Small Text", 52 | "label": "Description" 53 | }, 54 | { 55 | "fieldname": "image", 56 | "fieldtype": "Attach Image", 57 | "label": "Image" 58 | }, 59 | { 60 | "fieldname": "meta_title", 61 | "fieldtype": "Data", 62 | "label": "Title" 63 | }, 64 | { 65 | "fieldname": "readable", 66 | "fieldtype": "HTML Editor", 67 | "label": "Readable" 68 | }, 69 | { 70 | "fieldname": "column_break_8", 71 | "fieldtype": "Column Break" 72 | }, 73 | { 74 | "fieldname": "favicon", 75 | "fieldtype": "Attach Image", 76 | "label": "Favicon" 77 | }, 78 | { 79 | "fieldname": "section_break_11", 80 | "fieldtype": "Section Break" 81 | }, 82 | { 83 | "fieldname": "website", 84 | "fieldtype": "Data", 85 | "label": "Website" 86 | } 87 | ], 88 | "index_web_pages_for_search": 1, 89 | "links": [], 90 | "modified": "2020-09-12 19:34:46.290055", 91 | "modified_by": "Administrator", 92 | "module": "Markd", 93 | "name": "Bookmark", 94 | "owner": "Administrator", 95 | "permissions": [ 96 | { 97 | "create": 1, 98 | "delete": 1, 99 | "email": 1, 100 | "export": 1, 101 | "print": 1, 102 | "read": 1, 103 | "report": 1, 104 | "role": "System Manager", 105 | "share": 1, 106 | "write": 1 107 | } 108 | ], 109 | "quick_entry": 1, 110 | "sort_field": "modified", 111 | "sort_order": "DESC", 112 | "title_field": "meta_title", 113 | "track_changes": 1 114 | } -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark/bookmark.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Shivam Mishra and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | import requests 7 | import urllib 8 | from urllib.parse import urlparse 9 | from readability import Document as RDoc 10 | from bs4 import BeautifulSoup 11 | 12 | import frappe 13 | from frappe.utils.file_manager import save_file_on_filesystem 14 | from frappe.model.document import Document 15 | 16 | from markd.markd.search import add_item, remove_item 17 | 18 | class Bookmark(Document): 19 | def before_save(self): 20 | response = requests.get(self.url) 21 | meta = self.fetch_url_meta(response) 22 | self.meta_title = meta.title 23 | self.description = meta.description 24 | self.website = urlparse(self.url).netloc 25 | 26 | image = meta.image or meta.get("og:image") or meta.get("twitter:image") 27 | self.image = self.save_file(image) 28 | self.readable = self.get_readable(response) 29 | self.favicon = self.fetch_favicon(response) 30 | 31 | def after_insert(self): 32 | add_item(self.name) 33 | 34 | def on_trash(self): 35 | remove_item(self.name) 36 | 37 | def fetch_url_meta(self, response): 38 | soup = BeautifulSoup(response.text, features="lxml") 39 | metas = soup.find_all('meta') 40 | all_meta = { meta.attrs['name']:meta.attrs['content'] for meta in metas if 'name' in meta.attrs } 41 | 42 | title = soup.find('title') 43 | if title: 44 | all_meta['title'] = title.text 45 | 46 | return frappe._dict(all_meta) 47 | 48 | def fetch_favicon(self, response): 49 | soup = BeautifulSoup(response.text, features="lxml") 50 | icon_link = soup.find("link", rel="icon") 51 | if not icon_link: 52 | return 53 | icon_link = icon_link['href'] 54 | netloc = urlparse(self.url).netloc 55 | if netloc not in icon_link: 56 | icon_link = 'https://' + netloc + icon_link 57 | 58 | return self.save_file(icon_link) 59 | 60 | def get_readable(self, response): 61 | doc = RDoc(response.text) 62 | return doc.summary() 63 | 64 | def save_file(self, url): 65 | if not url: 66 | return 67 | urlfile = urllib.request.urlopen(url) 68 | name = self.name + frappe.utils.random_string(8) + '.' + url.split('.')[-1].split('?')[0] 69 | ico_file = save_file_on_filesystem(name, urlfile.read()) 70 | return ico_file.get('file_url') -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark/test_bookmark.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Shivam Mishra and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestBookmark(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark_tags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/markd/doctype/bookmark_tags/__init__.py -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark_tags/bookmark_tags.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Shivam Mishra and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Bookmark Tags', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark_tags/bookmark_tags.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2020-09-12 12:20:26.633439", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "tag" 9 | ], 10 | "fields": [ 11 | { 12 | "fieldname": "tag", 13 | "fieldtype": "Link", 14 | "in_list_view": 1, 15 | "label": "Tag", 16 | "options": "Tag Label", 17 | "reqd": 1 18 | } 19 | ], 20 | "index_web_pages_for_search": 1, 21 | "istable": 1, 22 | "links": [], 23 | "modified": "2020-09-12 12:23:36.443559", 24 | "modified_by": "Administrator", 25 | "module": "Markd", 26 | "name": "Bookmark Tags", 27 | "owner": "Administrator", 28 | "permissions": [], 29 | "quick_entry": 1, 30 | "sort_field": "modified", 31 | "sort_order": "DESC", 32 | "track_changes": 1 33 | } -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark_tags/bookmark_tags.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Shivam Mishra and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | # import frappe 7 | from frappe.model.document import Document 8 | 9 | class BookmarkTags(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /markd/markd/doctype/bookmark_tags/test_bookmark_tags.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Shivam Mishra and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestBookmarkTags(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /markd/markd/doctype/markd_settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/markd/doctype/markd_settings/__init__.py -------------------------------------------------------------------------------- /markd/markd/doctype/markd_settings/markd_settings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Shivam Mishra and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Markd Settings', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /markd/markd/doctype/markd_settings/markd_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2020-09-19 19:58:46.329989", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "enable_demo_mode" 9 | ], 10 | "fields": [ 11 | { 12 | "default": "0", 13 | "fieldname": "enable_demo_mode", 14 | "fieldtype": "Check", 15 | "label": "Enable Demo Mode" 16 | } 17 | ], 18 | "index_web_pages_for_search": 1, 19 | "issingle": 1, 20 | "links": [], 21 | "modified": "2020-09-19 19:58:46.329989", 22 | "modified_by": "Administrator", 23 | "module": "Markd", 24 | "name": "Markd Settings", 25 | "owner": "Administrator", 26 | "permissions": [ 27 | { 28 | "create": 1, 29 | "delete": 1, 30 | "email": 1, 31 | "print": 1, 32 | "read": 1, 33 | "role": "System Manager", 34 | "share": 1, 35 | "write": 1 36 | } 37 | ], 38 | "quick_entry": 1, 39 | "sort_field": "modified", 40 | "sort_order": "DESC", 41 | "track_changes": 1 42 | } -------------------------------------------------------------------------------- /markd/markd/doctype/markd_settings/markd_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Shivam Mishra and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | # import frappe 7 | from frappe.model.document import Document 8 | 9 | class MarkdSettings(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /markd/markd/doctype/markd_settings/test_markd_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Shivam Mishra and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestMarkdSettings(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /markd/markd/doctype/tag_label/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/markd/doctype/tag_label/__init__.py -------------------------------------------------------------------------------- /markd/markd/doctype/tag_label/tag_label.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Shivam Mishra and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Tag Label', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /markd/markd/doctype/tag_label/tag_label.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "autoname": "field:tag_name", 4 | "creation": "2020-09-12 12:19:56.743634", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "tag_name" 10 | ], 11 | "fields": [ 12 | { 13 | "fieldname": "tag_name", 14 | "fieldtype": "Data", 15 | "label": "Tag Name", 16 | "unique": 1 17 | } 18 | ], 19 | "index_web_pages_for_search": 1, 20 | "links": [], 21 | "modified": "2020-09-12 12:20:02.355248", 22 | "modified_by": "Administrator", 23 | "module": "Markd", 24 | "name": "Tag Label", 25 | "owner": "Administrator", 26 | "permissions": [ 27 | { 28 | "create": 1, 29 | "delete": 1, 30 | "email": 1, 31 | "export": 1, 32 | "print": 1, 33 | "read": 1, 34 | "report": 1, 35 | "role": "System Manager", 36 | "share": 1, 37 | "write": 1 38 | } 39 | ], 40 | "quick_entry": 1, 41 | "sort_field": "modified", 42 | "sort_order": "DESC", 43 | "track_changes": 1 44 | } -------------------------------------------------------------------------------- /markd/markd/doctype/tag_label/tag_label.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Shivam Mishra and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | # import frappe 7 | from frappe.model.document import Document 8 | 9 | class TagLabel(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /markd/markd/doctype/tag_label/test_tag_label.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Shivam Mishra and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestTagLabel(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /markd/markd/search.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.search.full_text_search import FullTextSearch 3 | from frappe.utils import strip_html_tags 4 | from whoosh.fields import TEXT, ID, Schema 5 | 6 | class BookmarkSearch(FullTextSearch): 7 | def get_items_to_index(self): 8 | all_docs = [] 9 | marks = frappe.get_all("Bookmark", fields=["name", "readable"]) 10 | for mark in marks: 11 | all_docs.append({ 12 | 'name': mark.name, 13 | 'title': mark.meta_title, 14 | 'content': strip_html_tags(mark.readable) 15 | }) 16 | return all_docs 17 | 18 | def get_schema(self): 19 | return Schema( 20 | title=TEXT(stored=True), name=ID(stored=True), content=TEXT(stored=True) 21 | ) 22 | 23 | def get_document_to_index(self, name): 24 | mark = frappe.get_doc("Bookmark", name) 25 | return { 26 | 'name': mark.name, 27 | 'content': strip_html_tags(mark.readable) 28 | } 29 | 30 | def parse_result(self, result): 31 | content_highlights = result.highlights("content") 32 | 33 | return frappe._dict( 34 | name=result["name"], 35 | content_highlights=content_highlights, 36 | doc=frappe.get_doc("Bookmark", result["name"]) 37 | ) 38 | 39 | def build(): 40 | bms = BookmarkSearch("bookmark-index") 41 | bms.build() 42 | 43 | def add_item(name): 44 | bms = BookmarkSearch("bookmark-index") 45 | return bms.update_index_by_name(name) 46 | 47 | def remove_item(name): 48 | bms = BookmarkSearch("bookmark-index") 49 | return bms.remove_document_from_index(name) -------------------------------------------------------------------------------- /markd/modules.txt: -------------------------------------------------------------------------------- 1 | Markd -------------------------------------------------------------------------------- /markd/patches.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/patches.txt -------------------------------------------------------------------------------- /markd/public/dashboard/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/favicon.ico -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/android-chrome-maskable-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/android-chrome-maskable-192x192.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/android-chrome-maskable-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/android-chrome-maskable-512x512.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/public/dashboard/img/icons/mstile-150x150.png -------------------------------------------------------------------------------- /markd/public/dashboard/img/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /markd/public/dashboard/js/app.5d3fe79f.js: -------------------------------------------------------------------------------- 1 | (function(e){function t(t){for(var r,o,i=t[0],l=t[1],c=t[2],d=0,p=[];d\n\t\n\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\n\t\n\n\n\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Logo.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Logo.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./Logo.vue?vue&type=template&id=2719a727&\"\nimport script from \"./Logo.vue?vue&type=script&lang=js&\"\nexport * from \"./Logo.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"pt-2 relative text-gray-600\"},[_c('input',{directives:[{name:\"model\",rawName:\"v-model\",value:(_vm.searchTerm),expression:\"searchTerm\"},{name:\"debounce\",rawName:\"v-debounce:300\",value:(_vm.search),expression:\"search\",arg:\"300\"}],staticClass:\"search-input relative border-2 border-gray-300 bg-white h-10 px-5 pr-16 rounded-lg text-sm focus:outline-none\",attrs:{\"type\":\"search\",\"name\":\"search\",\"placeholder\":\"Search\",\"autocomplete\":\"off\"},domProps:{\"value\":(_vm.searchTerm)},on:{\"input\":function($event){if($event.target.composing){ return; }_vm.searchTerm=$event.target.value}}}),(_vm.showResult)?_c('div',{staticClass:\"bg-white absolute search-results p-2 shadow-lg mt-2 rounded-md\"},_vm._l((_vm.searchResults),function(result){return _c('div',{key:result.name,staticClass:\"prose prose-xs hover:bg-teal-100 p-2 rounded\"},[_c('h4',[_vm._v(_vm._s(result.doc.meta_title))]),_c('p',{staticClass:\" text-xs\",domProps:{\"innerHTML\":_vm._s(result.content_highlights)}})])}),0):_vm._e(),_c('span',{staticClass:\"absolute right-0 top-0 mt-5 mr-4\"},[_c('svg',{staticClass:\"text-gray-600 h-4 w-4 fill-current\",staticStyle:{\"enable-background\":\"new 0 0 56.966 56.966\"},attrs:{\"xmlns\":\"http://www.w3.org/2000/svg\",\"xmlns:xlink\":\"http://www.w3.org/1999/xlink\",\"version\":\"1.1\",\"id\":\"Capa_1\",\"x\":\"0px\",\"y\":\"0px\",\"viewBox\":\"0 0 56.966 56.966\",\"xml:space\":\"preserve\",\"width\":\"512px\",\"height\":\"512px\"}},[_c('path',{attrs:{\"d\":\"M55.146,51.887L41.588,37.786c3.486-4.144,5.396-9.358,5.396-14.786c0-12.682-10.318-23-23-23s-23,10.318-23,23 s10.318,23,23,23c4.761,0,9.298-1.436,13.177-4.162l13.661,14.208c0.571,0.593,1.339,0.92,2.162,0.92 c0.779,0,1.518-0.297,2.079-0.837C56.255,54.982,56.293,53.08,55.146,51.887z M23.984,6c9.374,0,17,7.626,17,17s-7.626,17-17,17 s-17-7.626-17-17S14.61,6,23.984,6z\"}})])])])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\n\n\n\n\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Search.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Search.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./Search.vue?vue&type=template&id=ffb645a8&\"\nimport script from \"./Search.vue?vue&type=script&lang=js&\"\nexport * from \"./Search.vue?vue&type=script&lang=js&\"\nimport style0 from \"./Search.vue?vue&type=style&index=0&lang=scss&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('button',{staticClass:\"bg-teal-500 text-white active:bg-teal-600 font-bold uppercase text-sm px-6 py-2 rounded shadow hover:shadow-lg outline-none focus:outline-none\",staticStyle:{\"transition\":\"all .15s ease\"},attrs:{\"type\":\"button\"},on:{\"click\":function($event){return _vm.toggleModal()}}},[_vm._v(\" MARK \")]),(_vm.showModal)?_c('div',{staticClass:\"overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none justify-center items-center flex\"},[_c('div',{staticClass:\"relative w-1/3 my-6 mx-auto max-w-md\"},[_c('div',{staticClass:\"border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none\"},[_c('div',{staticClass:\"flex items-start justify-between px-5 py-3 border-gray-300 rounded-t\"},[_c('h3',{staticClass:\"text-xl font-semibold\"},[_vm._v(\" Add Mark \")]),_c('button',{staticClass:\"flex items-center ml-auto bg-transparent border-0 text-black float-right text-3xl leading-none font-semibold outline-none focus:outline-none\",on:{\"click\":function($event){return _vm.toggleModal()}}},[_c('span',{staticClass:\"bg-transparent text-gray-400 opacity-5 h-6 w-6 text-2xl block outline-none focus:outline-none\"},[_vm._v(\" × \")])])]),_c('div',{staticClass:\"relative px-5 py-3 flex-auto\"},[_c('input',{directives:[{name:\"model\",rawName:\"v-model\",value:(_vm.url),expression:\"url\"}],staticClass:\"px-3 py-3\\n\\t\\t\\t\\t\\tplaceholder-gray-400 text-gray-700 relative bg-gray-200\\n\\t\\t\\t\\t\\trounded text-sm outline-none focus:outline-none w-full\",attrs:{\"type\":\"text\",\"disabled\":_vm.freeze,\"placeholder\":\"https://getmarkd.app\"},domProps:{\"value\":(_vm.url)},on:{\"input\":function($event){if($event.target.composing){ return; }_vm.url=$event.target.value}}})]),_c('div',{staticClass:\"flex items-center justify-end p-2 rounded-b\"},[_c('button',{staticClass:\"text-white bg-teal-500 rounded font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1 mb-1\",staticStyle:{\"transition\":\"all .15s ease\"},attrs:{\"type\":\"button\",\"disabled\":_vm.freeze},on:{\"click\":function($event){return _vm.saveURL()}}},[_vm._v(\" mark it. \")])])])])]):_vm._e(),(_vm.showModal)?_c('div',{staticClass:\"opacity-25 fixed inset-0 z-40 bg-black\"}):_vm._e()])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\n\n\n\n\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./NavbarNew.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./NavbarNew.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./NavbarNew.vue?vue&type=template&id=4e963031&\"\nimport script from \"./NavbarNew.vue?vue&type=script&lang=js&\"\nexport * from \"./NavbarNew.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","\n\n\n\n\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Navbar.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Navbar.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./Navbar.vue?vue&type=template&id=64441803&\"\nimport script from \"./Navbar.vue?vue&type=script&lang=js&\"\nexport * from \"./Navbar.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","\n\n\n","import mod from \"-!../node_modules/cache-loader/dist/cjs.js??ref--12-0!../node_modules/thread-loader/dist/cjs.js!../node_modules/babel-loader/lib/index.js!../node_modules/cache-loader/dist/cjs.js??ref--0-0!../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../node_modules/cache-loader/dist/cjs.js??ref--12-0!../node_modules/thread-loader/dist/cjs.js!../node_modules/babel-loader/lib/index.js!../node_modules/cache-loader/dist/cjs.js??ref--0-0!../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./App.vue?vue&type=template&id=3ade2755&\"\nimport script from \"./App.vue?vue&type=script&lang=js&\"\nexport * from \"./App.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","/* eslint-disable no-console */\n\nimport { register } from 'register-service-worker'\n\nif (process.env.NODE_ENV === 'production') {\n register(`${process.env.BASE_URL}service-worker.js`, {\n ready () {\n console.log(\n 'App is being served from cache by a service worker.\\n' +\n 'For more details, visit https://goo.gl/AFskqB'\n )\n },\n registered () {\n console.log('Service worker has been registered.')\n },\n cached () {\n console.log('Content has been cached for offline use.')\n },\n updatefound () {\n console.log('New content is downloading.')\n },\n updated () {\n console.log('New content is available; please refresh.')\n },\n offline () {\n console.log('No internet connection found. App is running in offline mode.')\n },\n error (error) {\n console.error('Error during service worker registration:', error)\n }\n })\n}\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('div',{staticClass:\"grid grid-cols-4 gap-4 mt-5\"},_vm._l((_vm.fetchedData),function(mark){return _c('Bookmark',{key:mark.name,attrs:{\"mark\":mark}})}),1)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"bg-white shadow hover:shadow-md rounded-lg p-2 cursor-pointer\"},[_c('div',{staticClass:\"h-full\",on:{\"click\":_vm.openPreview}},[_c('img',{staticClass:\"rounded-md h-40 text-center object-cover\",attrs:{\"src\":_vm.mark.image}}),_c('div',{staticClass:\"flex flex-col justify-between\"},[_c('h3',{staticClass:\"text-lg font-bold mt-2\"},[_vm._v(\" \"+_vm._s(_vm._f(\"truncate\")(_vm.mark.meta_title,50))+\" \")]),_c('p',{staticClass:\"text-gray-600 text-sm\"},[_vm._v(\" \"+_vm._s(_vm.mark.website)+\" \")])])]),(_vm.showPreview)?_c('ArticlePreview',{attrs:{\"mark\":_vm.mark},on:{\"close\":_vm.closePreview}}):_vm._e()],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"fixed z-10 inset-0 overflow-y-auto\"},[_c('div',{staticClass:\"flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0\"},[_vm._m(0),_c('div',{staticClass:\"w-2/3 inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8\",attrs:{\"role\":\"dialog\",\"aria-modal\":\"true\",\"aria-labelledby\":\"modal-headline\"}},[_c('div',{staticClass:\"bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 w-2/3 mx-auto\"},[_c('div',{staticClass:\"flex justify-between\"},[_c('div',{staticClass:\"text-gray-600 uppercase tracking-wide text-xs font-bold\"},[(_vm.mark.website)?_c('a',{directives:[{name:\"tippy\",rawName:\"v-tippy\"}],staticClass:\"p-2 bg-gray-200 rounded flex items-center\",attrs:{\"href\":(\"https://\" + (_vm.mark.website)),\"target\":\"_blank\",\"content\":\"Open Website Home\"}},[(_vm.mark.favicon)?_c('img',{staticClass:\"inline-block h-4 mr-2\",attrs:{\"src\":_vm.mark.favicon}}):_vm._e(),_vm._v(\" \"+_vm._s(_vm.mark.website)+\" \")]):_vm._e()]),_c('div',{staticClass:\"flex justify-end\"},[_c('a',{directives:[{name:\"tippy\",rawName:\"v-tippy\"}],staticClass:\"text-gray-400 mr-4 hover:text-teal-500 focus:outline-none cursor-pointer\",attrs:{\"href\":_vm.mark.url,\"target\":\"_blank\",\"content\":\"Open Article Link\"}},[_c('unicon',{attrs:{\"name\":\"external-link-alt\",\"fill\":\"currentColor\",\"height\":\"18\",\"width\":\"18\"}})],1),_c('a',{directives:[{name:\"tippy\",rawName:\"v-tippy\",value:({\n\t\t\t\t\t\t\t\thideOnClick: false,\n\t\t\t\t\t\t\t}),expression:\"{\\n\\t\\t\\t\\t\\t\\t\\t\\thideOnClick: false,\\n\\t\\t\\t\\t\\t\\t\\t}\"}],staticClass:\"text-gray-400 mr-4 hover:text-red-500 focus:outline-none cursor-pointer\",attrs:{\"target\":\"_blank\",\"content\":_vm.deleteTipContent},on:{\"click\":_vm.deleteMark}},[_c('unicon',{attrs:{\"name\":\"trash-alt\",\"fill\":\"currentColor\",\"height\":\"18\",\"width\":\"18\"}})],1),_c('a',{directives:[{name:\"tippy\",rawName:\"v-tippy\"}],staticClass:\"text-gray-400 mr-4 hover:text-gray-800 focus:outline-none cursor-pointer\",attrs:{\"target\":\"_blank\",\"content\":\"Close Article\"},on:{\"click\":function($event){$event.preventDefault();return _vm.closeModal($event)}}},[_c('unicon',{attrs:{\"name\":\"times\",\"fill\":\"currentColor\",\"height\":\"18\",\"width\":\"18\"}})],1)])]),_c('div',{staticClass:\"prose prose-md my-12\"},[_c('h2',{staticClass:\"text-2xl leading-6 font-medium text-gray-900\",attrs:{\"id\":\"modal-headline\"}},[_vm._v(\" \"+_vm._s(_vm.mark.meta_title)+\" \")]),_c('div',{staticClass:\"mt-2 overflow-scroll limit-height\"},[_c('div',{domProps:{\"innerHTML\":_vm._s(_vm.mark.readable)}})])])])])])])}\nvar staticRenderFns = [function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"fixed inset-0 transition-opacity\"},[_c('div',{staticClass:\"absolute inset-0 bg-gray-500 opacity-75\"})])}]\n\nexport { render, staticRenderFns }","\n\n\n\n\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./ArticlePreview.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./ArticlePreview.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./ArticlePreview.vue?vue&type=template&id=0cde1d86&scoped=true&\"\nimport script from \"./ArticlePreview.vue?vue&type=script&lang=js&\"\nexport * from \"./ArticlePreview.vue?vue&type=script&lang=js&\"\nimport style0 from \"./ArticlePreview.vue?vue&type=style&index=0&id=0cde1d86&scoped=true&lang=css&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"0cde1d86\",\n null\n \n)\n\nexport default component.exports","\n\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Bookmark.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Bookmark.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./Bookmark.vue?vue&type=template&id=4ce1555e&\"\nimport script from \"./Bookmark.vue?vue&type=script&lang=js&\"\nexport * from \"./Bookmark.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","\n\n\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Home.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Home.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./Home.vue?vue&type=template&id=850d65de&\"\nimport script from \"./Home.vue?vue&type=script&lang=js&\"\nexport * from \"./Home.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","import Vue from 'vue'\nimport VueRouter from 'vue-router'\nimport Home from '../views/Home.vue'\n\nVue.use(VueRouter)\n\nconst routes = [\n\t{\n\t\tpath: '/',\n\t\tname: 'Home',\n\t\tcomponent: Home\n\t},\n\t// {\n\t// path: '/about',\n\t// name: 'About',\n\t// // route level code-splitting\n\t// // this generates a separate chunk (about.[hash].js) for this route\n\t// // which is lazy-loaded when the route is visited.\n\t// component: () => import(/* webpackChunkName: \"about\" */ '../views/About.vue')\n\t// }\n]\n\nconst router = new VueRouter({\n\troutes\n})\n\nexport default router\n","export default async function call(method, args) {\n\tif (!args) {\n\t\targs = {};\n\t}\n\n\tconst headers = {\n\t\tAccept: 'application/json',\n\t\t'Content-Type': 'application/json; charset=utf-8',\n\t\t'X-Frappe-Site-Name': window.location.hostname\n\t}\n\n\tif (window.csrf_token && window.csrf_token !== '{{ csrf_token }}') {\n\t\theaders['X-Frappe-CSRF-Token'] = window.csrf_token;\n\t}\n\n\tconst res = await fetch(`/api/method/markd.markd.api.${method}`, {\n\t\tmethod: 'POST',\n\t\theaders,\n\t\tbody: JSON.stringify(args)\n\t});\n\n\tif (res.ok) {\n\t\tconst data = await res.json();\n\t\tconsole.log(data)\n\t\tif (data.docs) {\n\t\t\treturn data;\n\t\t}\n\t\treturn data.message;\n\t} else {\n\t\tlet error = null;\n\t\tlet data = null;\n\t\ttry {\n\t\t\tdata = await res.json();\n\t\t\tif (data.exc) {\n\t\t\t\terror = JSON.parse(data.exc)[0];\n\t\t\t}\n\t\t} catch (e) {\n\t\t\terror = await res.text();\n\t\t}\n\t\tconsole.error(error);\n\t\treturn {\n\t\t\terror: true,\n\t\t\tdata\n\t\t};\n\t}\n}","import Vue from 'vue'\nimport App from './App.vue'\nimport './registerServiceWorker'\nimport router from './router'\nimport './assets/style.css';\nimport call from './assets/call';\nimport VueStringFilter from 'vue-string-filter';\nimport PortalVue from 'portal-vue'\nimport VueTippy, { TippyComponent } from \"vue-tippy\";\nimport Unicon from 'vue-unicons';\nimport { uniExternalLinkAlt, uniTrashAlt, uniTimes } from 'vue-unicons/src/icons'\nimport vueDebounce from 'vue-debounce'\n\nUnicon.add([uniExternalLinkAlt, uniTrashAlt, uniTimes])\nVue.use(Unicon)\n\nVue.use(vueDebounce)\n\n\nVue.use(VueTippy, {\n\tdirective: \"tippy\", // => v-tippy\n\tflipDuration: 0,\n\tarrow: true,\n\tanimation: 'scale',\n\tpopperOptions: {\n\t\t// modifiers: {\n\t\t// \tpreventOverflow: {\n\t\t// \t\tenabled: false\n\t\t// \t}\n\t\t// }\n\t}\n});\n\nVue.component(\"tippy\", TippyComponent);\n\nVue.use(PortalVue)\n\nVue.use(VueStringFilter);\nVue.prototype.$call = call;\nVue.config.productionTip = false\n\nVue.prototype.$eventHub = new Vue(); // Global event bus\n\n\nnew Vue({\n\trouter,\n\trender: h => h(App)\n}).$mount('#app')\n","import mod from \"-!../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Search.vue?vue&type=style&index=0&lang=scss&\"; export default mod; export * from \"-!../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Search.vue?vue&type=style&index=0&lang=scss&\"","import mod from \"-!../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--6-oneOf-1-0!../../node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/src/index.js??ref--6-oneOf-1-2!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./ArticlePreview.vue?vue&type=style&index=0&id=0cde1d86&scoped=true&lang=css&\"; export default mod; export * from \"-!../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--6-oneOf-1-0!../../node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/src/index.js??ref--6-oneOf-1-2!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./ArticlePreview.vue?vue&type=style&index=0&id=0cde1d86&scoped=true&lang=css&\""],"sourceRoot":""} -------------------------------------------------------------------------------- /markd/public/dashboard/manifest.json: -------------------------------------------------------------------------------- 1 | {"name":"dashboard","short_name":"dashboard","theme_color":"#4DBA87","icons":[{"src":"./img/icons/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"./img/icons/android-chrome-512x512.png","sizes":"512x512","type":"image/png"},{"src":"./img/icons/android-chrome-maskable-192x192.png","sizes":"192x192","type":"image/png","purpose":"maskable"},{"src":"./img/icons/android-chrome-maskable-512x512.png","sizes":"512x512","type":"image/png","purpose":"maskable"}],"start_url":".","display":"standalone","background_color":"#000000"} -------------------------------------------------------------------------------- /markd/public/dashboard/precache-manifest.32359028ecd51c22af442873dfd2c924.js: -------------------------------------------------------------------------------- 1 | self.__precacheManifest = (self.__precacheManifest || []).concat([ 2 | { 3 | "revision": "5762d7d1cc6fadf2ccf0", 4 | "url": "/assets/markd/dashboard/css/app.ece821f8.css" 5 | }, 6 | { 7 | "revision": "52ef6d3212f2230223dd049d8d080492", 8 | "url": "/assets/markd/dashboard/index.html" 9 | }, 10 | { 11 | "revision": "5762d7d1cc6fadf2ccf0", 12 | "url": "/assets/markd/dashboard/js/app.5d3fe79f.js" 13 | }, 14 | { 15 | "revision": "7ea608f06fe6c4c2a051", 16 | "url": "/assets/markd/dashboard/js/chunk-vendors.448aa4f4.js" 17 | }, 18 | { 19 | "revision": "af3442210705525bcba5cbbc7e4307bf", 20 | "url": "/assets/markd/dashboard/manifest.json" 21 | }, 22 | { 23 | "revision": "b6216d61c03e6ce0c9aea6ca7808f7ca", 24 | "url": "/assets/markd/dashboard/robots.txt" 25 | } 26 | ]); -------------------------------------------------------------------------------- /markd/public/dashboard/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /markd/public/dashboard/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); 15 | 16 | importScripts( 17 | "/assets/markd/dashboard/precache-manifest.32359028ecd51c22af442873dfd2c924.js" 18 | ); 19 | 20 | workbox.core.setCacheNameDetails({prefix: "dashboard"}); 21 | 22 | self.addEventListener('message', (event) => { 23 | if (event.data && event.data.type === 'SKIP_WAITING') { 24 | self.skipWaiting(); 25 | } 26 | }); 27 | 28 | /** 29 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 30 | * requests for URLs in the manifest. 31 | * See https://goo.gl/S9QRab 32 | */ 33 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 34 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 35 | -------------------------------------------------------------------------------- /markd/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/templates/__init__.py -------------------------------------------------------------------------------- /markd/templates/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/templates/pages/__init__.py -------------------------------------------------------------------------------- /markd/www/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scmmishra/markd/26e3fcb5d177785a1bd6af3a505a2abfb5729c55/markd/www/__init__.py -------------------------------------------------------------------------------- /markd/www/dashboard.html: -------------------------------------------------------------------------------- 1 | dashboard
-------------------------------------------------------------------------------- /markd/www/dashboard.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors 2 | # MIT License. See license.txt 3 | 4 | from __future__ import unicode_literals 5 | import frappe 6 | 7 | no_cache = 1 8 | 9 | def get_context(context): 10 | csrf_token = frappe.sessions.get_csrf_token() 11 | frappe.db.commit() 12 | context.csrf_token = csrf_token 13 | -------------------------------------------------------------------------------- /node_modules/.yarn-integrity: -------------------------------------------------------------------------------- 1 | { 2 | "systemParams": "darwin-x64-72", 3 | "modulesFolders": [], 4 | "flags": [], 5 | "linkedModules": [ 6 | "frappe-charts", 7 | "frappe-datatable" 8 | ], 9 | "topLevelPatterns": [], 10 | "lockfileEntries": {}, 11 | "files": [], 12 | "artifacts": {} 13 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | frappe 2 | readability-lxml -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from setuptools import setup, find_packages 3 | 4 | with open('requirements.txt') as f: 5 | install_requires = f.read().strip().split('\n') 6 | 7 | # get version from __version__ variable in markd/__init__.py 8 | from markd import __version__ as version 9 | 10 | setup( 11 | name='markd', 12 | version=version, 13 | description='A simple bookmarking app', 14 | author='Shivam Mishra', 15 | author_email='shivam@frappe.io', 16 | packages=find_packages(), 17 | zip_safe=False, 18 | include_package_data=True, 19 | install_requires=install_requires 20 | ) 21 | -------------------------------------------------------------------------------- /yarn-error.log: -------------------------------------------------------------------------------- 1 | Arguments: 2 | /Users/shivammishra/.nvm/versions/node/v12.18.1/bin/node /usr/local/Cellar/yarn/1.22.4/libexec/bin/yarn.js add tailwindcss 3 | 4 | PATH: 5 | /Users/shivammishra/.jenv/shims:/Users/shivammishra/.jenv/bin:/usr/local/opt/openjdk/bin:/Users/shivammishra/.nvm/versions/node/v12.18.1/bin:/Users/shivammishra/.pyenv/shims:/Applications/Postgres.app/Contents/Versions/12/bin/:/Users/shivammishra/Projects/nimo/node_modules/.bin:/usr/local/lib/node_modules/.bin:/usr/local/opt/sqlite/bin:/Users/shivammishra/.pyenv/bin:/usr/local/opt/openssl@1.1/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Applications/Postgres.app/Contents/Versions/latest/bin:/Users/shivammishra/bin 6 | 7 | Yarn version: 8 | 1.22.4 9 | 10 | Node version: 11 | 12.18.1 12 | 13 | Platform: 14 | darwin x64 15 | 16 | Trace: 17 | Error: getaddrinfo ENOTFOUND registry.yarnpkg.com 18 | at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:66:26) 19 | 20 | npm manifest: 21 | No manifest 22 | 23 | yarn manifest: 24 | No manifest 25 | 26 | Lockfile: 27 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 28 | # yarn lockfile v1 29 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | --------------------------------------------------------------------------------