diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a49c9c64..eed4b4ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,10 @@ jobs: - run: npm run bundle:min - run: npm run doc + - working-directory: core + run: | + npm run type-check + - name: Generate Contributors Images uses: jaywcjlove/github-action-contributors@main with: @@ -28,22 +32,29 @@ jobs: output: build/CONTRIBUTORS.svg avatarSize: 42 + - name: Create Tag + id: create_tag + uses: jaywcjlove/create-tag-action@v1.3.6 + with: + package-path: ./core/package.json + + - name: get tag version + id: tag_version + uses: jaywcjlove/changelog-generator@v1.5.6 + - name: Deploy uses: peaceiris/actions-gh-pages@v3 if: github.ref == 'refs/heads/main' with: + commit_message: ${{steps.tag_version.outputs.tag}} ${{ github.event.head_commit.message }} github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./build - - - name: Create Tag - id: create_tag - uses: jaywcjlove/create-tag-action@v1.3.5 - with: - package-path: ./package.json + publish_dir: ./www/build + user_name: 'github-actions[bot]' + user_email: 'github-actions[bot]@users.noreply.github.com' - name: Generate Changelog id: changelog - uses: jaywcjlove/changelog-generator@v1.4.8 + uses: jaywcjlove/changelog-generator@v1.5.6 with: token: ${{ secrets.GITHUB_TOKEN }} head-ref: ${{steps.create_tag.outputs.version}} @@ -69,5 +80,9 @@ jobs: ${{ steps.changelog.outputs.changelog }} - - run: npm install @jsdevtools/npm-publish -g - - run: npm-publish --token="${{ secrets.NPM_TOKEN }}" ./package.json \ No newline at end of file + - name: 📦 @uiw/react-heat-map publish to NPM + uses: JS-DevTools/npm-publish@v1 + with: + token: ${{ secrets.NPM_TOKEN }} + package: ./core/package.json + diff --git a/.gitignore b/.gitignore index de52cdba..46e6931a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ cjs esm +lib build dist node_modules diff --git a/.kktrc.ts b/.kktrc.ts deleted file mode 100644 index 9272640b..00000000 --- a/.kktrc.ts +++ /dev/null @@ -1,77 +0,0 @@ -import path from 'path'; -import webpack, { Configuration } from 'webpack'; -import { LoaderConfOptions } from 'kkt'; -import lessModules from '@kkt/less-modules'; -import rawModules from '@kkt/raw-modules'; -import scopePluginOptions from '@kkt/scope-plugin-options'; -import pkg from './package.json'; - -export default (conf: Configuration, env: 'development' | 'production', options: LoaderConfOptions) => { - conf = lessModules(conf, env, options); - if (options.bundle) { - conf.output!.library = '@uiw/react-heat-map'; - conf.externals = { - react: { - root: 'React', - commonjs2: 'react', - commonjs: 'react', - amd: 'react', - }, - }; - } else { - conf = scopePluginOptions(conf, env, { - ...options, - allowedFiles: [path.resolve(process.cwd(), 'README.md')], - }); - conf = rawModules(conf, env, { ...options }); - // Get the project version. - conf.plugins!.push( - new webpack.DefinePlugin({ - VERSION: JSON.stringify(pkg.version), - }), - ); - /** https://github.com/uiwjs/react-code-preview/issues/94 */ - conf.module!.exprContextCritical = false; - if (env === 'production') { - conf.output = { ...conf.output, publicPath: './' }; - conf.optimization = { - ...conf.optimization, - splitChunks: { - cacheGroups: { - reactvendor: { - test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/, - name: 'react-vendor', - chunks: 'all', - }, - babelstandalone: { - test: /[\\/]node_modules[\\/](@babel[\\/]standalone)[\\/]/, - name: 'babel-standalone-vendor', - chunks: 'all', - }, - prismjs: { - test: /[\\/]node_modules[\\/](refractor)[\\/]/, - name: 'refractor-vendor', - chunks: 'all', - }, - codemirror: { - test: /[\\/]node_modules[\\/](@codemirror)[\\/]/, - name: 'codemirror-vendor', - chunks: 'all', - }, - uiw: { - test: /[\\/]node_modules[\\/](@uiw)[\\/]/, - name: 'uiw-vendor', - chunks: 'all', - }, - parse5: { - test: /[\\/]node_modules[\\/](parse5)[\\/]/, - name: 'parse5-vendor', - chunks: 'all', - }, - }, - }, - }; - } - } - return conf; -}; diff --git a/README.md b/README.md index 375c06c2..63e1a027 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,6 @@ Basic usage example, Please pay warning to the time setting. ⚠️ Example: ~~`2016-01-11`~~ -> `2016/01/11`, Support `Safari` - ```jsx import ReactDOM from 'react-dom'; import HeatMap from '@uiw/react-heat-map'; @@ -284,6 +283,10 @@ ReactDOM.render(, _mount_); Runs the project in development mode. +```bash +npm i +``` + ```bash # Step 1, run first, listen to the component compile and output the .js file # listen for compilation output type .d.ts file @@ -298,6 +301,7 @@ Builds the app for production to the build folder. ```bash npm run build +npm run doc ``` The build is minified and the filenames include the hashes. diff --git a/core/.kktrc.ts b/core/.kktrc.ts new file mode 100644 index 00000000..076f5cab --- /dev/null +++ b/core/.kktrc.ts @@ -0,0 +1,22 @@ +// import path from 'path'; +import { Configuration } from 'webpack'; +import { LoaderConfOptions } from 'kkt'; +import lessModules from '@kkt/less-modules'; +// import rawModules from '@kkt/raw-modules'; +// import pkg from './package.json'; + +export default (conf: Configuration, env: 'production' | 'development', options: LoaderConfOptions) => { + conf = lessModules(conf, env, options); + if (options.bundle) { + conf.output!.library = '@uiw/react-heat-map'; + conf.externals = { + react: { + root: 'React', + commonjs2: 'react', + commonjs: 'react', + amd: 'react', + }, + }; + } + return conf; +}; diff --git a/core/README.md b/core/README.md new file mode 100644 index 00000000..9d2f5150 --- /dev/null +++ b/core/README.md @@ -0,0 +1,313 @@ +HeatMap 日历热图 +=== + + +[![Build & Deploy](https://github.com/uiwjs/react-heat-map/actions/workflows/ci.yml/badge.svg)](https://github.com/uiwjs/react-heat-map/actions/workflows/ci.yml) +[![Coverage Status](https://img.shields.io/npm/dm/@uiw/react-heat-map.svg?style=flat)](https://www.npmjs.com/package/@uiw/react-heat-map) +[![npm version](https://img.shields.io/npm/v/@uiw/react-heat-map.svg)](https://www.npmjs.com/package/@uiw/react-heat-map) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@uiw/react-heat-map)](https://bundlephobia.com/result?p=@uiw/react-heat-map) +[![Open in Gitpod](https://shields.io/badge/Open%20in-Gitpod-green?logo=Gitpod)](https://gitpod.io/#https://github.com/uiwjs/react-codemirror) +[![jsDelivr CDN](https://data.jsdelivr.com/v1/package/npm/@uiw/react-heat-map/badge?style=rounded)](https://www.jsdelivr.com/package/npm/@uiw/react-heat-map) + + +A lightweight calendar heatmap react component built on SVG, customizable version of GitHub's contribution graph. Try it out on [website example](https://uiwjs.github.io/react-heat-map/). + +## Install + +```bash +# Not dependent on uiw. +npm install @uiw/react-heat-map --save +``` + +## Basic Usage + +Basic usage example, Please pay warning to the time setting. + +⚠️ Example: ~~`2016-01-11`~~ -> `2016/01/11`, Support `Safari` + +```jsx mdx:preview +import React from 'react'; +import HeatMap from '@uiw/react-heat-map'; + +const value = [ + { date: '2016/01/11', count: 2 }, + { date: '2016/01/12', count: 20 }, + { date: '2016/01/13', count: 10 }, + ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx, content: '' })), + { date: '2016/04/11', count: 2 }, + { date: '2016/05/01', count: 5 }, + { date: '2016/05/02', count: 5 }, + { date: '2016/05/04', count: 11 }, +]; + +const Demo = () => { + return ( +
+ +
+ ) +}; + +export default Demo +``` + +## Set Color + +Set the theme color style. + +```jsx mdx:preview +import React from 'react'; +import HeatMap from '@uiw/react-heat-map'; + +const value = [ + { date: '2016/01/11', count:2 }, + { date: '2016/04/12', count:2 }, + { date: '2016/05/01', count:5 }, + { date: '2016/05/02', count:5 }, + { date: '2016/05/03', count:1 }, + { date: '2016/05/04', count:11 }, + { date: '2016/05/08', count:32 }, +]; + +const Demo = () => { + return ( + + ) +}; +export default Demo +``` + +## Set Rect Style + +Set the radius of the rect. + +```jsx mdx:preview +import React, { useState } from 'react'; +import HeatMap from '@uiw/react-heat-map'; + +const value = [ + { date: '2016/01/11', count:2 }, + ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx })), + ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx })), + { date: '2016/04/12', count:2 }, + { date: '2016/05/01', count:5 }, + { date: '2016/05/02', count:5 }, + { date: '2016/05/03', count:1 }, + { date: '2016/05/04', count:11 }, + { date: '2016/05/08', count:32 }, +]; + +const Demo = () => { + const [range, setRange] = useState(5) + return ( +
+ setRange(e.target.value)} /> {range} + } + rectProps={{ + rx: range + }} + /> +
+ ) +}; +export default Demo +``` + +## Tooltip + +A simple text popup tip. + +```jsx mdx:preview +import React from 'react'; +import Tooltip from '@uiw/react-tooltip'; +import HeatMap from '@uiw/react-heat-map'; + +const value = [ + { date: '2016/01/11', count:2 }, + ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx, })), + ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx, })), + { date: '2016/04/12', count:2 }, + { date: '2016/05/01', count:5 }, + { date: '2016/05/02', count:5 }, + { date: '2016/05/03', count:1 }, + { date: '2016/05/04', count:11 }, + { date: '2016/05/08', count:32 }, +]; + +const Demo = () => { + return ( + { + // if (!data.count) return ; + return ( + + + + ); + }} + /> + ) +}; +export default Demo +``` + +## Show/Hide Legend + +```jsx mdx:preview +import React, { useState } from 'react'; +import HeatMap from '@uiw/react-heat-map'; + +const value = [ + { date: '2016/01/11', count:2 }, + ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx })), + ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx })), + { date: '2016/04/12', count:2 }, + { date: '2016/05/01', count:5 }, + { date: '2016/05/02', count:5 }, + { date: '2016/05/03', count:1 }, + { date: '2016/05/04', count:11 }, + { date: '2016/05/08', count:32 }, +]; + +const Demo = () => { + const [size, setSize] = useState(0) + return ( +
+ + +
+ ) +}; +export default Demo +``` + +## Selected Rect + +```jsx mdx:preview +import React, { useState } from 'react'; +import HeatMap from '@uiw/react-heat-map'; + +const value = [ + { date: '2016/01/11', count:2 }, + ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx })), + ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx })), + { date: '2016/04/12', count:2 }, + { date: '2016/05/01', count:5 }, + { date: '2016/05/02', count:5 }, + { date: '2016/05/03', count:1 }, + { date: '2016/05/04', count:11 }, + { date: '2016/05/08', count:32 }, +]; + +const Demo = () => { + const [selected, setSelected] = useState('') + return ( +
+ { + if (selected !== '') { + props.opacity = data.date === selected ? 1 : 0.45 + } + return ( + { + setSelected(data.date === selected ? '' : data.date); + }} /> + ); + }} + /> +
+ ) +}; +export default Demo +``` + +## Props + +| Property | Description | Type | Default | +| ---- | ---- | ---- | ---- | +| value | Data to be displayed, **required** | Array | `[]` | +| rectSize | Grid size | number | `11` | +| legendCellSize | Size of the legend cells, in pixel. Value equal to `0` hide legend. | number | `11` | +| startDate | Start date | Date | `new Date()` | +| endDate | End date | Date | - | +| space | Interval between grid sizes | number | `2` |  +| rectProps | Grid node attribute settings | `React.SVGProps` | `2` | +| weekLabels | Week display | string[] | `['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']` |  +| monthLabels | Month display | string[] | `['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']` |  +| panelColors | Backgroud color of active colors | `Record` | `{ 0: '#EBEDF0', 8: '#7BC96F', 4: '#C6E48B', 12: '#239A3B', 32: '#196127' }` |  +| rectRender | Single `day` block re-render | `(data: E & { key: number }, valueItem: HeatMapValue & { date: string, column: number, row: number, index: number }) => React.ReactElement` | - | +| legendRender | Single `legend` block re-render | `(props: React.SVGProps) => React.ReactNode` | - | + +## Development + +**`development`** + +Runs the project in development mode. + +```bash +# Step 1, run first, listen to the component compile and output the .js file +# listen for compilation output type .d.ts file +npm run watch +# Step 2, development mode, listen to compile preview website instance +npm run start +``` + +**`production`** + +Builds the app for production to the build folder. + +```bash +npm run build +``` + +The build is minified and the filenames include the hashes. +Your app is ready to be deployed! + +## Contributors + +As always, thanks to our amazing contributors! + + + + + +Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors). + +## License + +Licensed under the MIT License. diff --git a/core/package.json b/core/package.json new file mode 100644 index 00000000..650e45c7 --- /dev/null +++ b/core/package.json @@ -0,0 +1,47 @@ +{ + "name": "@uiw/react-heat-map", + "version": "2.0.3", + "description": "React component create calendar heatmap to visualize time series data, a la github contribution graph.", + "homepage": "https://uiwjs.github.io/react-heat-map/", + "main": "./lib/index.js", + "module": "./esm/index.js", + "author": "kenny wang ", + "license": "MIT", + "scripts": { + "css:build": "compile-less -d src -o esm", + "css:watch": "compile-less -d src -o esm --watch", + "css:build:dist": "compile-less -d src --combine dist.css --rm-global", + "bundle": "ncc build src/index.tsx --target web --filename heat-map", + "bundle:watch": "ncc watch src/index.tsx --target web --filename heat-map", + "bundle:min": "ncc build src/index.tsx --target web --filename heat-map --minify", + "watch": "tsbb watch & npm run css:watch", + "build": "tsbb build && npm run css:build && npm run css:build:dist", + "type-check": "tsc --noEmit", + "test": "tsbb test --env=jsdom", + "coverage": "tsbb test --env=jsdom --coverage --bail" + }, + "repository": { + "type": "git", + "url": "https://github.com/uiwjs/react-heat-map.git" + }, + "files": [ + "dist.css", + "dist", + "src", + "cjs", + "esm" + ], + "keywords": [ + "react", + "heat-map", + "react-heat-map", + "uiw", + "uiwjs", + "code" + ], + "peerDependencies": { + "@babel/runtime": ">=7.10.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } +} diff --git a/src/LabelsMonth.tsx b/core/src/LabelsMonth.tsx similarity index 100% rename from src/LabelsMonth.tsx rename to core/src/LabelsMonth.tsx diff --git a/src/LabelsWeek.tsx b/core/src/LabelsWeek.tsx similarity index 100% rename from src/LabelsWeek.tsx rename to core/src/LabelsWeek.tsx diff --git a/src/Legend.tsx b/core/src/Legend.tsx similarity index 94% rename from src/Legend.tsx rename to core/src/Legend.tsx index 9c3e3caa..abf11e80 100644 --- a/src/Legend.tsx +++ b/core/src/Legend.tsx @@ -7,7 +7,7 @@ export interface LegendProps extends RectProps { rectSize: SVGProps['rectSize']; leftPad: number; legendCellSize: number; - legendRender?: (props: RectProps) => React.ReactElement | void; + legendRender?: (props: RectProps) => React.ReactElement; topPad: number; space: number; } diff --git a/src/Rect.tsx b/core/src/Rect.tsx similarity index 100% rename from src/Rect.tsx rename to core/src/Rect.tsx diff --git a/src/SVG.tsx b/core/src/SVG.tsx similarity index 100% rename from src/SVG.tsx rename to core/src/SVG.tsx diff --git a/src/index.tsx b/core/src/index.tsx similarity index 100% rename from src/index.tsx rename to core/src/index.tsx diff --git a/src/style/index.less b/core/src/style/index.less similarity index 100% rename from src/style/index.less rename to core/src/style/index.less diff --git a/src/utils.ts b/core/src/utils.ts similarity index 100% rename from src/utils.ts rename to core/src/utils.ts diff --git a/src/tsconfig.json b/core/tsconfig.json similarity index 57% rename from src/tsconfig.json rename to core/tsconfig.json index bff4689f..cf6fbb69 100644 --- a/src/tsconfig.json +++ b/core/tsconfig.json @@ -1,7 +1,8 @@ { "extends": "../tsconfig", + "include": ["src", ".kktrc.ts"], "compilerOptions": { - "outDir": "../cjs", + "baseUrl": ".", "noEmit": false } -} \ No newline at end of file +} diff --git a/lerna.json b/lerna.json new file mode 100644 index 00000000..e2da6adc --- /dev/null +++ b/lerna.json @@ -0,0 +1,5 @@ +{ + "version": "2.0.3", + "packages": ["core", "www"], + "useWorkspaces": true +} diff --git a/package.json b/package.json index a6f082ea..70e634c1 100644 --- a/package.json +++ b/package.json @@ -1,94 +1,43 @@ { - "name": "@uiw/react-heat-map", - "version": "2.0.3", - "description": "React component create calendar heatmap to visualize time series data, a la github contribution graph.", - "homepage": "https://uiwjs.github.io/react-heat-map/", - "main": "cjs/index.js", - "module": "esm/index.js", + "private": true, "scripts": { + "⬇️⬇️⬇️⬇️⬇️ package ⬇️⬇️⬇️⬇️⬇️": "▼▼▼▼▼ package ▼▼▼▼▼", + "watch": "npm run-script watch --workspace @uiw/react-heat-map", + "build": "npm run-script build --workspace @uiw/react-heat-map", + "bundle": "npm run-script bundle --workspace @uiw/react-heat-map", + "bundle:min": "npm run-script bundle:min --workspace @uiw/react-heat-map", + "doc": "npm run-script build --workspace www", + "start": "npm run-script start --workspace www", + "⬆️⬆️⬆️⬆️⬆️ package ⬆️⬆️⬆️⬆️⬆️": "▲▲▲▲▲ package ▲▲▲▲▲", "prepare": "npm run build", - "doc": "kkt build --app-src ./website", - "start": "kkt start --app-src ./website", - "css:build": "compile-less -d src -o esm", - "css:watch": "compile-less -d src -o esm --watch", - "css:build:dist": "compile-less -d src --combine dist.css --rm-global", - "bundle": "ncc build src/index.tsx --target web --filename heat-map", - "bundle:min": "ncc build src/index.tsx --target web --filename heat-map --minify", - "watch": "tsbb watch & npm run css:watch", - "build": "tsbb build && npm run css:build && npm run css:build:dist", "prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"", "type-check": "tsc --noEmit", "map": "source-map-explorer build/static/js/*.js --html build/website-result.html" }, - "repository": { - "type": "git", - "url": "https://github.com/uiwjs/react-heat-map.git" - }, "author": "kenny wong ", "license": "MIT", - "keywords": [ - "react", - "heat-map", - "react-heat-map", - "uiw", - "uiwjs", - "code" - ], "lint-staged": { "*.{js,jsx,tsx,ts,less,md,json}": [ "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"" ] }, - "files": [ - "dist.css", - "dist", - "src", - "cjs", - "esm" - ], - "peerDependencies": { - "@babel/runtime": ">=7.10.0", - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - }, "devDependencies": { "@kkt/less-modules": "~7.1.1", - "@kkt/ncc": "~1.0.8", - "@kkt/raw-modules": "~7.1.1", - "@kkt/scope-plugin-options": "~7.1.1", - "@types/react": "~17.0.39", - "@types/react-dom": "~17.0.11", - "@uiw/react-code-preview": "~4.0.5", - "@uiw/react-github-corners": "~1.5.3", - "@uiw/react-markdown-preview": "~3.4.7", - "@uiw/react-tooltip": "~4.12.2", - "@uiw/reset.css": "~1.0.5", - "compile-less-cli": "~1.8.11", - "husky": "~7.0.4", + "@kkt/ncc": "~1.0.9", + "compile-less-cli": "~1.8.13", + "husky": "~8.0.0", "kkt": "~7.1.5", - "lint-staged": "~12.3.4", - "prettier": "~2.5.1", - "react": "~17.0.2", - "react-dom": "~17.0.2", - "source-map-explorer": "~2.5.2", + "lerna": "^5.1.2", + "lint-staged": "~13.0.0", + "prettier": "~2.6.0", + "react-test-renderer": "~18.1.0", "tsbb": "~3.7.0" }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "workspaces": [ + "core", + "www" + ], + "engines": { + "node": ">=16.0.0" } } diff --git a/tsconfig.json b/tsconfig.json index c3848f61..b1fca474 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,8 +16,6 @@ "baseUrl": ".", "jsx": "react-jsx", "noFallthroughCasesInSwitch": true, - "noEmit": true, - "types": ["jest", "node"] - }, - "include": ["website", "src", ".kktrc.ts"] + "noEmit": true + } } diff --git a/website/App.tsx b/website/App.tsx deleted file mode 100644 index 71c00945..00000000 --- a/website/App.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { useRef, useEffect, useState } from 'react'; -import GitHubCorners from '@uiw/react-github-corners'; -import MarkdownPreview from '@uiw/react-markdown-preview'; -import Tooltip from '@uiw/react-tooltip'; -import Code from './Code'; -import HeatMap from '../'; -import pkg from '../package.json'; -import Example from './Example'; -import logo from './logo.svg'; -import styles from './App.module.less'; -import MDStr from '../README.md'; - -const getCodeStr = (data: any[] = [], code: string = '') => { - data.forEach((node) => { - if (node.type === 'text') { - code += node.value; - } else if (node.children && Array.isArray(node.children)) { - code += getCodeStr(node.children); - } - }); - return code; -}; - -const App: React.FC = () => { - return ( -
- -
- react logo -

