├── packages └── leetcode-site-base │ ├── website │ ├── README.md │ ├── sidebars.json │ ├── .vscode │ │ └── settings.json │ ├── static │ │ ├── img │ │ │ ├── favicon.png │ │ │ ├── oss_logo.png │ │ │ ├── favicon │ │ │ │ └── favicon.ico │ │ │ └── docusaurus.svg │ │ ├── css │ │ │ ├── custom.css │ │ │ └── code.css │ │ ├── index.html │ │ └── js │ │ │ └── code-block-buttons.js │ ├── scripts │ │ ├── clear.js │ │ └── generateDocs.js │ ├── package.json │ ├── core │ │ └── Footer.js │ └── siteConfig.js │ ├── README.md │ ├── .dockerignore │ ├── Dockerfile │ ├── .gitignore │ └── docker-compose.yml ├── .github └── FUNDING.yml ├── images ├── login.png └── screenshot.png ├── src ├── logout.js ├── init.js ├── cli.js ├── download.js ├── utils.js └── leetcode.js ├── .vscode └── settings.json ├── .eslintrc.js ├── package.json ├── LICENSE ├── .gitignore ├── README.md └── yarn.lock /packages/leetcode-site-base/website/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/README.md: -------------------------------------------------------------------------------- 1 | # leetcode-site-base 2 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/.dockerignore: -------------------------------------------------------------------------------- 1 | */node_modules 2 | *.log 3 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/sidebars.json: -------------------------------------------------------------------------------- 1 | {"docs":{"Problems":[]}} -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [beizhedenglong] 4 | -------------------------------------------------------------------------------- /images/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beizhedenglong/leetcode-site-generator/HEAD/images/login.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beizhedenglong/leetcode-site-generator/HEAD/images/screenshot.png -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Leet", 4 | "repo" 5 | ] 6 | } -------------------------------------------------------------------------------- /src/logout.js: -------------------------------------------------------------------------------- 1 | const { removeConfig } = require('./utils'); 2 | 3 | module.exports = () => { 4 | removeConfig('cookies'); 5 | }; 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Leet", 4 | "csrfmiddlewaretoken", 5 | "csrftoken", 6 | "leetcode", 7 | "promisify" 8 | ] 9 | } -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beizhedenglong/leetcode-site-generator/HEAD/packages/leetcode-site-base/website/static/img/favicon.png -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/static/img/oss_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beizhedenglong/leetcode-site-generator/HEAD/packages/leetcode-site-base/website/static/img/oss_logo.png -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/static/img/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beizhedenglong/leetcode-site-generator/HEAD/packages/leetcode-site-base/website/static/img/favicon/favicon.ico -------------------------------------------------------------------------------- /packages/leetcode-site-base/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8.11.4 2 | 3 | WORKDIR /app/website 4 | 5 | EXPOSE 3000 35729 6 | COPY ./docs /app/docs 7 | COPY ./website /app/website 8 | RUN yarn install 9 | 10 | CMD ["yarn", "start"] 11 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules 4 | 5 | lib/core/metadata.js 6 | lib/core/MetadataBlog.js 7 | 8 | website/translated_docs 9 | website/build/ 10 | website/yarn.lock 11 | website/node_modules 12 | website/i18n/* 13 | website/problems.json -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | commonjs: true, 5 | es6: true, 6 | }, 7 | extends: 'airbnb-base', 8 | globals: { 9 | Atomics: 'readonly', 10 | SharedArrayBuffer: 'readonly', 11 | }, 12 | parserOptions: { 13 | ecmaVersion: 2018, 14 | }, 15 | rules: { 16 | 'import/prefer-default-export': 'off', 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/static/css/custom.css: -------------------------------------------------------------------------------- 1 | /* your custom css */ 2 | 3 | @media only screen and (min-device-width: 360px) and (max-device-width: 736px) { 4 | } 5 | 6 | @media only screen and (min-width: 1024px) { 7 | } 8 | 9 | @media only screen and (max-width: 1023px) { 10 | } 11 | 12 | @media only screen and (min-width: 1400px) { 13 | } 14 | 15 | @media only screen and (min-width: 1500px) { 16 | } -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | LeetCode Site Generator 11 | 12 | 13 | 14 | If you are not redirected automatically, follow this link. 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/scripts/clear.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const sidebars = require('../sidebars.json'); 4 | const { docDirPath, sidebarsPath } = require('./generateDocs'); 5 | 6 | sidebars.docs.Problems.forEach((titleSlug) => { 7 | const problemPath = path.join(docDirPath, `${titleSlug}.md`); 8 | if (fs.existsSync(problemPath)) { 9 | fs.unlinkSync(problemPath); 10 | } 11 | }); 12 | sidebars.docs.Problems = []; 13 | 14 | fs.writeFileSync(sidebarsPath, JSON.stringify(sidebars, null, 2)); 15 | -------------------------------------------------------------------------------- /src/init.js: -------------------------------------------------------------------------------- 1 | const shell = require('shelljs'); 2 | const path = require('path'); 3 | const ora = require('ora'); 4 | const fs = require('fs'); 5 | 6 | 7 | module.exports = () => { 8 | const destination = 'leetcode-site-base'; 9 | if (fs.existsSync(destination)) { 10 | console.error('Already has leetcode-site-base directory!'); 11 | return; 12 | } 13 | const websiteDirPath = path.join(__dirname, '..', 'packages', 'leetcode-site-base'); 14 | const spinner = ora('Copying files into leetcode-site-base...').start(); 15 | shell.cp('-r', websiteDirPath, destination); 16 | spinner.stop(); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | docusaurus: 5 | build: . 6 | ports: 7 | - 3000:3000 8 | - 35729:35729 9 | volumes: 10 | - ./docs:/app/docs 11 | - ./website/blog:/app/website/blog 12 | - ./website/core:/app/website/core 13 | - ./website/i18n:/app/website/i18n 14 | - ./website/pages:/app/website/pages 15 | - ./website/static:/app/website/static 16 | - ./website/sidebars.json:/app/website/sidebars.json 17 | - ./website/siteConfig.js:/app/website/siteConfig.js 18 | working_dir: /app/website 19 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "download": "leetcode-site download && npm run generate-docs", 4 | "generate-docs": "node ./scripts/generateDocs.js", 5 | "clear": "node ./scripts/clear.js", 6 | "start": "docusaurus-start", 7 | "build": "docusaurus-build", 8 | "publish-gh-pages": "docusaurus-publish", 9 | "write-translations": "docusaurus-write-translations", 10 | "version": "docusaurus-version", 11 | "rename-version": "docusaurus-rename-version" 12 | }, 13 | "devDependencies": { 14 | "docusaurus": "^1.7.3", 15 | "leetcode-site-generator": "*" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leetcode-site-generator", 3 | "version": "0.2.0", 4 | "main": "./src/download.js", 5 | "bin": { 6 | "leetcode-site": "./src/cli.js" 7 | }, 8 | "repository": "https://github.com/beizhedenglong/leetcode-site-generator.git", 9 | "author": "Victor Wang ", 10 | "license": "MIT", 11 | "dependencies": { 12 | "axios": "^0.18.0", 13 | "commander": "^2.20.0", 14 | "enquirer": "^2.3.0", 15 | "graphql-request": "^1.8.2", 16 | "inquirer": "^7.3.3", 17 | "node-fs-extra": "^0.8.2", 18 | "ora": "^3.4.0", 19 | "puppeteer": "^5.3.0", 20 | "puppeteer-extra": "^3.1.15", 21 | "puppeteer-extra-plugin-stealth": "^2.6.1", 22 | "request": "^2.88.0", 23 | "shelljs": "^0.8.3" 24 | }, 25 | "devDependencies": { 26 | "eslint": "^5.15.3", 27 | "eslint-config-airbnb-base": "^13.1.0", 28 | "eslint-plugin-import": "^2.16.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/core/Footer.js: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | class Footer extends React.Component { 4 | docUrl(doc, language) { 5 | const baseUrl = this.props.config.baseUrl; 6 | const docsUrl = this.props.config.docsUrl; 7 | const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; 8 | const langPart = `${language ? `${language}/` : ''}`; 9 | return `${baseUrl}${docsPart}${langPart}${doc}`; 10 | } 11 | 12 | pageUrl(doc, language) { 13 | const baseUrl = this.props.config.baseUrl; 14 | return baseUrl + (language ? `${language}/` : '') + doc; 15 | } 16 | 17 | render() { 18 | return ( 19 | 22 | ); 23 | } 24 | } 25 | 26 | module.exports = Footer; 27 | -------------------------------------------------------------------------------- /src/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const commander = require('commander'); 3 | const packageJson = require('../package.json'); 4 | const download = require('./download'); 5 | const init = require('./init'); 6 | const logout = require('./logout'); 7 | const { login } = require('./leetcode'); 8 | 9 | commander 10 | .version(packageJson.version); 11 | 12 | commander 13 | .command('download') 14 | .option('-a, --all', 'Download all your accepted code from LeetCode.') 15 | .description('Download your new accepted code from LeetCode.') 16 | .action(download); 17 | 18 | commander 19 | .command('init') 20 | .description('Generate your personal LeetCode website.') 21 | .action(init); 22 | 23 | commander 24 | .command('login') 25 | .description('Log in to your Leetcode account.') 26 | .action(login); 27 | 28 | commander 29 | .command('logout') 30 | .description('Log out of current account.') 31 | .action(logout); 32 | 33 | commander.parse(process.argv); 34 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/static/css/code.css: -------------------------------------------------------------------------------- 1 | /* "Copy" code block button */ 2 | pre { 3 | position: relative; 4 | } 5 | .description pre { 6 | background: #f7f9fa; 7 | padding: 10px 15px; 8 | color: #263238; 9 | line-height: 1.6; 10 | font-size: 13px; 11 | border-radius: 3px; 12 | font-family: 'SFMono-Regular',Consolas,'Liberation Mono',Menlo,Courier,monospace; 13 | font-size: 1em; 14 | overflow: auto; 15 | } 16 | 17 | pre .btnIcon { 18 | position: absolute; 19 | top: 4px; 20 | z-index: 2; 21 | cursor: pointer; 22 | border: 1px solid transparent; 23 | padding: 0; 24 | color: #fff; 25 | background-color: transparent; 26 | height: 30px; 27 | transition: all .25s ease-out; 28 | } 29 | 30 | pre .btnIcon:hover { 31 | text-decoration: none; 32 | } 33 | 34 | .btnIcon__body { 35 | align-items: center; 36 | display: flex; 37 | } 38 | 39 | .btnIcon svg { 40 | fill: currentColor; 41 | margin-right: .4em; 42 | } 43 | 44 | .btnIcon__label { 45 | font-size: 11px; 46 | } 47 | 48 | .btnClipboard { 49 | right: 10px; 50 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Victor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | docs 64 | 65 | problems.json 66 | .DS_Store 67 | -------------------------------------------------------------------------------- /src/download.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const ora = require('ora'); 3 | const { stringify } = require('./utils'); 4 | const { getAllACQuestions, getAcCode } = require('./leetcode'); 5 | 6 | const difference = (problemsA = [], problemsB = []) => { 7 | const map = problemsB.reduce((acc, problem) => { 8 | acc[problem.titleSlug] = true; 9 | return acc; 10 | }, {}); 11 | return problemsA.filter(problem => !map[problem.titleSlug]); 12 | }; 13 | const download = async (command) => { 14 | const problemsPath = 'problems.json'; 15 | let problems = []; 16 | let questions = await getAllACQuestions(); 17 | if (!command.all) { 18 | if (fs.existsSync(problemsPath)) { 19 | problems = JSON.parse(fs.readFileSync(problemsPath)); 20 | } 21 | questions = difference(questions, problems); 22 | } 23 | 24 | const spinner = ora('Downloading accepted code...\n').start(); 25 | const aux = async (xs = []) => { 26 | if (xs.length === 0) { 27 | return; 28 | } 29 | const current = xs.shift(); 30 | try { 31 | const { 32 | code, 33 | lang, 34 | } = await getAcCode(current.titleSlug); 35 | current.code = code; 36 | current.lang = lang; 37 | } catch (error) { 38 | console.error(error.message); 39 | } 40 | spinner.text = `${questions.length - xs.length}/${questions.length}: [${current.title}] has downloaded.`; 41 | problems.push(current); 42 | fs.writeFileSync(problemsPath, stringify(problems)); 43 | await aux(xs); 44 | }; 45 | await aux([...questions]); 46 | spinner.stop(); 47 | }; 48 | 49 | module.exports = download; 50 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('util'); 2 | const homedir = require('os').homedir(); 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | let request = require('request'); 6 | 7 | const parseCookie = response => response.headers['set-cookie'] 8 | .map((x = '') => x.split('; ')) 9 | .reduce((acc, item) => acc.concat(item)) 10 | .reduce((acc, item) => { 11 | const [key, value] = item.split('='); 12 | acc[key] = value; 13 | return acc; 14 | }, {}); 15 | 16 | request = promisify(request); 17 | request.post = promisify(request.post); 18 | 19 | const getHeaders = session => ({ 20 | 'Content-Type': 'application/json', 21 | 'x-csrftoken': session.csrftoken, 22 | Cookie: `LEETCODE_SESSION=${session.LEETCODE_SESSION};csrftoken=${session.csrftoken};`, 23 | }); 24 | 25 | const unicodeToChar = text => text.replace(/\\u[\dA-F]{4}/gi, 26 | match => String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16))); 27 | 28 | const configPath = path.join(homedir, '.leetcode-site-generator.json'); 29 | const getConfig = () => { 30 | try { 31 | const config = JSON.parse(fs.readFileSync(configPath)); 32 | return config; 33 | } catch (error) { 34 | return { 35 | country: undefined, 36 | cookies: undefined, 37 | }; 38 | } 39 | }; 40 | const stringify = data => JSON.stringify(data, null, 2); 41 | 42 | const setConfig = (payload = {}) => { 43 | const config = { 44 | ...getConfig(), 45 | ...payload, 46 | }; 47 | fs.writeFileSync(configPath, stringify(config)); 48 | }; 49 | 50 | const removeConfig = (key) => { 51 | const config = getConfig(); 52 | config[key] = undefined; 53 | fs.writeFileSync(configPath, stringify(config)); 54 | }; 55 | 56 | module.exports = { 57 | parseCookie, 58 | request, 59 | getHeaders, 60 | unicodeToChar, 61 | getConfig, 62 | setConfig, 63 | removeConfig, 64 | stringify, 65 | }; 66 | -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/static/js/code-block-buttons.js: -------------------------------------------------------------------------------- 1 | // Turn off ESLint for this file because it's sent down to users as-is. 2 | /* eslint-disable */ 3 | window.addEventListener('load', function () { 4 | function button(label, ariaLabel, icon, className) { 5 | const btn = document.createElement('button'); 6 | btn.classList.add('btnIcon', className); 7 | btn.setAttribute('type', 'button'); 8 | btn.setAttribute('aria-label', ariaLabel); 9 | btn.innerHTML = 10 | '
' + 11 | icon + 12 | '' + 13 | label + 14 | '' + 15 | '
'; 16 | return btn; 17 | } 18 | 19 | function addButtons(codeBlockSelector, btn) { 20 | document.querySelectorAll(codeBlockSelector).forEach(function (code) { 21 | code.parentNode.appendChild(btn.cloneNode(true)); 22 | }); 23 | } 24 | 25 | const copyIcon = 26 | ''; 27 | 28 | addButtons( 29 | '.hljs', 30 | button('Copy', 'Copy code to clipboard', copyIcon, 'btnClipboard'), 31 | ); 32 | 33 | const clipboard = new ClipboardJS('.btnClipboard', { 34 | target: function (trigger) { 35 | return trigger.parentNode.querySelector('code'); 36 | }, 37 | }); 38 | 39 | clipboard.on('success', function (event) { 40 | event.clearSelection(); 41 | const textEl = event.trigger.querySelector('.btnIcon__label'); 42 | textEl.textContent = 'Copied'; 43 | setTimeout(function () { 44 | textEl.textContent = 'Copy'; 45 | }, 2000); 46 | }); 47 | }); -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/scripts/generateDocs.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const problems = require('../problems.json'); 4 | const sidebars = require('../sidebars.json'); 5 | 6 | const toDoc = ({ 7 | title, 8 | titleSlug, 9 | lang = '', 10 | code, 11 | content, 12 | }) => { 13 | const str = ( 14 | // eslint-disable-next-line 15 | `--- 16 | id: ${titleSlug} 17 | title: ${title} 18 | sidebar_label: ${title} 19 | --- 20 | ## Description 21 |
22 | ${content} 23 |
24 | 25 | ## Solution(${lang}) 26 | \`\`\`${lang} 27 | ${code} 28 | \`\`\`` 29 | ); 30 | return str; 31 | }; 32 | const indexPage = indexDoc => ( 33 | ` 34 | 35 | 36 | 37 | 38 | 39 | 42 | LeetCode Site Generator 43 | 44 | 45 | 46 | If you are not redirected automatically, follow this link. 47 | 48 | 49 | ` 50 | ); 51 | 52 | const docDirPath = path.join(__dirname, '..', '..', 'docs'); 53 | const sidebarsPath = path.join(__dirname, '..', 'sidebars.json'); 54 | 55 | if (!fs.existsSync(docDirPath)) { 56 | fs.mkdirSync(docDirPath); 57 | } 58 | sidebars.docs.Problems = []; 59 | problems.forEach((problem) => { 60 | const filename = `${problem.titleSlug}.md`; 61 | fs.writeFile(path.join(docDirPath, filename), toDoc(problem), (err) => { 62 | if (err) { 63 | console.error(`Write ${filename} error`); 64 | } 65 | }); 66 | sidebars.docs.Problems.push(problem.titleSlug); 67 | fs.writeFileSync(sidebarsPath, JSON.stringify(sidebars, null, 2)); 68 | }); 69 | const indexDoc = sidebars.docs.Problems[0]; 70 | const staticPath = path.join(__dirname, '..', 'static'); 71 | if (indexDoc) { 72 | fs.writeFile(path.join(staticPath, 'index.html'), indexPage(indexDoc), (err) => { 73 | if (err) { 74 | console.error('Write index.html error'); 75 | } 76 | }); 77 | } 78 | 79 | module.exports = { 80 | docDirPath, 81 | sidebarsPath, 82 | }; 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeetCode Site Generator 2 | Generate your personal LeetCode website with one command! 3 | 4 | ## Example Website 5 | [leetcode-solutions](https://beizhedenglong.github.io/leetcode-solutions/) 6 | 7 | [![screenshot](./images/screenshot.png)](https://beizhedenglong.github.io/leetcode-solutions/) 8 | 9 | ## Requirements 10 | - Make sure you have the recent version of [`node.js`](https://nodejs.org) installed. 11 | - [`yarn`](https://yarnpkg.com/en/)(optional), you can use `npm`. 12 | 13 | 14 | ## Features 15 | - Support both `leetcode.com` and `leetcode-cn.com` accounts. 16 | 17 | ## Installation 18 | 19 | `yarn global add leetcode-site-generator` or `npm i -g leetcode-site-generator` 20 | 21 | ## Usage 22 | 23 | 1. Run installation script: `leetcode-site init`, This will create a project called `leet-site-base` on your current directory. 24 | 2. Go to the `website` directory of `leet-site-base`, run `yarn download`. It will open a popup window and ask you to input your LeetCode username and password. 25 | ![login](./images/login.png) 26 | 3. Waiting for downloading process finished, then run `yarn & yarn start`. 27 | 28 | ## Publish to Github pages 29 | 1. Change the following keys in `siteConfig.js` 30 | ```js 31 | const siteConfig = { 32 | // ... 33 | url: 'https://beizhedenglong.github.io', // Your website URL 34 | baseUrl: '/leetcode-site-generator/', // Base URL for your project 35 | projectName: 'leetcode-site-generator', // Your project name 36 | organizationName: 'beizhedenglong', // Your github username 37 | // ... 38 | } 39 | ``` 40 | 41 | 2. Run `GIT_USER= CURRENT_BRANCH=master USE_SSH=true yarn run publish-gh-pages` 42 | 43 | 44 | ## List of commands 45 | 46 | ```md 47 | Usage: leetcode-site [options] [command] 48 | 49 | Options: 50 | -V, --version output the version number 51 | -h, --help output usage information 52 | 53 | Commands: 54 | download [options] Download your new accepted code from LeetCode. 55 | init Generate your personal LeetCode website. 56 | login Log in to your Leetcode account. 57 | logout Log out of current account. 58 | ``` 59 | 60 | ### download 61 | 62 | ```md 63 | Usage: download [options] 64 | 65 | Download your new accepted code from LeetCode. 66 | 67 | Options: 68 | -a, --all Download all your accepted code from LeetCode. 69 | -h, --help output usage information 70 | ``` -------------------------------------------------------------------------------- /packages/leetcode-site-base/website/siteConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | // See https://docusaurus.io/docs/site-config for all the possible 9 | // site configuration options. 10 | 11 | // List of projects/orgs using your project for the users page. 12 | const sidebars = require('./sidebars.json'); 13 | 14 | const users = [ 15 | { 16 | caption: 'User1', 17 | // You will need to prepend the image path with your baseUrl 18 | // if it is not '/', like: '/test-site/img/docusaurus.svg'. 19 | image: '/img/docusaurus.svg', 20 | infoLink: 'https://www.facebook.com', 21 | pinned: true, 22 | }, 23 | ]; 24 | 25 | const repoUrl = 'https://github.com/beizhedenglong/leetcode-site-generator'; 26 | 27 | const siteConfig = { 28 | title: 'LeetCode Site Generator', // Title for your website. 29 | tagline: 'Generate your personal LeetCode website with one command!', 30 | url: 'https://beizhedenglong.github.io', // Your website URL 31 | baseUrl: '/leetcode-site-generator/', // Base URL for your project */ 32 | // For github.io type URLs, you would set the url and baseUrl like: 33 | // url: 'https://facebook.github.io', 34 | // baseUrl: '/test-site/', 35 | 36 | // Used for publishing and more 37 | projectName: 'leetcode-site-generator', 38 | // organizationName: 'facebook', 39 | // For top-level user or org sites, the organization is still the same. 40 | // e.g., for the https://JoelMarcey.github.io site, it would be set like... 41 | organizationName: 'beizhedenglong', 42 | 43 | // For no header links in the top nav bar -> headerLinks: [], 44 | headerLinks: [ 45 | { 46 | doc: sidebars.docs.Problems[0], 47 | label: 'Problems', 48 | }, 49 | { 50 | href: repoUrl, 51 | label: 'GitHub', 52 | }, 53 | ], 54 | 55 | // If you have users set above, you add it here: 56 | users, 57 | 58 | /* path to images for header/footer */ 59 | headerIcon: 'img/docusaurus.svg', 60 | footerIcon: 'img/docusaurus.svg', 61 | favicon: 'img/favicon.png', 62 | 63 | /* Colors for website */ 64 | colors: { 65 | primaryColor: '#2E8555', 66 | secondaryColor: '#205C3B', 67 | }, 68 | 69 | /* Custom fonts for website */ 70 | /* 71 | fonts: { 72 | myFont: [ 73 | "Times New Roman", 74 | "Serif" 75 | ], 76 | myOtherFont: [ 77 | "-apple-system", 78 | "system-ui" 79 | ] 80 | }, 81 | */ 82 | 83 | // This copyright info is used in /core/Footer.js and blog RSS/Atom feeds. 84 | copyright: `Copyright © ${new Date().getFullYear()} Your Name or Your Company Name`, 85 | 86 | highlight: { 87 | // Highlight.js theme to use for syntax highlighting in code blocks. 88 | theme: 'atom-one-dark', 89 | }, 90 | 91 | // Add custom scripts here that would be placed in