Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49bf21de71 | ||
|
|
15723a08c9 | ||
|
|
4fd4f3644d | ||
|
|
7969fb28a4 | ||
|
|
1955ec9cbd | ||
|
|
54e4188eb0 | ||
|
|
6fe79146d3 | ||
|
|
e7b52e0ebe | ||
|
|
8991adcd15 | ||
|
|
1b2e3b534d | ||
|
|
d85368cb4f | ||
|
|
8b4194f5ae | ||
|
|
ab3423a697 | ||
|
|
504259b862 | ||
|
|
b05d90e15b | ||
|
|
f6e71388f1 | ||
|
|
1c9a7a8668 | ||
|
|
314f47f8af | ||
|
|
be06f694a5 | ||
|
|
c23ada95ff | ||
|
|
2632cb1938 | ||
|
|
77616468a4 | ||
|
|
41eb86cd2b | ||
|
|
5fe5ddfa61 | ||
|
|
82cc2a3df4 | ||
|
|
b5596d76b6 | ||
|
|
d2c2746420 | ||
|
|
ef1ed54be7 | ||
|
|
e3a3cf5ff6 | ||
|
|
4f4ad71d09 | ||
|
|
3b32e76f65 | ||
|
|
056b792519 | ||
|
|
de98442b3c | ||
|
|
8bf24877bf | ||
|
|
ad546bfb6c | ||
|
|
bac929d894 | ||
|
|
ab1c043931 | ||
|
|
5afb09a715 | ||
|
|
df79dcf694 | ||
|
|
33a60420a4 | ||
|
|
c7dba6d5de | ||
|
|
ed596a7403 | ||
|
|
7f28e6ada1 | ||
|
|
df10f96a65 | ||
|
|
02cb33cfcd | ||
|
|
13a96916d7 | ||
|
|
245d54e511 | ||
|
|
06e216aa22 | ||
|
|
a50acf3888 | ||
|
|
195d2ce8d0 | ||
|
|
9adcd7eaa7 | ||
|
|
193ec20a22 | ||
|
|
8f62d41020 | ||
|
|
8720638f9d | ||
|
|
8d33e4dab2 | ||
|
|
1c79ec8b0a | ||
|
|
f3337f064e | ||
|
|
c86d5bbc0c | ||
|
|
55c369f23c | ||
|
|
6aad6713d2 | ||
|
|
5c10978fe9 | ||
|
|
8d17f7532e | ||
|
|
7f997282fc | ||
|
|
60b32b3ca8 | ||
|
|
83e834d6cf | ||
|
|
5cc2758073 | ||
|
|
d84ad70345 | ||
|
|
ba5eb6115c | ||
|
|
57e604c195 | ||
|
|
76a6f48d0a | ||
|
|
a66e906eef | ||
|
|
b694d61bf0 | ||
|
|
fd6ad59d5c | ||
|
|
b1dc77e98b | ||
|
|
57b719c163 |
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ko_fi: jaywcjlove
|
||||||
|
buy_me_a_coffee: jaywcjlove
|
||||||
|
custom: ["https://www.paypal.me/kennyiseeyou", "https://jaywcjlove.github.io/#/sponsor"]
|
||||||
311
.github/workflows/ci.yml
vendored
@@ -5,40 +5,47 @@ on:
|
|||||||
- master
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-deploy:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 20
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
|
- run: npm run doc
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: webiste
|
||||||
|
path: |
|
||||||
|
website/build/**
|
||||||
|
|
||||||
- name: Generate Contributors Images
|
- name: Generate Contributors Images
|
||||||
uses: jaywcjlove/github-action-contributors@main
|
uses: jaywcjlove/github-action-contributors@main
|
||||||
with:
|
with:
|
||||||
filter-author: (renovate\[bot\]|renovate-bot|dependabot\[bot\])
|
filter-author: (renovate\[bot\]|renovate-bot|dependabot\[bot\])
|
||||||
output: build/CONTRIBUTORS.svg
|
output: website/build/CONTRIBUTORS.svg
|
||||||
avatarSize: 42
|
avatarSize: 42
|
||||||
|
|
||||||
- name: Create Tag
|
- name: Create Tag
|
||||||
id: create_tag
|
id: create_tag
|
||||||
uses: jaywcjlove/create-tag-action@main
|
uses: jaywcjlove/create-tag-action@main
|
||||||
with:
|
with:
|
||||||
package-path: ./package.json
|
package-path: ./website/package.json
|
||||||
|
|
||||||
- name: get tag version
|
- name: get tag version
|
||||||
id: tag_version
|
id: tag_version
|
||||||
uses: jaywcjlove/changelog-generator@main
|
uses: jaywcjlove/changelog-generator@main
|
||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v4
|
||||||
with:
|
with:
|
||||||
commit_message: ${{ github.event.head_commit.message }} ${{steps.tag_version.outputs.tag}}
|
commit_message: ${{ github.event.head_commit.message }} ${{steps.tag_version.outputs.tag}}
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: ./build
|
publish_dir: ./website/build
|
||||||
|
|
||||||
- name: Generate Changelog
|
- name: Generate Changelog
|
||||||
id: changelog
|
id: changelog
|
||||||
@@ -48,52 +55,268 @@ jobs:
|
|||||||
filter-author: (renovate-bot|Renovate Bot)
|
filter-author: (renovate-bot|Renovate Bot)
|
||||||
filter: '[R|r]elease[d]\s+[v|V]\d(\.\d+){0,2}'
|
filter: '[R|r]elease[d]\s+[v|V]\d(\.\d+){0,2}'
|
||||||
|
|
||||||
- name: Create Release
|
outputs:
|
||||||
uses: ncipollo/release-action@v1
|
version: ${{ steps.changelog.outputs.version }}
|
||||||
if: steps.create_tag.outputs.successful
|
create_tag_version: ${{ steps.create_tag.outputs.version }}
|
||||||
|
create_tag_versionNumber: ${{ steps.create_tag.outputs.versionNumber }}
|
||||||
|
tag: ${{ steps.changelog.outputs.tag }}
|
||||||
|
successful: ${{steps.create_tag.outputs.successful }}
|
||||||
|
gh-pages-short-hash: ${{ steps.changelog.outputs.gh-pages-short-hash }}
|
||||||
|
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: webiste
|
||||||
|
path: website/build
|
||||||
|
|
||||||
|
- run: echo "outputs.version - ${{ needs.build.outputs.version }}"
|
||||||
|
- run: echo "outputs.create_tag_version - ${{ needs.build.outputs.create_tag_version }}"
|
||||||
|
- run: echo "outputs.create_tag_versionNumber - ${{ needs.build.outputs.create_tag_versionNumber }}"
|
||||||
|
- run: echo "outputs.tag - ${{ needs.build.outputs.tag }}"
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
# Create Docker Image
|
||||||
|
- name: Docker login
|
||||||
|
run: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
# - name: Build wxmp image
|
||||||
|
# working-directory: website
|
||||||
|
# run: docker image build -t wxmp .
|
||||||
|
|
||||||
|
- name: Build and push multi-platform image
|
||||||
|
working-directory: website
|
||||||
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
-t ${{ secrets.DOCKER_USER }}/wxmp:latest \
|
||||||
|
--push .
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build and push multi-platform image (with tag)
|
||||||
|
if: needs.build.outputs.successful
|
||||||
|
working-directory: website
|
||||||
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
-t ${{ secrets.DOCKER_USER }}/wxmp:${{ needs.build.outputs.version }} \
|
||||||
|
--push .
|
||||||
|
|
||||||
|
# # Create Docker Image in GitHub
|
||||||
|
# - name: Login to GitHub registry
|
||||||
|
# run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
|
# - name: Build docker image
|
||||||
|
# working-directory: website
|
||||||
|
# run: docker build -t ghcr.io/jaywcjlove/wxmp:latest .
|
||||||
|
|
||||||
|
# - name: Publish to GitHub registry
|
||||||
|
# run: docker push ghcr.io/jaywcjlove/wxmp:latest
|
||||||
|
|
||||||
|
# - name: Tag docker image (beta) and publish to GitHub registry
|
||||||
|
# if: needs.build.outputs.successful
|
||||||
|
# run: |
|
||||||
|
# echo "version: v${{ needs.build.outputs.version }}"
|
||||||
|
# docker tag ghcr.io/jaywcjlove/wxmp:latest ghcr.io/jaywcjlove/wxmp:${{needs.build.outputs.version}}
|
||||||
|
# docker push ghcr.io/jaywcjlove/wxmp:${{needs.build.outputs.version}}
|
||||||
|
|
||||||
|
build_windows:
|
||||||
|
needs: [build]
|
||||||
|
runs-on: windows-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: npm install --build-from-source
|
||||||
|
|
||||||
|
- run: npm run hoist
|
||||||
|
- run: npm run build
|
||||||
|
# - run: npm run electron
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: webiste
|
||||||
|
path: website/build
|
||||||
|
|
||||||
|
- name: electron-builder install-app-deps
|
||||||
|
working-directory: electron/app
|
||||||
|
run: npm run deps
|
||||||
|
|
||||||
|
- run: npm run build:app
|
||||||
|
- working-directory: electron/app/dist
|
||||||
|
run: ls -R
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: needs.build.outputs.successful == 'true'
|
||||||
|
with:
|
||||||
|
name: wxmp-windows
|
||||||
|
path: |
|
||||||
|
electron\app\dist\*.exe
|
||||||
|
|
||||||
|
build_macos:
|
||||||
|
needs: [build]
|
||||||
|
runs-on: macos-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run hoist
|
||||||
|
- run: npm run build
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: webiste
|
||||||
|
path: website/build
|
||||||
|
|
||||||
|
- name: electron-builder install-app-deps
|
||||||
|
working-directory: electron/app
|
||||||
|
run: npm run deps
|
||||||
|
|
||||||
|
- run: npm run build:app
|
||||||
|
- working-directory: electron/app/dist
|
||||||
|
run: ls -R
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: needs.build.outputs.successful == 'true'
|
||||||
|
with:
|
||||||
|
name: wxmp-macos
|
||||||
|
path: |
|
||||||
|
electron/app/dist/*.zip
|
||||||
|
|
||||||
|
build_linux:
|
||||||
|
needs: [build]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run hoist
|
||||||
|
- run: npm run build
|
||||||
|
# - run: npm run electron
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: webiste
|
||||||
|
path: website/build
|
||||||
|
|
||||||
|
- name: electron-builder install-app-deps
|
||||||
|
working-directory: electron/app
|
||||||
|
run: npm run deps
|
||||||
|
|
||||||
|
- run: npm run build:app
|
||||||
|
- working-directory: electron/app/dist
|
||||||
|
run: ls -R
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: needs.build.outputs.successful == 'true'
|
||||||
|
with:
|
||||||
|
name: wxmp-linux
|
||||||
|
path: |
|
||||||
|
electron/app/dist/*.deb
|
||||||
|
electron/app/dist/*.rpm
|
||||||
|
|
||||||
|
|
||||||
|
create_release:
|
||||||
|
needs: [build, build_windows, build_macos, build_linux]
|
||||||
|
if: needs.build.outputs.successful == 'true'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: wxmp-linux
|
||||||
|
path: dist/linux
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: wxmp-macos
|
||||||
|
path: dist/macos
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: wxmp-windows
|
||||||
|
path: dist/windows
|
||||||
|
|
||||||
|
- name: Display structure of downloaded files
|
||||||
|
working-directory: dist
|
||||||
|
run: ls -R
|
||||||
|
|
||||||
|
- name: Generate Changelog
|
||||||
|
id: changelog
|
||||||
|
uses: jaywcjlove/changelog-generator@main
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
name: ${{ steps.create_tag.outputs.version }}
|
filter-author: (jaywcjlove|小弟调调™|dependabot\[bot\]|Renovate Bot)
|
||||||
tag: ${{ steps.create_tag.outputs.version }}
|
filter: (^[\s]+?[R|r]elease)|(^[R|r]elease)
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
if: needs.build.outputs.successful == 'true'
|
||||||
|
with:
|
||||||
|
allowUpdates: true
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
name: ${{ steps.changelog.outputs.tag }}
|
||||||
|
tag: ${{ steps.changelog.outputs.tag }}
|
||||||
|
artifacts: "dist/linux/*.rpm,dist/linux/*.deb,dist/macos/*.zip,dist/macos/*.dmg,dist/windows/*.exe"
|
||||||
body: |
|
body: |
|
||||||
Documentation ${{ steps.changelog.outputs.tag }}: https://raw.githack.com/jaywcjlove/wxmp/${{ steps.changelog.outputs.gh-pages-short-hash }}/index.html
|
Documentation ${{ steps.changelog.outputs.tag }}: https://raw.githack.com/jaywcjlove/wxmp/${{ steps.changelog.outputs.gh-pages-short-hash }}/index.html
|
||||||
Comparing Changes: ${{ steps.changelog.outputs.compareurl }}
|
Comparing Changes: ${{ steps.changelog.outputs.compareurl }}
|
||||||
|
|
||||||
${{ steps.changelog.outputs.changelog }}
|
${{ steps.changelog.outputs.changelog }}
|
||||||
|
|
||||||
# Create Docker Image
|
```bash
|
||||||
- name: Docker login
|
docker pull wcjiang/wxmp:${{needs.build.outputs.create_tag_versionNumber}}
|
||||||
run: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
|
```
|
||||||
|
|
||||||
- name: Build Awesome Mac image
|
```bash
|
||||||
run: docker image build -t wxmp .
|
docker run --name wxmp --rm -d -p 9666:3000 wcjiang/wxmp:${{ needs.build.outputs.create_tag_versionNumber }}
|
||||||
|
# Or
|
||||||
|
docker run --name wxmp -itd -p 9666:3000 wcjiang/wxmp:${{ needs.build.outputs.create_tag_versionNumber }}
|
||||||
|
```
|
||||||
|
|
||||||
- name: Tags & Push image (latest)
|
Visit the following URL in your browser
|
||||||
run: |
|
|
||||||
echo "outputs.tag - ${{ steps.changelog.outputs.version }}"
|
|
||||||
docker tag wxmp ${{ secrets.DOCKER_USER }}/wxmp:latest
|
|
||||||
docker push ${{ secrets.DOCKER_USER }}/wxmp:latest
|
|
||||||
|
|
||||||
- name: Tags & Push image
|
```bash
|
||||||
if: steps.create_tag.outputs.successful
|
http://localhost:9666/
|
||||||
run: |
|
```
|
||||||
echo "outputs.tag - ${{ steps.changelog.outputs.version }}"
|
|
||||||
docker tag wxmp ${{ secrets.DOCKER_USER }}/wxmp:${{steps.changelog.outputs.version}}
|
|
||||||
docker push ${{ secrets.DOCKER_USER }}/wxmp:${{steps.changelog.outputs.version}}
|
|
||||||
|
|
||||||
# Create Docker Image in GitHub
|
roll_back:
|
||||||
- name: Login to GitHub registry
|
if: failure()
|
||||||
run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
needs: [build, create_release]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 4
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
- name: Build docker image
|
- run: echo "outputs.version - ${{ needs.build.outputs.create_tag_version }}"
|
||||||
run: docker build -t ghcr.io/jaywcjlove/wxmp:latest .
|
|
||||||
|
|
||||||
- name: Publish to GitHub registry
|
- uses: dev-drprasad/delete-tag-and-release@v1.1
|
||||||
run: docker push ghcr.io/jaywcjlove/wxmp:latest
|
if: needs.build.outputs.successful == 'true'
|
||||||
|
with:
|
||||||
- name: Tag docker image (beta) and publish to GitHub registry
|
delete_release: true
|
||||||
if: steps.create_tag.outputs.successful
|
repo: jaywcjlove/wxmp
|
||||||
run: |
|
tag_name: '${{ needs.build.outputs.create_tag_version }}'
|
||||||
echo "version: v${{ steps.changelog.outputs.version }}"
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
docker tag ghcr.io/jaywcjlove/wxmp:latest ghcr.io/jaywcjlove/wxmp:${{steps.changelog.outputs.version}}
|
|
||||||
docker push ghcr.io/jaywcjlove/wxmp:${{steps.changelog.outputs.version}}
|
|
||||||
|
|||||||
102
README.md
@@ -1,11 +1,55 @@
|
|||||||
|
<div markdown="1">
|
||||||
|
<sup>使用<a href="https://wangchujiang.com/#/app" target="_blank">我的应用</a>也是一种<a href="https://wangchujiang.com/#/sponsor" target="_blank">支持</a>我的方式:</sup>
|
||||||
|
<br>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/Deskmark/6755948110" title="Deskmark for macOS"><img alt="Deskmark" height="52" width="52" src="https://wangchujiang.com/appicon/deskmark.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/Keyzer/6500434773" title="Keyzer for macOS"><img alt="Keyzer" height="52" width="52" src="https://wangchujiang.com/appicon/keyzer.png"></a>
|
||||||
|
<a target="_blank" href="https://github.com/jaywcjlove/vidwall-hub" title="Vidwall Hub for macOS"><img alt="Vidwall Hub" height="52" width="52" src="https://wangchujiang.com/appicon/vidwall-hub.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/VidCrop/6752624705" title="VidCrop for macOS"><img alt="VidCrop" height="52" width="52" src="https://wangchujiang.com/appicon/vidcrop.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/Vidwall/6747587746" title="Vidwall for macOS"><img alt="Vidwall" height="52" width="52" src="https://wangchujiang.com/appicon/vidwall.png"></a>
|
||||||
|
<a target="_blank" href="https://wangchujiang.com/mousio-hint/" title="Mousio Hint for macOS"><img alt="Mousio Hint" height="52" width="52" src="https://wangchujiang.com/appicon/mousio-hint.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6746747327" title="Mousio for macOS"><img alt="Mousio" height="52" width="52" src="https://wangchujiang.com/appicon/mousio.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6745227444" title="Musicer for macOS"><img alt="Musicer" height="52" width="52" src="https://wangchujiang.com/appicon/musicer.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6743841447" title="Audioer for macOS"><img alt="Audioer" height="52" width="52" src="https://wangchujiang.com/appicon/audioer.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6744690194" title="FileSentinel for macOS"><img alt="FileSentinel" height="52" width="52" src="https://wangchujiang.com/appicon/file-sentinel.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6743495172" title="FocusCursor for macOS"><img alt="FocusCursor" height="52" width="52" src="https://wangchujiang.com/appicon/focus-cursor.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6742680573" title="Videoer for macOS"><img alt="Videoer" height="52" width="52" src="https://wangchujiang.com/appicon/videoer.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6740425504" title="KeyClicker for macOS"><img alt="KeyClicker" height="52" width="52" src="https://wangchujiang.com/appicon/key-clicker.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6739052447" title="DayBar for macOS"><img alt="DayBar" height="52" width="52" src="https://wangchujiang.com/appicon/daybar.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6739444407" title="Iconed for macOS"><img alt="Iconed" height="52" width="52" src="https://wangchujiang.com/appicon/iconed.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6737160756" title="Mousio for macOS"><img alt="Mousio" height="52" width="52" src="https://wangchujiang.com/appicon/rightmenu-master.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6723903021" title="Paste Quick for macOS"><img alt="Quick RSS" height="52" width="52" src="https://wangchujiang.com/appicon/paste-quick.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6670696072" title="Quick RSS for macOS/iOS"><img alt="Quick RSS" height="52" width="52" src="https://wangchujiang.com/appicon/quick-rss.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6670167443" title="Web Serve for macOS"><img alt="Web Serve" height="52" width="52" src="https://wangchujiang.com/appicon/web-serve.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6503953628" title="Copybook Generator for macOS/iOS"><img alt="Copybook Generator" height="52" width="52" src="https://wangchujiang.com/appicon/copybook-generator.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6471227008" title="DevTutor for macOS/iOS"><img alt="DevTutor for SwiftUI" height="52" width="52" src="https://wangchujiang.com/appicon/devtutor.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6479819388" title="RegexMate for macOS/iOS"><img alt="RegexMate" height="52" width="52" src="https://wangchujiang.com/appicon/regex-mate.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6479194014" title="Time Passage for macOS/iOS"><img alt="Time Passage" height="52" width="52" src="https://wangchujiang.com/appicon/time-passage.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6478772538" title="IconizeFolder for macOS"><img alt="Iconize Folder" height="52" width="52" src="https://wangchujiang.com/appicon/iconize-folder.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6478511402" title="Textsound Saver for macOS/iOS"><img alt="Textsound Saver" height="52" width="52" src="https://wangchujiang.com/appicon/textsound-saver.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6476924627" title="Create Custom Symbols for macOS"><img alt="Create Custom Symbols" height="52" width="52" src="https://wangchujiang.com/appicon/create-custom-symbols.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6476452351" title="DevHub for macOS"><img alt="DevHub" height="52" width="52" src="https://wangchujiang.com/appicon/devhub.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6476400184" title="Resume Revise for macOS"><img alt="Resume Revise" height="52" width="52" src="https://wangchujiang.com/appicon/resume-revise.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6472593276" title="Palette Genius for macOS"><img alt="Palette Genius" height="52" width="52" src="https://wangchujiang.com/appicon/palette-genius.png"></a>
|
||||||
|
<a target="_blank" href="https://apps.apple.com/app/6470879005" title="Symbol Scribe for macOS"><img alt="Symbol Scribe" height="52" width="52" src="https://wangchujiang.com/appicon/symbol-scribe.png"></a>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<h1 align="center">微信公众号 Markdown 编辑器</h1>
|
<h1 align="center">微信公众号 Markdown 编辑器</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||

|
[](https://jaywcjlove.github.io/#/sponsor)
|
||||||
|
[](https://github.com/jaywcjlove/wxmp/actions/workflows/ci.yml)
|
||||||
|
[](https://hub.docker.com/r/wcjiang/wxmp)
|
||||||
|
[](https://hub.docker.com/r/wcjiang/wxmp)
|
||||||
|
[](https://hub.docker.com/r/wcjiang/wxmp)
|
||||||
|
|
||||||
|
[](https://jaywcjlove.github.io/wxmp)
|
||||||
|
|
||||||
微信公众号文章 Markdown 在线编辑器,使用 markdown 语法创建一篇简介美观大方的微信公众号图文。由于发版本麻烦,和一些功能无法扩展停滞开发了,未来不再开发 Chrome 的插件(暂存在 chrome 分支),通过 web 版本定制更丰富的功能。
|
微信公众号文章 Markdown 在线编辑器,使用 markdown 语法创建一篇简介美观大方的微信公众号图文。由于发版本麻烦,和一些功能无法扩展停滞开发了,未来不再开发 Chrome 的插件(暂存在 chrome 分支),通过 web 版本定制更丰富的功能。
|
||||||
|
|
||||||
|
[](https://github.com/jaywcjlove/wxmp/releases)
|
||||||
|
|
||||||
## 功能特性
|
## 功能特性
|
||||||
|
|
||||||
开发计划和一些功能介绍,有需求可以在 issue 中提,使得工具变得更加完善。下面示例用于 web 应用中效果展示。
|
开发计划和一些功能介绍,有需求可以在 issue 中提,使得工具变得更加完善。下面示例用于 web 应用中效果展示。
|
||||||
@@ -14,9 +58,20 @@
|
|||||||
- [x] 支持自定义 CSS 样式
|
- [x] 支持自定义 CSS 样式
|
||||||
- [x] 支持主题选择 & 编辑预览。
|
- [x] 支持主题选择 & 编辑预览。
|
||||||
- [x] 支持明暗两种主题预览。
|
- [x] 支持明暗两种主题预览。
|
||||||
- [ ] 支持色盘取色,快速替换文章整体色调
|
- [ ] 支持代码块主题样式选择。
|
||||||
- [ ] 支持 URL 参数加载 Markdown 内容。
|
- [x] 支持色盘取色,快速替换文章整体色调
|
||||||
|
- [x] 支持 URL 参数加载 Markdown 内容。
|
||||||
- [x] 支持 URL 参数选择预览主题。
|
- [x] 支持 URL 参数选择预览主题。
|
||||||
|
- [x] CI 自动生成 Electron 桌面应用。
|
||||||
|
- [ ] ~~支持全局字号大小选择。~~
|
||||||
|
|
||||||
|
### 数学公式
|
||||||
|
|
||||||
|
$\\c = \pm\sqrt{a^2 + b^2}$ 和 $C_L$ 数学公式行内显示
|
||||||
|
|
||||||
|
```math
|
||||||
|
L = \frac{1}{2} \rho v^2 S C_L
|
||||||
|
```
|
||||||
|
|
||||||
### 支持代码块样式
|
### 支持代码块样式
|
||||||
|
|
||||||
@@ -66,13 +121,20 @@ Inline Code `{code: 0}`
|
|||||||
|
|
||||||
### 支持注释
|
### 支持注释
|
||||||
|
|
||||||
|
```html
|
||||||
<ruby>
|
<ruby>
|
||||||
汉 <rp></rp><rt>Han</rt><rp></rp>
|
汉 <rt>Han</rt>
|
||||||
字 <rp></rp><rt>zi</rt><rp></rp>
|
</ruby>
|
||||||
拼 <rp></rp><rt>pin</rt><rp></rp>
|
```
|
||||||
音 <rp></rp><rt>yin</rt><rp></rp>
|
|
||||||
注 <rp></rp><rt>zhu</rt><rp></rp>
|
汉字注音效果:
|
||||||
音 <rp></rp><rt>yin</rt><rp></rp>
|
<ruby>
|
||||||
|
汉 <rt>Han</rt>
|
||||||
|
字 <rt>zi</rt>
|
||||||
|
拼 <rt>pin</rt>
|
||||||
|
音 <rt>yin</rt>
|
||||||
|
注 <rt>zhu</rt>
|
||||||
|
音 <rt>yin</rt>
|
||||||
</ruby>
|
</ruby>
|
||||||
|
|
||||||
### 支持自定义样式
|
### 支持自定义样式
|
||||||
@@ -100,9 +162,23 @@ Inline Code `{code: 0}`
|
|||||||
<!--rehype:ignore:start-->内容在微信 Markdown 编辑器预览中不显示。在其它预览工具中展示内容。<!--rehype:ignore:end-->
|
<!--rehype:ignore:start-->内容在微信 Markdown 编辑器预览中不显示。在其它预览工具中展示内容。<!--rehype:ignore:end-->
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 支持 URL 参数加载 Markdown 内容
|
||||||
|
|
||||||
|
```
|
||||||
|
https://<URL>?md=<Markdown 资源 URL>
|
||||||
|
```
|
||||||
|
|
||||||
|
加载 Markdown 内容的示例 URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://jaywcjlove.github.io/wxmp/#/?theme=underscore&md=https://raw.githubusercontent.com/jaywcjlove/c-tutorial/master/README.md
|
||||||
|
|
||||||
|
Markdown URL 地址: https://raw.githubusercontent.com/jaywcjlove/c-tutorial/master/README.md
|
||||||
|
```
|
||||||
|
|
||||||
## 主题定制
|
## 主题定制
|
||||||
|
|
||||||
在目录 `src/themes` 中存放默认主题,在 `src/store/context.tsx` 中配置主题,主题使用 css 定义样式,不支持复杂的选择器。提供在线主题编辑器,欢迎修改并 PR 进仓库供大家使用。
|
在目录 `website/src/themes` 中存放默认主题,在 `website/src/store/context.tsx` 中配置主题,主题使用 `css` 定义样式,不支持复杂的选择器。提供在线主题编辑器,欢迎修改并 `PR` 进仓库供大家使用。
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* 1~6 标题样式定义 */
|
/* 1~6 标题样式定义 */
|
||||||
@@ -161,11 +237,11 @@ docker pull ghcr.io/jaywcjlove/wxmp:latest
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --name wxmp --rm -d -p 96611:3000 wcjiang/wxmp:latest
|
docker run --name wxmp --rm -d -p 8113:3000 wcjiang/wxmp:latest
|
||||||
# Or
|
# Or
|
||||||
docker run --name wxmp -itd -p 96611:3000 wcjiang/wxmp:latest
|
docker run --name wxmp -itd -p 8113:3000 wcjiang/wxmp:latest
|
||||||
# Or
|
# Or
|
||||||
docker run --name wxmp -itd -p 96611:3000 ghcr.io/jaywcjlove/wxmp:latest
|
docker run --name wxmp -itd -p 8113:3000 ghcr.io/jaywcjlove/wxmp:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
在浏览器中访问以下 URL
|
在浏览器中访问以下 URL
|
||||||
|
|||||||
2
electron/app/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
dist
|
||||||
|
website
|
||||||
8
electron/app/assets/entitlements.mac.plist
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
35
electron/app/config.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"productName": "wxmp",
|
||||||
|
"appId": "com.wangchujiang.wxmp",
|
||||||
|
"asar": true,
|
||||||
|
"directories": {
|
||||||
|
"output": "dist"
|
||||||
|
},
|
||||||
|
"mac": {
|
||||||
|
"icon": "tools.icns",
|
||||||
|
"target": {
|
||||||
|
"target": "default",
|
||||||
|
"arch": ["arm64", "x64"]
|
||||||
|
},
|
||||||
|
"category": "public.app-category.developer-tools",
|
||||||
|
"type": "distribution",
|
||||||
|
"entitlements": "assets/entitlements.mac.plist",
|
||||||
|
"entitlementsInherit": "assets/entitlements.mac.plist"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"icon": "tools.icns",
|
||||||
|
"description": "微信公众号 Markdown 编辑器",
|
||||||
|
"category": "Development",
|
||||||
|
"target": ["deb", "rpm"],
|
||||||
|
"desktop": {
|
||||||
|
"Name": "Web Tools"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"icon": "tools.ico",
|
||||||
|
"target": {
|
||||||
|
"target": "nsis",
|
||||||
|
"arch": ["x64", "ia32"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
electron/app/icon.icns
Normal file
BIN
electron/app/icons.iconset/icon_128x128.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
electron/app/icons.iconset/icon_128x128@2x.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
electron/app/icons.iconset/icon_16x16.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
electron/app/icons.iconset/icon_16x16@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
electron/app/icons.iconset/icon_256x256.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
electron/app/icons.iconset/icon_256x256@2x.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
electron/app/icons.iconset/icon_32x32.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
electron/app/icons.iconset/icon_32x32@2x.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
electron/app/icons.iconset/icon_512x512.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
electron/app/icons.iconset/icon_512x512@2x.png
Normal file
|
After Width: | Height: | Size: 275 KiB |
BIN
electron/app/logo.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
15
electron/app/main.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { App } = require('@wcj/wxmp-main');
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const options = {};
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
options.preload = require.resolve('@wcj/wxmp-preload');
|
||||||
|
options.webpath = require.resolve('website/build/index.html');
|
||||||
|
} else {
|
||||||
|
options.preload = path.resolve(__dirname, 'website/index.js');
|
||||||
|
options.webpath = 'website/index.html';
|
||||||
|
}
|
||||||
|
const app = new App();
|
||||||
|
await app.createWindow(options);
|
||||||
|
})();
|
||||||
30
electron/app/package.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "wxmp",
|
||||||
|
"description": "微信公众号 Markdown 编辑器",
|
||||||
|
"homepage": "https://github.com/jaywcjlove/wxmp.git",
|
||||||
|
"version": "2.4.1",
|
||||||
|
"main": "main.js",
|
||||||
|
"author": "Kenny Wong <398188662@qq.com>",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"deps": "electron-builder install-app-deps",
|
||||||
|
"start": "cross-env NODE_ENV=development ELECTRON_DISABLE_SECURITY_WARNINGS=true electron .",
|
||||||
|
"start:production": "cross-env NODE_ENV=production ELECTRON_DISABLE_SECURITY_WARNINGS=true electron .",
|
||||||
|
"dist-win32": "electron-builder --win --ia32 --config config.json",
|
||||||
|
"dist-win64": "electron-builder --win --x64 --config config.json",
|
||||||
|
"dist-mac": "electron-builder --mac --universal --config config.json",
|
||||||
|
"dist-linux": "electron-builder --linux --config config.json",
|
||||||
|
"copy": "cpy './node_modules/@wcj/wxmp-preload/lib/*.js' './node_modules/website/build/**' website",
|
||||||
|
"build": "npm run copy && cross-env NODE_ENV=production electron-builder build --publish=never --config config.json"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@wcj/wxmp-main": "2.4.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@wcj/wxmp-preload": "2.4.1",
|
||||||
|
"cpy-cli": "^5.0.0",
|
||||||
|
"electron": "20.1.3",
|
||||||
|
"electron-builder": "23.3.3",
|
||||||
|
"website": "2.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
electron/main/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
lib
|
||||||
16
electron/main/package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "@wcj/wxmp-main",
|
||||||
|
"version": "2.4.1",
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsbb build",
|
||||||
|
"watch": "tsbb watch"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"electron": "20.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
56
electron/main/src/Menu.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { app, Menu, MenuItem, MenuItemConstructorOptions } from 'electron';
|
||||||
|
const isMac = process.platform === 'darwin';
|
||||||
|
const template = [
|
||||||
|
// { role: 'appMenu' }
|
||||||
|
...(isMac
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: app.name,
|
||||||
|
submenu: [
|
||||||
|
{ role: 'about' },
|
||||||
|
{ type: 'separator' },
|
||||||
|
{ role: 'services' },
|
||||||
|
{ type: 'separator' },
|
||||||
|
{ role: 'hide' },
|
||||||
|
{ role: 'hideOthers' },
|
||||||
|
{ role: 'unhide' },
|
||||||
|
{ type: 'separator' },
|
||||||
|
{ role: 'quit' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
{ role: 'editMenu' },
|
||||||
|
{
|
||||||
|
label: 'Window',
|
||||||
|
submenu: [
|
||||||
|
{ role: 'minimize' },
|
||||||
|
{ role: 'zoom' },
|
||||||
|
...(isMac
|
||||||
|
? [{ type: 'separator' }, { role: 'front' }, { type: 'separator' }, { role: 'window' }]
|
||||||
|
: [{ role: 'close' }]),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'help',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Open Source for Github',
|
||||||
|
click: async () => {
|
||||||
|
const { shell } = require('electron');
|
||||||
|
await shell.openExternal('https://github.com/jaywcjlove/wxmp');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Online Website',
|
||||||
|
click: async () => {
|
||||||
|
const { shell } = require('electron');
|
||||||
|
await shell.openExternal('https://jaywcjlove.github.io/wxmp');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const menu = Menu.buildFromTemplate(template as Array<MenuItem | MenuItemConstructorOptions>);
|
||||||
|
Menu.setApplicationMenu(menu);
|
||||||
61
electron/main/src/app.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { app, shell, BrowserWindow } from 'electron';
|
||||||
|
import './Menu';
|
||||||
|
|
||||||
|
export interface Options extends Electron.BrowserWindowConstructorOptions {
|
||||||
|
preload?: string;
|
||||||
|
webpath?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class App {
|
||||||
|
app = app;
|
||||||
|
win?: BrowserWindow;
|
||||||
|
isLogin: boolean = false;
|
||||||
|
/** 创建主进程窗口 */
|
||||||
|
async createWindow(options: Options = {}, loadURL?: string) {
|
||||||
|
await app.whenReady();
|
||||||
|
const opts: Options = {
|
||||||
|
// titleBarStyle: 'hiddenInset', // 无标题栏
|
||||||
|
// frame: false, // 创建无边窗口
|
||||||
|
width: 850,
|
||||||
|
height: 600,
|
||||||
|
minWidth: 850,
|
||||||
|
minHeight: 600,
|
||||||
|
center: true,
|
||||||
|
// maximizable: true,
|
||||||
|
// minimizable: true,
|
||||||
|
// resizable: true,
|
||||||
|
webPreferences: {
|
||||||
|
// 多线程
|
||||||
|
nodeIntegrationInWorker: true,
|
||||||
|
nodeIntegration: true,
|
||||||
|
contextIsolation: false,
|
||||||
|
},
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
if (options.preload) {
|
||||||
|
opts.webPreferences.preload = options.preload;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.win = new BrowserWindow(opts);
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
this.win.loadURL(loadURL || 'http://localhost:3000/');
|
||||||
|
// 打开开发者工具,默认不打开
|
||||||
|
this.win.webContents.openDevTools();
|
||||||
|
} else {
|
||||||
|
this.win.loadFile(options.webpath);
|
||||||
|
}
|
||||||
|
this.win.webContents.setWindowOpenHandler(({ url }) => {
|
||||||
|
if (/^https?:\/\//.test(url)) {
|
||||||
|
shell.openExternal(url);
|
||||||
|
return { action: 'deny' };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
action: 'allow',
|
||||||
|
overrideBrowserWindowOptions: {
|
||||||
|
modal: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return this.win;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
electron/main/src/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './app';
|
||||||
19
electron/main/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"declaration": true,
|
||||||
|
"target": "es2017",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"sourceMap": false,
|
||||||
|
"strict": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"outDir": "lib",
|
||||||
|
"baseUrl": "."
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
1
electron/preload/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
lib
|
||||||
16
electron/preload/package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "@wcj/wxmp-preload",
|
||||||
|
"version": "2.4.1",
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsbb build",
|
||||||
|
"watch": "tsbb watch"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"electron": "20.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
electron/preload/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
const styleStr = `.header .logo {}`;
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const head = document.querySelector('head');
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = styleStr;
|
||||||
|
if (head) {
|
||||||
|
head.append(style);
|
||||||
|
}
|
||||||
|
});
|
||||||
27
electron/preload/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"declaration": true,
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"sourceMap": false,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"outDir": "lib",
|
||||||
|
"baseUrl": "."
|
||||||
|
// "esModuleInterop": true,
|
||||||
|
// "allowSyntheticDefaultImports": true,
|
||||||
|
// "forceConsistentCasingInFileNames": true,
|
||||||
|
// "noFallthroughCasesInSwitch": true,
|
||||||
|
// "isolatedModules": false,
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
4
lerna.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"version": "2.4.1",
|
||||||
|
"packages": ["website", "electron/*"]
|
||||||
|
}
|
||||||
88
package.json
@@ -1,81 +1,35 @@
|
|||||||
{
|
{
|
||||||
"name": "website",
|
|
||||||
"version": "2.1.0",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "kkt start",
|
"build": "lerna exec --scope @wcj/* --ignore wxmp -- npm run build",
|
||||||
"build": "kkt build",
|
"doc": "npm run-script build --workspace website",
|
||||||
|
"start": "npm run-script start --workspace website",
|
||||||
|
"build:app": "npm run-script build --workspace wxmp",
|
||||||
|
"⬆️⬆️⬆️⬆️⬆️ package ⬆️⬆️⬆️⬆️⬆️": "▲▲▲▲▲ package ▲▲▲▲▲",
|
||||||
|
"version": "lerna version --exact --force-publish --no-push --no-git-tag-version",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
|
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
|
||||||
"pretty-quick": "pretty-quick --staged"
|
"hoist": "lerna bootstrap --hoist",
|
||||||
|
"clean": "lerna clean --yes"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
|
||||||
"@babel/runtime": "^7.18.9",
|
|
||||||
"@uiw/codemirror-theme-abcdef": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-androidstudio": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-atomone": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-bbedit": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-bespin": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-darcula": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-dracula": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-duotone": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-eclipse": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-github": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-okaidia": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-sublime": "^4.11.6",
|
|
||||||
"@uiw/codemirror-theme-xcode": "^4.11.6",
|
|
||||||
"@uiw/react-back-to-top": "^1.2.0",
|
|
||||||
"@uiw/react-github-corners": "^1.5.15",
|
|
||||||
"@uiw/react-markdown-editor": "^5.6.0",
|
|
||||||
"@wcj/dark-mode": "^1.0.15",
|
|
||||||
"css-tree": "^2.2.1",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-code-preview-layout": "^2.0.4",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react-hot-toast": "^2.3.0",
|
|
||||||
"react-router-dom": "^6.3.0",
|
|
||||||
"rehype-attr": "^2.0.8",
|
|
||||||
"rehype-ignore": "^1.0.1",
|
|
||||||
"rehype-prism-plus": "^1.5.0",
|
|
||||||
"rehype-raw": "^6.1.1",
|
|
||||||
"rehype-stringify": "^9.0.3",
|
|
||||||
"remark-gfm": "^3.0.1",
|
|
||||||
"remark-parse": "^10.0.1",
|
|
||||||
"remark-rehype": "^10.1.0",
|
|
||||||
"styled-components": "^5.3.5",
|
|
||||||
"unified": "^10.1.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kkt/less-modules": "^7.2.0",
|
"@lerna/legacy-package-management": "^8.0.0",
|
||||||
"@kkt/raw-modules": "^7.2.0",
|
"cross-env": "^7.0.3",
|
||||||
"@kkt/scope-plugin-options": "^7.2.0",
|
|
||||||
"@types/css-tree": "^1.0.7",
|
|
||||||
"@types/react": "^18.0.17",
|
|
||||||
"@types/react-dom": "^18.0.6",
|
|
||||||
"@types/styled-components": "^5.1.25",
|
|
||||||
"husky": "^8.0.1",
|
"husky": "^8.0.1",
|
||||||
"prettier": "^2.7.1",
|
"lerna": "^8.0.0",
|
||||||
"pretty-quick": "~3.1.3",
|
"prettier": "^3.0.2",
|
||||||
"kkt": "^7.2.0",
|
"react": "~18.2.0",
|
||||||
"markdown-react-code-preview-loader": "^2.1.2"
|
"react-dom": "~18.2.0",
|
||||||
|
"tsbb": "~4.4.0"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"workspaces": {
|
||||||
"extends": [
|
"packages": [
|
||||||
"react-app",
|
"electron/**",
|
||||||
"react-app/jest"
|
"website"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"engines": {
|
||||||
"production": [
|
"node": ">=16.0.0"
|
||||||
">0.2%",
|
|
||||||
"not dead",
|
|
||||||
"not op_mini all"
|
|
||||||
],
|
|
||||||
"development": [
|
|
||||||
"last 1 chrome version",
|
|
||||||
"last 1 firefox version",
|
|
||||||
"last 1 safari version"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { MarkdownPreviewProps } from '@uiw/react-markdown-preview';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import { Context } from '../../store/context';
|
|
||||||
|
|
||||||
import { markdownToHTML } from '../../utils/markdownToHTML';
|
|
||||||
|
|
||||||
const Warpper = styled.div`
|
|
||||||
width: 375px;
|
|
||||||
padding: 20px;
|
|
||||||
box-shadow: 0 0 60px rgb(0 0 0 / 10%);
|
|
||||||
min-height: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Preview = (props: MarkdownPreviewProps) => {
|
|
||||||
const { css } = useContext(Context);
|
|
||||||
const html = markdownToHTML(props.source || '', css);
|
|
||||||
return <Warpper contentEditable spellCheck={false} dangerouslySetInnerHTML={{ __html: html }} />;
|
|
||||||
};
|
|
||||||
4
website/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
public
|
||||||
|
src
|
||||||
|
.git
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import path from 'path';
|
|
||||||
import webpack, { Configuration } from 'webpack';
|
import webpack, { Configuration } from 'webpack';
|
||||||
import lessModules from '@kkt/less-modules';
|
import lessModules from '@kkt/less-modules';
|
||||||
import { mdCodeModulesLoader } from 'markdown-react-code-preview-loader';
|
import { mdCodeModulesLoader } from 'markdown-react-code-preview-loader';
|
||||||
import scopePluginOptions from '@kkt/scope-plugin-options';
|
import { disableScopePlugin } from '@kkt/scope-plugin-options';
|
||||||
import { LoaderConfOptions } from 'kkt';
|
import { LoaderConfOptions } from 'kkt';
|
||||||
import raw from '@kkt/raw-modules';
|
import raw from '@kkt/raw-modules';
|
||||||
import pkg from './package.json';
|
import pkg from './package.json';
|
||||||
@@ -14,16 +13,15 @@ export default (conf: Configuration, env: 'development' | 'production', options:
|
|||||||
...options,
|
...options,
|
||||||
test: /\.(md.css)$/i,
|
test: /\.(md.css)$/i,
|
||||||
});
|
});
|
||||||
conf = scopePluginOptions(conf, env, {
|
conf = disableScopePlugin(conf);
|
||||||
...options,
|
|
||||||
allowedFiles: [path.resolve(process.cwd(), 'README.md'), path.resolve(process.cwd(), 'src')],
|
|
||||||
});
|
|
||||||
conf.plugins!.push(
|
conf.plugins!.push(
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
VERSION: JSON.stringify(pkg.version),
|
VERSION: JSON.stringify(pkg.version),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** https://github.com/kktjs/kkt/issues/446 */
|
||||||
|
conf.ignoreWarnings = [{ module: /node_modules[\\/]parse5[\\/]/ }];
|
||||||
conf.module!.exprContextCritical = false;
|
conf.module!.exprContextCritical = false;
|
||||||
if (env === 'production') {
|
if (env === 'production') {
|
||||||
conf.output = { ...conf.output, publicPath: './' };
|
conf.output = { ...conf.output, publicPath: './' };
|
||||||
76
website/package.json
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"name": "website",
|
||||||
|
"version": "2.4.1",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "kkt start",
|
||||||
|
"build": "kkt build"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.18.9",
|
||||||
|
"@tanstack/react-query": "^4.2.3",
|
||||||
|
"@uiw/codemirror-theme-abcdef": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-androidstudio": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-atomone": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-bbedit": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-bespin": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-darcula": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-dracula": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-duotone": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-eclipse": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-github": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-okaidia": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-sublime": "^4.11.6",
|
||||||
|
"@uiw/codemirror-theme-xcode": "^4.11.6",
|
||||||
|
"@uiw/react-back-to-top": "^1.2.0",
|
||||||
|
"@uiw/react-github-corners": "^1.5.15",
|
||||||
|
"@uiw/react-markdown-editor": "^6.0.0",
|
||||||
|
"@wcj/dark-mode": "^1.0.15",
|
||||||
|
"css-tree": "^2.2.1",
|
||||||
|
"react": "~18.2.0",
|
||||||
|
"react-dom": "~18.2.0",
|
||||||
|
"react-hot-toast": "^2.3.0",
|
||||||
|
"react-router-dom": "^6.3.0",
|
||||||
|
"rehype-attr": "^3.0.0",
|
||||||
|
"rehype-ignore": "^2.0.0",
|
||||||
|
"rehype-katex": "^7.0.1",
|
||||||
|
"rehype-prism-plus": "^2.0.0",
|
||||||
|
"rehype-raw": "^7.0.0",
|
||||||
|
"rehype-stringify": "^10.0.0",
|
||||||
|
"remark-gfm": "^4.0.0",
|
||||||
|
"remark-math": "^6.0.0",
|
||||||
|
"remark-parse": "^11.0.0",
|
||||||
|
"remark-rehype": "^11.0.0",
|
||||||
|
"styled-components": "~6.1.0",
|
||||||
|
"unified": "^11.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@kkt/less-modules": "^7.2.0",
|
||||||
|
"@kkt/raw-modules": "^7.2.0",
|
||||||
|
"@kkt/scope-plugin-options": "^7.2.0",
|
||||||
|
"@types/css-tree": "^2.3.1",
|
||||||
|
"@types/react": "^18.0.17",
|
||||||
|
"@types/react-dom": "^18.0.6",
|
||||||
|
"kkt": "^7.2.0",
|
||||||
|
"markdown-react-code-preview-loader": "^2.1.2"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -2,6 +2,7 @@ import { Routes, Route } from 'react-router-dom';
|
|||||||
import { Layout } from './components/Layout';
|
import { Layout } from './components/Layout';
|
||||||
import { HomePage } from './pages/home';
|
import { HomePage } from './pages/home';
|
||||||
import { EditorPage } from './pages/theme/editor';
|
import { EditorPage } from './pages/theme/editor';
|
||||||
|
import { DocsPage } from './pages/docs';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
@@ -9,6 +10,7 @@ export default function App() {
|
|||||||
<Route path="/" element={<Layout />}>
|
<Route path="/" element={<Layout />}>
|
||||||
<Route index element={<HomePage />} />
|
<Route index element={<HomePage />} />
|
||||||
<Route path="/editor/theme" element={<EditorPage />} />
|
<Route path="/editor/theme" element={<EditorPage />} />
|
||||||
|
<Route path="/doc" element={<DocsPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
|
Before Width: | Height: | Size: 576 B After Width: | Height: | Size: 576 B |
|
Before Width: | Height: | Size: 784 B After Width: | Height: | Size: 784 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
29
website/src/assets/tail-spin.svg
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 105 105" fill="currentColor">
|
||||||
|
<circle cx="12.5" cy="12.5" r="12.5">
|
||||||
|
<animate attributeName="fill-opacity" begin="0s" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
<circle cx="12.5" cy="52.5" r="12.5" fill-opacity=".5">
|
||||||
|
<animate attributeName="fill-opacity" begin="100ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
<circle cx="52.5" cy="12.5" r="12.5">
|
||||||
|
<animate attributeName="fill-opacity" begin="300ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
<circle cx="52.5" cy="52.5" r="12.5">
|
||||||
|
<animate attributeName="fill-opacity" begin="600ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
<circle cx="92.5" cy="12.5" r="12.5">
|
||||||
|
<animate attributeName="fill-opacity" begin="800ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
<circle cx="92.5" cy="52.5" r="12.5">
|
||||||
|
<animate attributeName="fill-opacity" begin="400ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
<circle cx="12.5" cy="92.5" r="12.5">
|
||||||
|
<animate attributeName="fill-opacity" begin="700ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
<circle cx="52.5" cy="92.5" r="12.5">
|
||||||
|
<animate attributeName="fill-opacity" begin="500ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
<circle cx="92.5" cy="92.5" r="12.5">
|
||||||
|
<animate attributeName="fill-opacity" begin="200ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
42
website/src/commands/color.tsx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { ICommand } from '@uiw/react-markdown-editor';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { Context } from '../store/context';
|
||||||
|
|
||||||
|
const Input = styled.input`
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Button = styled.button``;
|
||||||
|
|
||||||
|
const ColorView: React.FC<{}> = (props) => {
|
||||||
|
const { preColor, setPreColor } = useContext(Context);
|
||||||
|
const handleChange = (evn: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setPreColor(evn.target.value);
|
||||||
|
};
|
||||||
|
const color = preColor ? preColor : 'currentColor';
|
||||||
|
return (
|
||||||
|
<Button type="button">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" height="16" width="16">
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M8.203 2.004c1.261 0 2.304 1.103 2.476 2.538l8.483 8.484-7.778 7.778a3 3 0 0 1-4.243 0L2.9 16.562a3 3 0 0 1 0-4.243l2.804-2.805V4.961c0-1.633 1.12-2.957 2.5-2.957Zm.5 2.957v1.553l-1 1V4.961c0-.327.224-.591.5-.591.277 0 .5.264.5.591Zm0 5.914V9.342l-4.39 4.391a1 1 0 0 0 0 1.414l4.243 4.243a1 1 0 0 0 1.414 0l6.364-6.364-5.63-5.63v3.48l-.003.128h-2.01a.698.698 0 0 0 .012-.129Z"
|
||||||
|
/>
|
||||||
|
<path d="M16.859 16.875a3 3 0 1 0 4.242 0l-2.121-2.121-2.121 2.12Z" fill={color} />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<Input type="color" value={preColor} onChange={handleChange} />
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const colorCommand: ICommand = {
|
||||||
|
name: 'color',
|
||||||
|
keyCommand: 'color',
|
||||||
|
button: () => <ColorView />,
|
||||||
|
};
|
||||||
@@ -4,30 +4,35 @@ import toast from 'react-hot-toast';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
const Button = styled.button`
|
const Button = styled.button`
|
||||||
white-space: nowrap;
|
/* white-space: nowrap;
|
||||||
width: initial !important;
|
width: initial !important;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center; */
|
||||||
padding: 0 0.4rem !important;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const CopyView: React.FC<{ command: ICommand; editorProps: IMarkdownEditor & ToolBarProps }> = (props) => {
|
const CopyView: React.FC<{ command: ICommand; editorProps: IMarkdownEditor & ToolBarProps }> = (props) => {
|
||||||
const { editorProps } = props;
|
const { editorProps } = props;
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
const dom = editorProps.preview.current;
|
const dom: HTMLDivElement | null = editorProps.preview.current;
|
||||||
dom?.focus();
|
if (!dom) {
|
||||||
window.getSelection()?.removeAllRanges();
|
toast.error(<div>dom is null</div>);
|
||||||
let range = document.createRange();
|
return;
|
||||||
range.setStartBefore(dom?.firstChild!);
|
}
|
||||||
range.setEndAfter(dom?.lastChild!);
|
dom.focus();
|
||||||
window.getSelection()?.addRange(range);
|
const htmlContent = dom.innerHTML;
|
||||||
document.execCommand(`copy`);
|
navigator.clipboard
|
||||||
window.getSelection()?.removeAllRanges();
|
.writeText(htmlContent)
|
||||||
toast.success(<div>复制成功!去公众号编辑器复制吧!</div>);
|
.then(() => {
|
||||||
|
toast.success(<div>复制成功!去公众号编辑器粘贴吧!</div>);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(<div>{JSON.stringify(err)}</div>);
|
||||||
|
console.error('Failed to copy: ', err);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Button type="button" onClick={handleClick}>
|
<Button type="button" onClick={handleClick}>
|
||||||
{props.command.icon} 复制
|
{props.command.icon}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -4,7 +4,7 @@ import styled from 'styled-components';
|
|||||||
|
|
||||||
const Link = styled(NavLink)`
|
const Link = styled(NavLink)`
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
line-height: 0.8rem;
|
line-height: 0.7rem;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
padding: 0.18rem 0.3rem;
|
padding: 0.18rem 0.3rem;
|
||||||
&:hover {
|
&:hover {
|
||||||
@@ -12,7 +12,7 @@ const Select = styled.select`
|
|||||||
padding: 0 0.2rem 0 0.2rem;
|
padding: 0 0.2rem 0 0.2rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 0.3rem;
|
font-size: 0.7rem;
|
||||||
outline: none;
|
outline: none;
|
||||||
height: 1.15rem;
|
height: 1.15rem;
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
@@ -49,7 +49,6 @@ const ThemePreviewView: React.FC<{}> = () => {
|
|||||||
const { setCss, previewTheme, setPreviewTheme } = useContext(Context);
|
const { setCss, previewTheme, setPreviewTheme } = useContext(Context);
|
||||||
const handleChange = (ev: React.ChangeEvent<HTMLSelectElement>) => {
|
const handleChange = (ev: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
const value = ev.target.value as PreviewThemeValue;
|
const value = ev.target.value as PreviewThemeValue;
|
||||||
console.log('vvvv');
|
|
||||||
setPreviewTheme(value);
|
setPreviewTheme(value);
|
||||||
setCss(previewThemes[value].value);
|
setCss(previewThemes[value].value);
|
||||||
};
|
};
|
||||||
@@ -1,17 +1,29 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Outlet, NavLink } from 'react-router-dom';
|
import { Outlet, NavLink } from 'react-router-dom';
|
||||||
import '@wcj/dark-mode';
|
import '@wcj/dark-mode';
|
||||||
|
import { useContext } from 'react';
|
||||||
import { ReactComponent as LogoIcon } from '../assets/logo.svg';
|
import { ReactComponent as LogoIcon } from '../assets/logo.svg';
|
||||||
import { ReactComponent as GithubIcon } from '../assets/github.svg';
|
import { ReactComponent as GithubIcon } from '../assets/github.svg';
|
||||||
|
import { ReactComponent as Loading } from '../assets/tail-spin.svg';
|
||||||
|
import { Context } from '../store/context';
|
||||||
|
|
||||||
const Warpper = styled.div``;
|
const Warpper = styled.div``;
|
||||||
|
const HeaderPlace = styled.div`
|
||||||
|
position: relative;
|
||||||
|
height: 2.8rem;
|
||||||
|
`;
|
||||||
|
|
||||||
const Header = styled.header`
|
const Header = styled.header`
|
||||||
|
-webkit-app-region: drag;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
background: var(--color-canvas-default);
|
||||||
border-bottom: 1px solid var(--color-border-muted);
|
border-bottom: 1px solid var(--color-border-muted);
|
||||||
padding: 0.5rem 0.6rem 0.5rem 1rem;
|
padding: 0.5rem 0.6rem 0.5rem 0.8rem;
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 9;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Article = styled.article`
|
const Article = styled.article`
|
||||||
@@ -36,9 +48,9 @@ const Title = styled.h1`
|
|||||||
margin-left: 0.4rem;
|
margin-left: 0.4rem;
|
||||||
background-color: var(--color-border-muted);
|
background-color: var(--color-border-muted);
|
||||||
border-radius: 0.1rem;
|
border-radius: 0.1rem;
|
||||||
padding: 0 0.2rem;
|
padding: 0 0.2rem 0 0.1rem;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 0.1rem;
|
font-size: 0.7rem;
|
||||||
letter-spacing: -0.1rem;
|
letter-spacing: -0.1rem;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@@ -60,14 +72,16 @@ const Section = styled.section`
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--color-theme-text);
|
color: var(--color-theme-text);
|
||||||
padding: 0.1rem 0.3rem;
|
padding: 0.1rem 0.3rem;
|
||||||
box-shadow: inset 0 0 0 var(--color-accent-fg);
|
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
|
border-radius: 0.2rem;
|
||||||
&.active {
|
&.active {
|
||||||
|
background-color: var(--color-accent-fg);
|
||||||
box-shadow: inset 0 -0.3rem 0 var(--color-accent-fg);
|
box-shadow: inset 0 -0.3rem 0 var(--color-accent-fg);
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
&:hover:not(.active):not(:last-child) {
|
&:hover:not(.active):not(:last-child) {
|
||||||
box-shadow: inset 0 -1.5rem 0 var(--color-accent-fg);
|
background-color: var(--color-accent-fg);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 0.2rem;
|
border-radius: 0.2rem;
|
||||||
}
|
}
|
||||||
@@ -75,25 +89,30 @@ const Section = styled.section`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export function Layout() {
|
export function Layout() {
|
||||||
|
const { isLoading } = useContext(Context);
|
||||||
return (
|
return (
|
||||||
<Warpper className="wmde-markdown-color">
|
<Warpper className="wmde-markdown-color">
|
||||||
<Header>
|
<HeaderPlace>
|
||||||
<Article>
|
<Header className="header">
|
||||||
<Logo width={28} height={28} />
|
<Article className="logo">
|
||||||
<Title>
|
<Logo width={28} height={28} />
|
||||||
微信公众号排版编辑器
|
<Title>
|
||||||
<sup> v{VERSION} </sup>
|
微信公众号排版编辑器
|
||||||
</Title>
|
<sup> v{VERSION} </sup>
|
||||||
</Article>
|
</Title>
|
||||||
<Section>
|
{isLoading && <Loading />}
|
||||||
<NavLink to="/">首页</NavLink>
|
</Article>
|
||||||
<NavLink to="/editor/theme">编辑主题</NavLink>
|
<Section>
|
||||||
<dark-mode permanent dark="Dark" light="Light" />
|
<NavLink to="/">首页</NavLink>
|
||||||
<a href="https://github.com/jaywcjlove/wxmp" target="__blank">
|
<NavLink to="/editor/theme">编辑主题</NavLink>
|
||||||
<GithubIcon width={23} height={23} />
|
<NavLink to="/doc">文档</NavLink>
|
||||||
</a>
|
<dark-mode permanent dark="Dark" light="Light" />
|
||||||
</Section>
|
<a href="https://github.com/jaywcjlove/wxmp" target="__blank">
|
||||||
</Header>
|
<GithubIcon width={23} height={23} />
|
||||||
|
</a>
|
||||||
|
</Section>
|
||||||
|
</Header>
|
||||||
|
</HeaderPlace>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</Warpper>
|
</Warpper>
|
||||||
);
|
);
|
||||||
@@ -4,8 +4,9 @@ import { HashRouter } from 'react-router-dom';
|
|||||||
import BackToUp from '@uiw/react-back-to-top';
|
import BackToUp from '@uiw/react-back-to-top';
|
||||||
import { Toaster } from 'react-hot-toast';
|
import { Toaster } from 'react-hot-toast';
|
||||||
import { createGlobalStyle } from 'styled-components';
|
import { createGlobalStyle } from 'styled-components';
|
||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import { Provider } from './store/context';
|
import { Provider } from './store/Provider';
|
||||||
|
|
||||||
export const GlobalStyle = createGlobalStyle`
|
export const GlobalStyle = createGlobalStyle`
|
||||||
[data-color-mode*='dark'], [data-color-mode*='dark'] body {
|
[data-color-mode*='dark'], [data-color-mode*='dark'] body {
|
||||||
@@ -52,15 +53,20 @@ export const GlobalStyle = createGlobalStyle`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const queryClient = new QueryClient();
|
||||||
|
const style: React.CSSProperties = { zIndex: 999 };
|
||||||
|
|
||||||
const container = document.getElementById('root');
|
const container = document.getElementById('root');
|
||||||
const root = createRoot(container!);
|
const root = createRoot(container!);
|
||||||
root.render(
|
root.render(
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<BackToUp>Top</BackToUp>
|
<BackToUp style={style}>Top</BackToUp>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
<Provider>
|
<QueryClientProvider client={queryClient}>
|
||||||
<App />
|
<Provider>
|
||||||
</Provider>
|
<App />
|
||||||
|
</Provider>
|
||||||
|
</QueryClientProvider>
|
||||||
</HashRouter>,
|
</HashRouter>,
|
||||||
);
|
);
|
||||||
17
website/src/pages/docs/index.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import MarkdownEditor from '@uiw/react-markdown-editor';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { markdownString } from '../../store/context';
|
||||||
|
|
||||||
|
const Warpper = styled.div`
|
||||||
|
max-width: 59rem;
|
||||||
|
margin: 0 auto 0 auto;
|
||||||
|
padding: 0 1rem 3rem 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DocsPage = () => {
|
||||||
|
return (
|
||||||
|
<Warpper>
|
||||||
|
<MarkdownEditor.Markdown source={markdownString} />
|
||||||
|
</Warpper>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -5,15 +5,16 @@ import { Context } from '../../store/context';
|
|||||||
|
|
||||||
import { markdownToHTML } from '../../utils/markdownToHTML';
|
import { markdownToHTML } from '../../utils/markdownToHTML';
|
||||||
|
|
||||||
const Warpper = styled.div`
|
export const Warpper = styled.div`
|
||||||
width: 375px;
|
width: 375px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
box-shadow: 0 0 60px rgb(0 0 0 / 10%);
|
box-shadow: 0 0 60px rgb(0 0 0 / 10%);
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
font-size: 17px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Preview = (props: MarkdownPreviewProps) => {
|
export const Preview = (props: MarkdownPreviewProps) => {
|
||||||
const { css, markdown } = useContext(Context);
|
const { css, preColor, previewTheme } = useContext(Context);
|
||||||
const html = markdownToHTML(markdown, css);
|
const html = markdownToHTML(props.source || '', css, { preColor, previewTheme });
|
||||||
return <Warpper contentEditable spellCheck={false} dangerouslySetInnerHTML={{ __html: html }} />;
|
return <Warpper contentEditable spellCheck={false} dangerouslySetInnerHTML={{ __html: html }} />;
|
||||||
};
|
};
|
||||||
@@ -1,35 +1,32 @@
|
|||||||
import MarkdownEditor, { getCommands } from '@uiw/react-markdown-editor';
|
import MarkdownEditor, { getCommands } from '@uiw/react-markdown-editor';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
// @ts-ignore
|
||||||
import { EditorView } from '@codemirror/view';
|
import { EditorView } from '@codemirror/view';
|
||||||
import styled from 'styled-components';
|
|
||||||
import { Preview } from './Preview';
|
import { Preview } from './Preview';
|
||||||
import { copy } from '../../commands/copy';
|
import { copy } from '../../commands/copy';
|
||||||
|
import { colorCommand } from '../../commands/color';
|
||||||
import { theme as themeCommand, previeTheme } from '../../commands/theme';
|
import { theme as themeCommand, previeTheme } from '../../commands/theme';
|
||||||
import { cssCommand } from '../../commands/css';
|
import { cssCommand } from '../../commands/css';
|
||||||
import { Context, themes } from '../../store/context';
|
import { Context, themes } from '../../store/context';
|
||||||
|
|
||||||
const Warpper = styled.div`
|
|
||||||
height: calc(100vh - 2.9rem);
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const HomePage = () => {
|
export const HomePage = () => {
|
||||||
const commands = [...getCommands(), themeCommand];
|
const commands = [...getCommands(), themeCommand];
|
||||||
const { theme, markdown, setMarkdown } = useContext(Context);
|
const { theme, markdown, isLoading, setMarkdown } = useContext(Context);
|
||||||
const themeValue = themes[theme].value;
|
const themeValue = themes[theme].value;
|
||||||
const handleChange = (value: string) => setMarkdown(value);
|
const handleChange = (value: string) => setMarkdown(value);
|
||||||
return (
|
return (
|
||||||
<Warpper>
|
<MarkdownEditor
|
||||||
<MarkdownEditor
|
value={markdown}
|
||||||
value={markdown}
|
toolbars={commands}
|
||||||
toolbars={commands}
|
theme={themeValue}
|
||||||
theme={themeValue}
|
readOnly={isLoading}
|
||||||
toolbarsMode={[cssCommand, previeTheme, copy, 'preview', 'fullscreen']}
|
toolbarsMode={[cssCommand, previeTheme, copy, colorCommand, 'fullscreen', 'preview']}
|
||||||
extensions={[EditorView.lineWrapping]}
|
extensions={[EditorView.lineWrapping]}
|
||||||
renderPreview={Preview}
|
renderPreview={Preview}
|
||||||
onChange={handleChange}
|
previewWidth="420px"
|
||||||
visible={true}
|
onChange={handleChange}
|
||||||
height="calc(100vh - 4.92rem)"
|
visible={true}
|
||||||
/>
|
height="calc(100vh - 4.6rem)"
|
||||||
</Warpper>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
11
website/src/pages/theme/Preview.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { Context } from '../../store/context';
|
||||||
|
|
||||||
|
import { markdownToHTML } from '../../utils/markdownToHTML';
|
||||||
|
import { Warpper } from '../home/Preview';
|
||||||
|
|
||||||
|
export const Preview = () => {
|
||||||
|
const { css, markdown, preColor, previewTheme } = useContext(Context);
|
||||||
|
const html = markdownToHTML(markdown, css, { preColor, previewTheme });
|
||||||
|
return <Warpper contentEditable spellCheck={false} dangerouslySetInnerHTML={{ __html: html }} />;
|
||||||
|
};
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import MarkdownEditor, { IMarkdownEditor } from '@uiw/react-markdown-editor';
|
import MarkdownEditor, { IMarkdownEditor } from '@uiw/react-markdown-editor';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { EditorView } from '@codemirror/view';
|
import { EditorView } from '@codemirror/view';
|
||||||
import styled from 'styled-components';
|
|
||||||
import { css as cssLang } from '@codemirror/lang-css';
|
import { css as cssLang } from '@codemirror/lang-css';
|
||||||
import { Preview } from './Preview';
|
import { Preview } from './Preview';
|
||||||
import { copy } from '../../commands/copy';
|
import { copy } from '../../commands/copy';
|
||||||
@@ -10,29 +9,25 @@ import { themeTitle } from '../../commands/title';
|
|||||||
import { theme as themeCommand, previeTheme } from '../../commands/theme';
|
import { theme as themeCommand, previeTheme } from '../../commands/theme';
|
||||||
import { Context, themes } from '../../store/context';
|
import { Context, themes } from '../../store/context';
|
||||||
|
|
||||||
const Warpper = styled.div`
|
|
||||||
height: calc(100vh - 2.9rem);
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const EditorPage = () => {
|
export const EditorPage = () => {
|
||||||
const commands = [themeTitle, themeCommand, previousCommand];
|
const commands = [themeTitle, themeCommand, previousCommand];
|
||||||
const toolbarsMode: IMarkdownEditor['toolbarsMode'] = [previeTheme, copy, 'preview', 'fullscreen'];
|
const toolbarsMode: IMarkdownEditor['toolbarsMode'] = [previeTheme, copy, 'fullscreen', 'preview'];
|
||||||
const { theme, css, setCss } = useContext(Context);
|
const { theme, css, setCss, isLoading } = useContext(Context);
|
||||||
const value = themes[theme].value;
|
const value = themes[theme].value;
|
||||||
const handleChange = (value: string) => setCss(value);
|
const handleChange = (value: string) => setCss(value);
|
||||||
return (
|
return (
|
||||||
<Warpper>
|
<MarkdownEditor
|
||||||
<MarkdownEditor
|
value={css}
|
||||||
value={css}
|
theme={value}
|
||||||
theme={value}
|
readOnly={isLoading}
|
||||||
toolbars={commands}
|
toolbars={commands}
|
||||||
toolbarsMode={toolbarsMode}
|
toolbarsMode={toolbarsMode}
|
||||||
reExtensions={[EditorView.lineWrapping, cssLang()]}
|
reExtensions={[EditorView.lineWrapping, cssLang()]}
|
||||||
renderPreview={Preview}
|
renderPreview={Preview}
|
||||||
onChange={handleChange}
|
previewWidth="420px"
|
||||||
visible={true}
|
onChange={handleChange}
|
||||||
height="calc(100vh - 4.92rem)"
|
visible={true}
|
||||||
/>
|
height="calc(100vh - 4.6rem)"
|
||||||
</Warpper>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
53
website/src/store/Provider.tsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
import { PreviewThemeValue, previewThemes, ThemeValue, Context, markdownString } from './context';
|
||||||
|
import { useMdSource } from './getMdSource';
|
||||||
|
|
||||||
|
export const Provider: React.FC<React.PropsWithChildren> = ({ children }) => {
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
const paramPreviewTheme = searchParams.get('theme') as PreviewThemeValue;
|
||||||
|
const initPreviewTheme = paramPreviewTheme || 'underscore';
|
||||||
|
const mdurl = searchParams.get('md');
|
||||||
|
const [markdown, setMarkdown] = React.useState<string>(mdurl ? '' : markdownString);
|
||||||
|
const [css, setCss] = React.useState<string>(previewThemes[initPreviewTheme].value);
|
||||||
|
const [previewTheme, setPreviewTheme] = React.useState<PreviewThemeValue>(initPreviewTheme);
|
||||||
|
const [theme, setTheme] = React.useState<ThemeValue>('default');
|
||||||
|
const [preColor, setPreColor] = React.useState<string>(
|
||||||
|
previewThemes[initPreviewTheme] ? previewThemes[initPreviewTheme].color : '',
|
||||||
|
);
|
||||||
|
const [isLoading, setIsLoading] = React.useState<boolean>(true);
|
||||||
|
const { data: mddata, isLoading: loading } = useMdSource(mdurl);
|
||||||
|
useEffect(() => {
|
||||||
|
if (paramPreviewTheme !== previewTheme) {
|
||||||
|
searchParams.set('theme', previewTheme);
|
||||||
|
setSearchParams(searchParams);
|
||||||
|
}
|
||||||
|
}, [paramPreviewTheme, previewTheme, searchParams, setSearchParams]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (mdurl) {
|
||||||
|
setMarkdown(mddata || '');
|
||||||
|
}
|
||||||
|
}, [mddata, mdurl]);
|
||||||
|
useEffect(() => setIsLoading(loading), [loading]);
|
||||||
|
useEffect(() => setPreColor(previewThemes[initPreviewTheme].color), [initPreviewTheme]);
|
||||||
|
return (
|
||||||
|
<Context.Provider
|
||||||
|
value={{
|
||||||
|
preColor,
|
||||||
|
setPreColor,
|
||||||
|
isLoading,
|
||||||
|
setIsLoading,
|
||||||
|
markdown,
|
||||||
|
setMarkdown,
|
||||||
|
css,
|
||||||
|
setCss,
|
||||||
|
previewTheme,
|
||||||
|
setPreviewTheme,
|
||||||
|
theme,
|
||||||
|
setTheme,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Context.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React from 'react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
|
||||||
import { defaultTheme } from '@uiw/react-markdown-editor';
|
import { defaultTheme } from '@uiw/react-markdown-editor';
|
||||||
import { abcdef } from '@uiw/codemirror-theme-abcdef';
|
import { abcdef } from '@uiw/codemirror-theme-abcdef';
|
||||||
import { androidstudio } from '@uiw/codemirror-theme-androidstudio';
|
import { androidstudio } from '@uiw/codemirror-theme-androidstudio';
|
||||||
@@ -19,7 +18,9 @@ import simpleStyle from '../themes/simple.md.css';
|
|||||||
import underscoreStyle from '../themes/underscore.md.css';
|
import underscoreStyle from '../themes/underscore.md.css';
|
||||||
import baseStyle from '../themes/base.md.css';
|
import baseStyle from '../themes/base.md.css';
|
||||||
|
|
||||||
import data from '../../README.md';
|
import data from '../../../README.md';
|
||||||
|
|
||||||
|
export const markdownString = data.source;
|
||||||
|
|
||||||
export const themes = {
|
export const themes = {
|
||||||
default: {
|
default: {
|
||||||
@@ -96,25 +97,66 @@ export const previewThemes = {
|
|||||||
default: {
|
default: {
|
||||||
label: '翡翠绿',
|
label: '翡翠绿',
|
||||||
value: defStyle,
|
value: defStyle,
|
||||||
|
color: '#009874',
|
||||||
},
|
},
|
||||||
simple: {
|
simple: {
|
||||||
label: '简洁蓝',
|
label: '简洁蓝',
|
||||||
value: simpleStyle,
|
value: simpleStyle,
|
||||||
|
color: '#0f4c81',
|
||||||
},
|
},
|
||||||
underscore: {
|
underscore: {
|
||||||
label: '下划线黄',
|
label: '下划线黄',
|
||||||
value: underscoreStyle,
|
value: underscoreStyle,
|
||||||
|
color: '#ffb11b',
|
||||||
},
|
},
|
||||||
base: {
|
base: {
|
||||||
label: '简洁',
|
label: '简洁',
|
||||||
value: baseStyle,
|
value: baseStyle,
|
||||||
|
color: '',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 用于全局主题替换样式 */
|
||||||
|
export const replaceData: Record<PreviewThemeValue, ReplaceData[]> = {
|
||||||
|
underscore: [
|
||||||
|
{ select: 'a', name: 'color', value: '{{color}}' },
|
||||||
|
{ select: 'h1', name: 'box-shadow', value: 'inset 0 -0.9rem 0 0 {{color}}' },
|
||||||
|
{ select: 'h2', name: 'box-shadow', value: 'inset 0 -0.7rem 0 0 {{color}}' },
|
||||||
|
{ select: 'h3', name: 'border-left', value: '5px solid {{color}}' },
|
||||||
|
],
|
||||||
|
default: [
|
||||||
|
{ select: 'a', name: 'color', value: '{{color}}' },
|
||||||
|
{ select: 'h1', name: 'border-bottom', value: '3px solid {{color}}' },
|
||||||
|
{ select: 'h2', name: 'background', value: '{{color}}' },
|
||||||
|
{ select: 'h3', name: 'border-left', value: '5px solid {{color}}' },
|
||||||
|
],
|
||||||
|
simple: [
|
||||||
|
{ select: 'a', name: 'color', value: '{{color}}' },
|
||||||
|
{ select: 'h1', name: 'border-bottom', value: '3px solid {{color}}' },
|
||||||
|
{ select: 'h2', name: 'background', value: '{{color}}' },
|
||||||
|
{ select: 'h3', name: 'border-left', value: '5px solid {{color}}' },
|
||||||
|
{ select: '.code-spans', name: 'color', value: '{{color}}' },
|
||||||
|
],
|
||||||
|
base: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ReplaceData = {
|
||||||
|
select: string;
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const colors = (Object.keys(previewThemes) as Array<keyof typeof previewThemes>).map(
|
||||||
|
(key) => previewThemes[key].color,
|
||||||
|
);
|
||||||
export type ThemeValue = keyof typeof themes;
|
export type ThemeValue = keyof typeof themes;
|
||||||
export type PreviewThemeValue = keyof typeof previewThemes;
|
export type PreviewThemeValue = keyof typeof previewThemes;
|
||||||
|
|
||||||
export interface CreateContext {
|
export interface CreateContext {
|
||||||
|
preColor: string;
|
||||||
|
setPreColor: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
isLoading: boolean;
|
||||||
|
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
markdown: string;
|
markdown: string;
|
||||||
setMarkdown: React.Dispatch<React.SetStateAction<string>>;
|
setMarkdown: React.Dispatch<React.SetStateAction<string>>;
|
||||||
css: string;
|
css: string;
|
||||||
@@ -126,6 +168,10 @@ export interface CreateContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Context = React.createContext<CreateContext>({
|
export const Context = React.createContext<CreateContext>({
|
||||||
|
preColor: '',
|
||||||
|
setPreColor: () => {},
|
||||||
|
isLoading: true,
|
||||||
|
setIsLoading: () => {},
|
||||||
markdown: data.source,
|
markdown: data.source,
|
||||||
setMarkdown: () => {},
|
setMarkdown: () => {},
|
||||||
css: previewThemes['underscore'].value,
|
css: previewThemes['underscore'].value,
|
||||||
@@ -135,35 +181,3 @@ export const Context = React.createContext<CreateContext>({
|
|||||||
theme: 'default',
|
theme: 'default',
|
||||||
setTheme: () => {},
|
setTheme: () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Provider: React.FC<React.PropsWithChildren> = ({ children }) => {
|
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
|
||||||
const paramPreviewTheme = searchParams.get('theme') as PreviewThemeValue;
|
|
||||||
const initPreviewTheme = paramPreviewTheme || 'underscore';
|
|
||||||
const [markdown, setMarkdown] = React.useState<string>(data.source);
|
|
||||||
const [css, setCss] = React.useState<string>(previewThemes[initPreviewTheme].value);
|
|
||||||
const [previewTheme, setPreviewTheme] = React.useState<PreviewThemeValue>(initPreviewTheme);
|
|
||||||
const [theme, setTheme] = React.useState<ThemeValue>('default');
|
|
||||||
useEffect(() => {
|
|
||||||
if (paramPreviewTheme !== previewTheme) {
|
|
||||||
searchParams.set('theme', previewTheme);
|
|
||||||
setSearchParams(searchParams);
|
|
||||||
}
|
|
||||||
}, [paramPreviewTheme, previewTheme, searchParams, setSearchParams]);
|
|
||||||
return (
|
|
||||||
<Context.Provider
|
|
||||||
value={{
|
|
||||||
markdown,
|
|
||||||
setMarkdown,
|
|
||||||
css,
|
|
||||||
setCss,
|
|
||||||
previewTheme,
|
|
||||||
setPreviewTheme,
|
|
||||||
theme,
|
|
||||||
setTheme,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Context.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
25
website/src/store/getMdSource.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const Warpper = styled.div`
|
||||||
|
font-size: 0.8rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const useMdSource = (url: string | null) => {
|
||||||
|
return useQuery(['database-list', url], () => {
|
||||||
|
if (!url) return Promise.resolve('');
|
||||||
|
return fetch(url)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((data) => {
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(
|
||||||
|
<Warpper>
|
||||||
|
加载失败!<a href={url}>请检查你的URL</a>
|
||||||
|
</Warpper>,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -5,14 +5,14 @@ a {
|
|||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-size: 1.5rem;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
margin: 2.5rem 0 1rem 0;
|
margin: 2.5rem 0 1rem 0;
|
||||||
font-size: 1.3em;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,19 +20,20 @@ h3 {
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
margin: 1em 0 1em 0;
|
margin: 1em 0 1em 0;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1em;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
margin: 0.6em 0 0.6em 0;
|
margin: 0.6em 0 0.6em 0;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 0.9em;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: initial;
|
color: initial;
|
||||||
font-size: 0.85em;
|
font-size: 16px;
|
||||||
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@@ -45,13 +46,15 @@ ol {
|
|||||||
|
|
||||||
li {
|
li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
@@ -60,7 +63,7 @@ pre {
|
|||||||
padding: 1em;
|
padding: 1em;
|
||||||
color: rgb(51, 51, 51);
|
color: rgb(51, 51, 51);
|
||||||
background: rgb(248, 248, 248);
|
background: rgb(248, 248, 248);
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
word-spacing: 0px;
|
word-spacing: 0px;
|
||||||
@@ -73,7 +76,7 @@ table {
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
@@ -90,7 +93,7 @@ th {
|
|||||||
.code-highlight {
|
.code-highlight {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-family: Menlo, 'Operator Mono', Consolas, Monaco, monospace;
|
font-family: Menlo, 'Operator Mono', Consolas, Monaco, monospace;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -103,26 +106,28 @@ th {
|
|||||||
.code-spans {
|
.code-spans {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
white-space: pre;
|
white-space: initial;
|
||||||
background: rgba(27, 31, 35, 0.05);
|
background: rgba(27, 31, 35, 0.05);
|
||||||
padding: 0.2em 0.6em;
|
padding: 0.1em 0.3em;
|
||||||
border-radius: 0.6em;
|
border-radius: 0.3em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 0.45em;
|
font-size: 1em;
|
||||||
|
top: -0.1em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnotes-title {
|
.footnotes-title {
|
||||||
display: table;
|
display: table;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1em;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 3rem 0 0.6rem 0;
|
margin: 3rem 0 0.6rem 0;
|
||||||
padding-left: 0.2rem;
|
padding-left: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnotes-list {
|
.footnotes-list {
|
||||||
font-size: 0.75em;
|
font-size: 10px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
margin: 0.4rem 0;
|
margin: 0.4rem 0;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
a {
|
a {
|
||||||
color: #576b95;
|
color: #009874;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -11,11 +11,11 @@ h1 {
|
|||||||
line-height: 1.75;
|
line-height: 1.75;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1em;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 2em auto 1em;
|
margin: 2em auto 1em;
|
||||||
padding: 0 1em;
|
padding: 0 1em;
|
||||||
border-bottom: 2px solid #009874;
|
border-bottom: 3px solid #009874;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ h2 {
|
|||||||
line-height: 1.75;
|
line-height: 1.75;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1.3em;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 4em auto 2em;
|
margin: 4em auto 2em;
|
||||||
padding: 0 0.3em;
|
padding: 0 0.3em;
|
||||||
@@ -34,21 +34,17 @@ h2 {
|
|||||||
background: #009874;
|
background: #009874;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 0.85em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #3f3f3f;
|
color: #3f3f3f;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1.1em;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 2em 8px 0.75em 0;
|
margin: 2em 8px 0.75em 0;
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
border-left: 3px solid #009874;
|
border-left: 5px solid #009874;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@@ -62,22 +58,29 @@ ol {
|
|||||||
li {
|
li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
color: rgb(30 41 59);
|
font-size: 14px;
|
||||||
font-size: 0.85em;
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
padding: 0.5em 0 !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
margin-top: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1.75;
|
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
padding: 0.1rem 1rem;
|
padding: 0.5em 1em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: rgba(27, 31, 35, 0.05);
|
background: rgba(27, 31, 35, 0.05);
|
||||||
margin: 1rem 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
@@ -111,7 +114,7 @@ table {
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
@@ -129,7 +132,7 @@ th {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1.75;
|
line-height: 1.75;
|
||||||
font-family: Menlo, 'Operator Mono', Consolas, Monaco, monospace;
|
font-family: Menlo, 'Operator Mono', Consolas, Monaco, monospace;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -142,27 +145,29 @@ th {
|
|||||||
.code-spans {
|
.code-spans {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
white-space: pre;
|
white-space: initial;
|
||||||
color: #009874;
|
color: #333;
|
||||||
background: rgba(27, 31, 35, 0.05);
|
background: rgba(27, 31, 35, 0.05);
|
||||||
padding: 0.2em 0.6em;
|
padding: 0.1em 0.3em;
|
||||||
border-radius: 0.6em;
|
border-radius: 0.3em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 0.45em;
|
font-size: 1em;
|
||||||
|
top: -0.1em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnotes-title {
|
.footnotes-title {
|
||||||
display: table;
|
display: table;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1em;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 3em 0 0.6em 0;
|
margin: 3em 0 0.6em 0;
|
||||||
padding-left: 0.2em;
|
padding-left: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnotes-list {
|
.footnotes-list {
|
||||||
font-size: 0.75em;
|
font-size: 10px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
margin: 0.4rem 0;
|
margin: 0.4rem 0;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
a {
|
a {
|
||||||
color: #576b95;
|
color: #0f4c81;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -11,11 +11,11 @@ h1 {
|
|||||||
line-height: 1.75;
|
line-height: 1.75;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1.2em;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 2em auto 1em;
|
margin: 2em auto 1em;
|
||||||
padding: 0 1em;
|
padding: 0 1em;
|
||||||
border-bottom: 2px solid #0f4c81;
|
border-bottom: 3px solid #0f4c81;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ h2 {
|
|||||||
line-height: 1.75;
|
line-height: 1.75;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1.2em;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 4em auto 2em;
|
margin: 4em auto 2em;
|
||||||
padding: 0 0.3em;
|
padding: 0 0.3em;
|
||||||
@@ -34,21 +34,17 @@ h2 {
|
|||||||
background: #0f4c81;
|
background: #0f4c81;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 0.85em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #3f3f3f;
|
color: #3f3f3f;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1.1em;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 2em 8px 0.75em 0;
|
margin: 2em 8px 0.75em 0;
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
border-left: 3px solid #0f4c81;
|
border-left: 5px solid #0f4c81;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@@ -62,22 +58,29 @@ ol {
|
|||||||
li {
|
li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
color: rgb(30 41 59);
|
font-size: 14px;
|
||||||
font-size: 0.85em;
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
padding: 0.5em 0 !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
margin-top: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1.75;
|
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
padding: 0.1rem 1rem;
|
padding: 0.5em 1em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: rgba(27, 31, 35, 0.05);
|
background: rgba(27, 31, 35, 0.05);
|
||||||
margin: 1rem 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
@@ -111,7 +114,7 @@ table {
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
@@ -129,7 +132,7 @@ th {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1.75;
|
line-height: 1.75;
|
||||||
font-family: Menlo, 'Operator Mono', Consolas, Monaco, monospace;
|
font-family: Menlo, 'Operator Mono', Consolas, Monaco, monospace;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -142,27 +145,29 @@ th {
|
|||||||
.code-spans {
|
.code-spans {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
white-space: pre;
|
white-space: initial;
|
||||||
color: #0f4c81;
|
color: #0f4c81;
|
||||||
background: rgba(27, 31, 35, 0.05);
|
background: rgba(27, 31, 35, 0.05);
|
||||||
padding: 0.2em 0.6em;
|
padding: 0.1em 0.3em;
|
||||||
border-radius: 0.6em;
|
border-radius: 0.3em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 0.45em;
|
font-size: 14px;
|
||||||
|
top: -0.1em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnotes-title {
|
.footnotes-title {
|
||||||
display: table;
|
display: table;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1em;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 3em 0 0.6em 0;
|
margin: 3em 0 0.6em 0;
|
||||||
padding-left: 0.2em;
|
padding-left: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnotes-list {
|
.footnotes-list {
|
||||||
font-size: 0.75em;
|
font-size: 10px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
margin: 0.4rem 0;
|
margin: 0.4rem 0;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
a {
|
a {
|
||||||
color: #576b95;
|
color: #ffb11b;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -11,7 +11,7 @@ h1 {
|
|||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1.3em;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 2em auto 1em;
|
margin: 2em auto 1em;
|
||||||
padding: 0 1em 0.3em 1em;
|
padding: 0 1em 0.3em 1em;
|
||||||
@@ -24,24 +24,20 @@ h2 {
|
|||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1.2em;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 0 0.3em;
|
padding: 0 0.3em;
|
||||||
margin: 2em 0 1em 0;
|
margin: 2em 0 1em 0;
|
||||||
box-shadow: inset 0 -0.7rem 0 0 #ffb11b;
|
box-shadow: inset 0 -0.7rem 0 0 #ffb11b;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 0.85em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #3f3f3f;
|
color: #3f3f3f;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1.1em;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 2em 8px 0.75em 0;
|
margin: 2em 8px 0.75em 0;
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
@@ -59,22 +55,29 @@ ol {
|
|||||||
li {
|
li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
color: rgb(30 41 59);
|
font-size: 14px;
|
||||||
font-size: 0.85em;
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
padding: 0.5em 0 !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
margin-top: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1.75;
|
line-height: 1.5em;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
padding: 0.1rem 1rem;
|
padding: 0.5em 1em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: rgba(27, 31, 35, 0.05);
|
background: rgba(27, 31, 35, 0.05);
|
||||||
margin: 1rem 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
@@ -108,7 +111,7 @@ table {
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
@@ -126,7 +129,7 @@ th {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1.75;
|
line-height: 1.75;
|
||||||
font-family: Menlo, 'Operator Mono', Consolas, Monaco, monospace;
|
font-family: Menlo, 'Operator Mono', Consolas, Monaco, monospace;
|
||||||
font-size: 0.85em;
|
font-size: 14px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -139,27 +142,29 @@ th {
|
|||||||
.code-spans {
|
.code-spans {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
white-space: pre;
|
white-space: initial;
|
||||||
color: #ffb11b;
|
color: #333;
|
||||||
background: rgba(27, 31, 35, 0.05);
|
background: rgba(27, 31, 35, 0.05);
|
||||||
padding: 0.2em 0.6em;
|
padding: 0.1em 0.3em;
|
||||||
border-radius: 0.6em;
|
border-radius: 0.3em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 0.45em;
|
font-size: 14px;
|
||||||
|
top: -0.1em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnotes-title {
|
.footnotes-title {
|
||||||
display: table;
|
display: table;
|
||||||
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB',
|
||||||
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;
|
||||||
font-size: 1em;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 3em 0 0.6em 0;
|
margin: 3em 0 0.6em 0;
|
||||||
padding-left: 0.2em;
|
padding-left: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnotes-list {
|
.footnotes-list {
|
||||||
font-size: 0.75em;
|
font-size: 10px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
margin: 0.4rem 0;
|
margin: 0.4rem 0;
|
||||||
@@ -1,20 +1,55 @@
|
|||||||
import { RootContent, Element, Text, Root } from 'hast';
|
import { RootContent, Element, Text, Root } from 'hast';
|
||||||
|
import { PreviewThemeValue, replaceData, ReplaceData } from '../store/context';
|
||||||
|
|
||||||
export const getBlock = (data: any, str: string = '') => {
|
/**
|
||||||
|
* {
|
||||||
|
* "replace": [
|
||||||
|
* { select: 'a', name: 'color', value: 'red' },
|
||||||
|
* { select: 'h1', name: 'box-shadow', value: 'red' },
|
||||||
|
* { select: 'h2', name: 'box-shadow', value: 'red' },
|
||||||
|
* { select: 'h3', name: 'border-left', value: 'red' },
|
||||||
|
* { select: 'h3', name: 'color', value: 'red' },
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
type BlockOption = {
|
||||||
|
replace?: Array<ReplaceData>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getBlock = (data: any, str: string = '', opts: BlockOption = {}) => {
|
||||||
|
const { replace } = opts;
|
||||||
if (data && data.data && data.data.type === 'Declaration') {
|
if (data && data.data && data.data.type === 'Declaration') {
|
||||||
str = `${data.data.property}: ${data.data.value.value}${data.data.important ? ' !important' : ''};`;
|
const value = replace?.find((m) => m.name === data.data.property)?.value || data.data.value.value;
|
||||||
|
// console.log(value)
|
||||||
|
str = `${data.data.property}: ${value}${data.data.important ? ' !important' : ''};`;
|
||||||
if (data.next) {
|
if (data.next) {
|
||||||
str += getBlock(data.next);
|
str += getBlock(data.next, '', opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cssdata = (list: any, result: Record<string, string> = {}) => {
|
type Cssdata = {
|
||||||
|
theme?: PreviewThemeValue;
|
||||||
|
color?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const cssdata = (list: any, result: Record<string, string> = {}, opts: Cssdata = {}) => {
|
||||||
if (list.data && list.data.type === 'Rule') {
|
if (list.data && list.data.type === 'Rule') {
|
||||||
result[list.data.prelude.value] = getBlock(list.data.block.children.head);
|
const selector = list.data.prelude.value;
|
||||||
|
const options: BlockOption = {};
|
||||||
|
// console.log('opts:', opts)
|
||||||
|
if (opts.color && opts.theme && replaceData[opts.theme]) {
|
||||||
|
options.replace = replaceData[opts.theme]
|
||||||
|
.filter((m) => m.select === selector)
|
||||||
|
.map((m) => ({
|
||||||
|
...m,
|
||||||
|
value: m.value.replace('{{color}}', opts.color!),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
result[selector] = getBlock(list.data.block.children.head, '', options);
|
||||||
if (list.next) {
|
if (list.next) {
|
||||||
result = cssdata(list.next, { ...result });
|
result = cssdata(list.next, { ...result }, opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -29,7 +64,6 @@ export const spaceEscape = (node: RootContent) => {
|
|||||||
}
|
}
|
||||||
node.properties.className = className.filter((str: string) => !/(token|control-flow)/.test(str));
|
node.properties.className = className.filter((str: string) => !/(token|control-flow)/.test(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
node.children.map((elm) => {
|
node.children.map((elm) => {
|
||||||
if (elm.type === 'element' && elm.children) {
|
if (elm.type === 'element' && elm.children) {
|
||||||
spaceEscape(elm);
|
spaceEscape(elm);
|
||||||
@@ -95,7 +129,7 @@ export const footnotesLabel = (node: Element) => {
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const imagesStyle = (node: Element, parent: Root | Element | null) => {
|
export const imagesStyle = (node: Element, parent: Root | Element | undefined) => {
|
||||||
if (
|
if (
|
||||||
parent?.type === 'element' &&
|
parent?.type === 'element' &&
|
||||||
/(p|a)/.test(parent.tagName) &&
|
/(p|a)/.test(parent.tagName) &&
|
||||||
@@ -5,7 +5,10 @@ import { Element } from 'hast';
|
|||||||
import remarkParse from 'remark-parse';
|
import remarkParse from 'remark-parse';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
import remarkRehype from 'remark-rehype';
|
import remarkRehype from 'remark-rehype';
|
||||||
|
import remarkMath from 'remark-math';
|
||||||
import rehypePrism from 'rehype-prism-plus';
|
import rehypePrism from 'rehype-prism-plus';
|
||||||
|
import rehypeKatex from 'rehype-katex';
|
||||||
|
import 'katex/dist/katex.min.css'; // Ensure KaTeX styles are included
|
||||||
import rehypeRaw from 'rehype-raw';
|
import rehypeRaw from 'rehype-raw';
|
||||||
import rehypeAttrs from 'rehype-attr';
|
import rehypeAttrs from 'rehype-attr';
|
||||||
import rehypeIgnore from 'rehype-ignore';
|
import rehypeIgnore from 'rehype-ignore';
|
||||||
@@ -13,9 +16,12 @@ import rehypeRewrite from 'rehype-rewrite';
|
|||||||
import stringify from 'rehype-stringify';
|
import stringify from 'rehype-stringify';
|
||||||
import { cssdata, spaceEscape, footnotes, footnotesLabel, imagesStyle } from './css';
|
import { cssdata, spaceEscape, footnotes, footnotesLabel, imagesStyle } from './css';
|
||||||
|
|
||||||
export type MarkdownToHTMLOptions = {};
|
export type MarkdownToHTMLOptions = {
|
||||||
|
preColor?: string;
|
||||||
|
previewTheme?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export function markdownToHTML(md: string, css: string, options: MarkdownToHTMLOptions = {}) {
|
export function markdownToHTML(md: string, css: string, opts: MarkdownToHTMLOptions = {}) {
|
||||||
const ast = csstree.parse(css, {
|
const ast = csstree.parse(css, {
|
||||||
parseAtrulePrelude: false,
|
parseAtrulePrelude: false,
|
||||||
parseRulePrelude: false,
|
parseRulePrelude: false,
|
||||||
@@ -23,19 +29,23 @@ export function markdownToHTML(md: string, css: string, options: MarkdownToHTMLO
|
|||||||
parseCustomProperty: false,
|
parseCustomProperty: false,
|
||||||
positions: false,
|
positions: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const data = cssdata(ast.children.head);
|
const data = cssdata(ast.children.head, {}, { color: opts.preColor, theme: opts.previewTheme });
|
||||||
const processor = unified()
|
const processor = unified()
|
||||||
.use(remarkParse)
|
.use(remarkParse)
|
||||||
.use(remarkGfm)
|
.use(remarkGfm)
|
||||||
|
.use(remarkMath)
|
||||||
.use(remarkRehype, { allowDangerousHtml: true })
|
.use(remarkRehype, { allowDangerousHtml: true })
|
||||||
.use(rehypePrism)
|
|
||||||
.use(rehypeRaw)
|
.use(rehypeRaw)
|
||||||
|
.use(rehypeKatex)
|
||||||
|
.use(rehypePrism, {
|
||||||
|
ignoreMissing: true,
|
||||||
|
})
|
||||||
.use(rehypeIgnore, {})
|
.use(rehypeIgnore, {})
|
||||||
.use(rehypeAttrs, { properties: 'attr' })
|
.use(rehypeAttrs, { properties: 'attr' })
|
||||||
.use(rehypeRewrite, {
|
.use(rehypeRewrite, {
|
||||||
rewrite: (node, index, parent) => {
|
rewrite: (node, _index, parent) => {
|
||||||
// @ts-ignore
|
|
||||||
if (
|
if (
|
||||||
node?.type === 'element' &&
|
node?.type === 'element' &&
|
||||||
node?.tagName === 'code' &&
|
node?.tagName === 'code' &&
|
||||||