- React component create calendar heatmap to visualize time series data, a la github contribution graph. -

- -
- { - const { noPreview, noScroll, bgWhite, noCode, codeSandbox, codePen } = props as any; - if (inline) { - return ; - } - const config = { noPreview, noScroll, bgWhite, noCode, codeSandbox, codePen } as any; - if (Object.keys(config).filter((name) => config[name] !== undefined).length === 0) { - return ; - } - return ( - - ); - }, - }} - /> -
- ); -}; - -export default App; diff --git a/website/index.tsx b/website/index.tsx deleted file mode 100644 index c6746ebd..00000000 --- a/website/index.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import ReactDOM from 'react-dom'; -import '@uiw/reset.css/reset.css'; -import App from './App'; - -ReactDOM.render(, document.getElementById('root')); diff --git a/www/.kktrc.ts b/www/.kktrc.ts new file mode 100644 index 00000000..9104e6a2 --- /dev/null +++ b/www/.kktrc.ts @@ -0,0 +1,84 @@ +import path from 'path'; +import webpack, { Configuration } from 'webpack'; +import { LoaderConfOptions } from 'kkt'; +import lessModules from '@kkt/less-modules'; +import scopePluginOptions from '@kkt/scope-plugin-options'; +import { mdCodeModulesLoader } from 'markdown-react-code-preview-loader'; +import pkg from './package.json'; + +export default (conf: Configuration, env: 'production' | 'development', options: LoaderConfOptions) => { + conf = lessModules(conf, env, options); + conf = mdCodeModulesLoader(conf); + conf = scopePluginOptions(conf, env, { + ...options, + allowedFiles: [path.resolve(process.cwd(), 'README.md')], + }); + // Get the project version. + conf.plugins!.push( + new webpack.DefinePlugin({ + VERSION: JSON.stringify(pkg.version), + }), + ); + conf.module!.exprContextCritical = false; + if (env === 'production') { + conf.optimization = { + ...conf.optimization, + splitChunks: { + cacheGroups: { + reactvendor: { + test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/, + name: 'react-vendor', + chunks: 'all', + }, + katex: { + test: /[\\/]node_modules[\\/](katex)[\\/]/, + name: 'katex-vendor', + chunks: 'all', + }, + mermaid: { + test: /[\\/]node_modules[\\/](mermaid)[\\/]/, + name: 'mermaid-vendor', + chunks: 'all', + }, + dagred3: { + test: /[\\/]node_modules[\\/](dagre-d3)[\\/]/, + name: 'dagre-d3-vendor', + chunks: 'all', + }, + momentlodash: { + test: /[\\/]node_modules[\\/](moment-mini|lodash|d3-array|d3-geo|d3-shape|dagre)[\\/]/, + name: 'momentlodash-vendor', + chunks: 'all', + }, + d3: { + test: /[\\/]node_modules[\\/](d3-\w+(-?\w+))[\\/]/, + name: 'd3-vendor', + chunks: 'all', + }, + micromark: { + test: /[\\/]node_modules[\\/](micromark)[\\/]/, + name: 'micromark-vendor', + chunks: 'all', + }, + prismjs: { + test: /[\\/]node_modules[\\/](refractor)[\\/]/, + name: 'refractor-prismjs-vendor', + chunks: 'all', + }, + runtime: { + test: /[\\/]node_modules[\\/](@babel[\\/]runtime)[\\/]/, + name: 'babel-runtime-vendor', + chunks: 'all', + }, + parse5: { + test: /[\\/]node_modules[\\/](parse5)[\\/]/, + name: 'parse5-vendor', + chunks: 'all', + }, + }, + }, + }; + conf.output = { ...conf.output, publicPath: './' }; + } + return conf; +}; diff --git a/www/package.json b/www/package.json new file mode 100644 index 00000000..b2a3dfe2 --- /dev/null +++ b/www/package.json @@ -0,0 +1,53 @@ +{ + "name": "www", + "private": true, + "version": "2.0.3", + "scripts": { + "build": "kkt build", + "start": "kkt start", + "map": "source-map-explorer build/static/js/*.js --html build/website-result.html" + }, + "license": "MIT", + "devDependencies": { + "@kkt/less-modules": "~7.1.1", + "@kkt/raw-modules": "~7.1.1", + "@kkt/scope-plugin-options": "~7.1.1", + "@types/katex": "~0.14.0", + "@types/react": "~18.0.9", + "@types/react-dom": "~18.0.3", + "kkt": "~7.1.5", + "markdown-react-code-preview-loader": "^2.1.2", + "source-map-explorer": "~2.5.2" + }, + "dependencies": { + "@uiw/react-tooltip": "^4.21.11", + "@uiw/react-github-corners": "~1.5.3", + "@uiw/react-markdown-preview": "^4.0.17", + "@uiw/react-heat-map": "2.0.3", + "@uiw/react-shields": "~1.1.2", + "@wcj/dark-mode": "~1.0.9", + "@uiw/reset.css": "^1.0.6", + "react": "~18.1.0", + "react-code-preview-layout": "^2.0.4", + "react-dom": "~18.1.0", + "rehype-ignore": "^1.0.1" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/public/bundle.html b/www/public/bundle.html similarity index 100% rename from public/bundle.html rename to www/public/bundle.html diff --git a/public/favicon.ico b/www/public/favicon.ico similarity index 100% rename from public/favicon.ico rename to www/public/favicon.ico diff --git a/public/index.html b/www/public/index.html similarity index 100% rename from public/index.html rename to www/public/index.html diff --git a/website/App.module.less b/www/src/App.module.less similarity index 94% rename from website/App.module.less rename to www/src/App.module.less index 306c02e2..cd166172 100644 --- a/website/App.module.less +++ b/www/src/App.module.less @@ -27,7 +27,6 @@ html { .app { padding-bottom: 70px; - background-color: #fff; } .content { @@ -57,8 +56,6 @@ html { padding: 10px; padding-left: 0px; border-radius: 5px; - background-color: #efefef; - color: #333; label { display: flex; align-items: center; diff --git a/www/src/App.tsx b/www/src/App.tsx new file mode 100644 index 00000000..ea0af310 --- /dev/null +++ b/www/src/App.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import GitHubCorners from '@uiw/react-github-corners'; +import '@wcj/dark-mode'; +import MarkdownPreview from './Markdown'; +import Example from './Example'; +import logo from './logo.svg'; +import styles from './App.module.less'; + +const App: React.FC = () => { + return ( +
+ + +
+ react logo +

+ React component create calendar heatmap to visualize time series data, a la github contribution graph. +

+ +
+ +
+ ); +}; + +export default App; diff --git a/website/Code.tsx b/www/src/Code.tsx similarity index 99% rename from website/Code.tsx rename to www/src/Code.tsx index f0283a93..2d17f8fa 100755 --- a/website/Code.tsx +++ b/www/src/Code.tsx @@ -1,4 +1,5 @@ import React from 'react'; +// @ts-ignore import CodePreview, { CodePreviewProps } from '@uiw/react-code-preview'; export interface CodeProps extends CodePreviewProps { diff --git a/website/Example.tsx b/www/src/Example.tsx similarity index 99% rename from website/Example.tsx rename to www/src/Example.tsx index 3d1cf591..7e075fc2 100644 --- a/website/Example.tsx +++ b/www/src/Example.tsx @@ -1,6 +1,6 @@ import { Fragment, useState } from 'react'; import Tooltip from '@uiw/react-tooltip'; -import HeatMap, { HeatMapValue } from '../'; +import HeatMap, { HeatMapValue } from '@uiw/react-heat-map'; import styles from './App.module.less'; const data1: HeatMapValue[] = [ diff --git a/www/src/Markdown.tsx b/www/src/Markdown.tsx new file mode 100644 index 00000000..4171dfe4 --- /dev/null +++ b/www/src/Markdown.tsx @@ -0,0 +1,52 @@ +import { useEffect, useRef } from 'react'; +import CodeLayout from 'react-code-preview-layout'; +import { getMetaId, isMeta, getURLParameters } from 'markdown-react-code-preview-loader'; +import MarkdownPreview from '@uiw/react-markdown-preview'; +import rehypeIgnore from 'rehype-ignore'; +import data from '@uiw/react-heat-map/README.md'; +import { CodeComponent, ReactMarkdownNames } from 'react-markdown/lib/ast-to-react'; + +const CodePreview: CodeComponent | ReactMarkdownNames = ({ inline, node, ...props }) => { + const $dom = useRef(null); + const { 'data-meta': meta, ...rest } = props as any; + + useEffect(() => { + if ($dom.current) { + const parentElement = $dom.current.parentElement; + if (parentElement && parentElement.parentElement) { + parentElement.parentElement.replaceChild($dom.current, parentElement); + } + } + }, [$dom]); + + if (inline || !isMeta(meta)) { + return ; + } + const line = node.position?.start.line; + const metaId = getMetaId(meta) || String(line); + const Child = data.components[`${metaId}`]; + if (metaId && typeof Child === 'function') { + const code = data.data[metaId].value || ''; + const param = getURLParameters(meta); + return ( + } text={code}> + + + ); + } + return ; +}; + +export default function Markdown() { + return ( + + ); +} diff --git a/www/src/index.tsx b/www/src/index.tsx new file mode 100644 index 00000000..0b715d34 --- /dev/null +++ b/www/src/index.tsx @@ -0,0 +1,8 @@ +import { createRoot } from 'react-dom/client'; +import '@uiw/reset.css/reset.css'; +import App from './App'; + + +const container = document.getElementById('root'); +const root = createRoot(container!); // createRoot(container!) if you use TypeScript +root.render(); \ No newline at end of file diff --git a/website/logo.svg b/www/src/logo.svg similarity index 100% rename from website/logo.svg rename to www/src/logo.svg diff --git a/website/react-app-env.d.ts b/www/src/react-app-env.d.ts similarity index 67% rename from website/react-app-env.d.ts rename to www/src/react-app-env.d.ts index 51fa39e9..10a7af05 100644 --- a/website/react-app-env.d.ts +++ b/www/src/react-app-env.d.ts @@ -6,6 +6,7 @@ declare module '*.module.less' { } declare module '*.md' { - const src: string; + import { CodeBlockData } from 'markdown-react-code-preview-loader'; + const src: CodeBlockData; export default src; } diff --git a/www/tsconfig.json b/www/tsconfig.json new file mode 100644 index 00000000..8ad2d59d --- /dev/null +++ b/www/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig", + "include": ["./src", ".kktrc.ts"], + "compilerOptions": { + "baseUrl": ".", + "emitDeclarationOnly": true, + "noEmit": false + } +}