forked from iarv/vscode-front-matter
Compare commits
330 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d364bde59d | ||
|
|
8ae105fd6e | ||
|
|
3a8854b060 | ||
|
|
af393bbfc5 | ||
|
|
76707b9eee | ||
|
|
8042a25fbb | ||
|
|
1a3520833b | ||
|
|
1b1eac0a43 | ||
|
|
6b19e69806 | ||
|
|
04960b7fdb | ||
|
|
3ca979bea9 | ||
|
|
12ecee8c49 | ||
|
|
680ea99f05 | ||
|
|
39cee294af | ||
|
|
558845a8d2 | ||
|
|
327559fdd7 | ||
|
|
2efbfa7820 | ||
|
|
cdeaa87321 | ||
|
|
483cfcd761 | ||
|
|
74bc8d78a0 | ||
|
|
bc88df98ee | ||
|
|
d48e63ba32 | ||
|
|
20ee0e1ca5 | ||
|
|
716f7d1f0c | ||
|
|
5119f631f3 | ||
|
|
4eea855d0f | ||
|
|
5354619283 | ||
|
|
dd939f4b7a | ||
|
|
2635cc9b6d | ||
|
|
c843e74077 | ||
|
|
baed139cc6 | ||
|
|
38839470ac | ||
|
|
8a4b24396c | ||
|
|
4a50cf70a0 | ||
|
|
db38b9da68 | ||
|
|
2b7f124582 | ||
|
|
089f0a643d | ||
|
|
9c9102f6f5 | ||
|
|
c95d79a218 | ||
|
|
c0b1e4383f | ||
|
|
ddf2873794 | ||
|
|
faf629cca5 | ||
|
|
bf4b66564c | ||
|
|
5c62255605 | ||
|
|
4f91aeb80b | ||
|
|
e19b4d7d6c | ||
|
|
7f02fe34ba | ||
|
|
5dec859849 | ||
|
|
5e1558ecfa | ||
|
|
8a099de859 | ||
|
|
ddef00726b | ||
|
|
70316c4c28 | ||
|
|
50f2e7ea72 | ||
|
|
663d346e2e | ||
|
|
d42561fbf5 | ||
|
|
0c5224b5f9 | ||
|
|
cfa805add9 | ||
|
|
86a8ef68b6 | ||
|
|
cc2c6dc217 | ||
|
|
1764965aa7 | ||
|
|
12559bae4a | ||
|
|
fc1d750c5e | ||
|
|
85c4a869e3 | ||
|
|
8b3889f997 | ||
|
|
75b01cde7b | ||
|
|
c75ab2a07b | ||
|
|
a12cf70a80 | ||
|
|
4b1d80f04b | ||
|
|
a84fecaf96 | ||
|
|
5b9c279fa2 | ||
|
|
f67be9efb9 | ||
|
|
4c50100230 | ||
|
|
82ace03692 | ||
|
|
576d07fdef | ||
|
|
f6bc4fb630 | ||
|
|
c35f4ab070 | ||
|
|
59cbc03b0c | ||
|
|
0ea06a841e | ||
|
|
b54eb5a360 | ||
|
|
16b6fff6dc | ||
|
|
7a46729a46 | ||
|
|
32182c3df0 | ||
|
|
78587509b3 | ||
|
|
e3bd7eebbe | ||
|
|
f1a8e0d425 | ||
|
|
33e294d702 | ||
|
|
e098442eaa | ||
|
|
1de14122c5 | ||
|
|
c0838fffd4 | ||
|
|
082c25144f | ||
|
|
d701651a05 | ||
|
|
5205b2d079 | ||
|
|
e864d56081 | ||
|
|
c6a4c239a0 | ||
|
|
42fbdf9708 | ||
|
|
8d53990aea | ||
|
|
b9a0c656d3 | ||
|
|
8a8db67e82 | ||
|
|
0ac4571859 | ||
|
|
a072957793 | ||
|
|
fad5ad7243 | ||
|
|
b248ee7184 | ||
|
|
cf2d170d6f | ||
|
|
8d577ceb79 | ||
|
|
5748aa0540 | ||
|
|
4e850e5cb9 | ||
|
|
f89d4fce3f | ||
|
|
1ecf75ae9c | ||
|
|
888e5c5229 | ||
|
|
45eb542619 | ||
|
|
5a565f1154 | ||
|
|
78002563be | ||
|
|
be3071dc18 | ||
|
|
5c9d7eda17 | ||
|
|
9f3cfd9d3a | ||
|
|
0c6ae47a7b | ||
|
|
726a26850d | ||
|
|
5fbb05f083 | ||
|
|
afca99b53a | ||
|
|
a8d2c428bc | ||
|
|
5254f2b7f9 | ||
|
|
13a71cfd82 | ||
|
|
07d67bf881 | ||
|
|
27887bedef | ||
|
|
2b8f08c03c | ||
|
|
cb2194bc48 | ||
|
|
46872f81ac | ||
|
|
eb9984396b | ||
|
|
b7b79024e1 | ||
|
|
d17cc901ff | ||
|
|
1fe03197e3 | ||
|
|
a1eaa5baca | ||
|
|
b83b2205c0 | ||
|
|
989d20c474 | ||
|
|
2cf3ff93c5 | ||
|
|
67b44dce42 | ||
|
|
c182a67daa | ||
|
|
2494e4c6c5 | ||
|
|
efc230f81e | ||
|
|
e455fa764b | ||
|
|
c6273fa9c1 | ||
|
|
9f37ff773e | ||
|
|
9b21e15c63 | ||
|
|
fe41d9a751 | ||
|
|
5e91a0e7af | ||
|
|
e00186890c | ||
|
|
b2b017efc0 | ||
|
|
51b11b66ab | ||
|
|
2275c1b9cc | ||
|
|
bf98ff9a1d | ||
|
|
23c5a7bc18 | ||
|
|
4d05c660c8 | ||
|
|
83d4427c09 | ||
|
|
45285d3cf2 | ||
|
|
f46fdb9fb0 | ||
|
|
3557360297 | ||
|
|
600c225265 | ||
|
|
7fa814ca1b | ||
|
|
e4f44def47 | ||
|
|
08aa73f9c3 | ||
|
|
fcb564b054 | ||
|
|
ac4aea68eb | ||
|
|
ad6c37f62d | ||
|
|
bc3d5cb6b2 | ||
|
|
88c8cc82c8 | ||
|
|
69e0dc3343 | ||
|
|
dda9b88752 | ||
|
|
5b712e64d7 | ||
|
|
af1cc15d3d | ||
|
|
76e3c08405 | ||
|
|
ebae16f724 | ||
|
|
911adaa5d6 | ||
|
|
1766c19133 | ||
|
|
4a8bbaf82e | ||
|
|
fa7b9f3ad1 | ||
|
|
ecc9c74091 | ||
|
|
282c95be29 | ||
|
|
9325ce3638 | ||
|
|
a4da46ca21 | ||
|
|
44f30f70d5 | ||
|
|
2ef39cb2ed | ||
|
|
c8ecc92309 | ||
|
|
3ca6609ace | ||
|
|
670791fcf6 | ||
|
|
30dc33a859 | ||
|
|
07ed95793c | ||
|
|
9a9ec33f9f | ||
|
|
89aab6c74e | ||
|
|
c0e6c79c67 | ||
|
|
7badfda41b | ||
|
|
9445ce6d37 | ||
|
|
1aa8f77590 | ||
|
|
dab6a46d98 | ||
|
|
6b940e2f24 | ||
|
|
8c0ce05133 | ||
|
|
937494f81c | ||
|
|
7392d7ea0d | ||
|
|
9fcc231a7a | ||
|
|
149703a5df | ||
|
|
463455121e | ||
|
|
43ae9a6ba2 | ||
|
|
c24cc2165f | ||
|
|
f177a61d4f | ||
|
|
f13b9e8ea5 | ||
|
|
c04dd79778 | ||
|
|
00273a8c86 | ||
|
|
231ef804dc | ||
|
|
44dc22c792 | ||
|
|
830fc550bd | ||
|
|
6c7567a15c | ||
|
|
be9797cc77 | ||
|
|
a78d9c5906 | ||
|
|
8f4fe45d9e | ||
|
|
79157feed5 | ||
|
|
09888d5657 | ||
|
|
a0371167bc | ||
|
|
0dc2623ded | ||
|
|
7d81a83672 | ||
|
|
17150a53bc | ||
|
|
fbf1990045 | ||
|
|
c5881d7905 | ||
|
|
b83f7beb30 | ||
|
|
d2c5a850ef | ||
|
|
5b334db3c9 | ||
|
|
69aa7a7648 | ||
|
|
97e4313d93 | ||
|
|
3f7acd7e26 | ||
|
|
7a2b45f031 | ||
|
|
8ed64691c4 | ||
|
|
844971cdd9 | ||
|
|
cf376cdda7 | ||
|
|
1a6acce77f | ||
|
|
e9258e1a7f | ||
|
|
61b461661d | ||
|
|
a12a3852d2 | ||
|
|
0c94b33606 | ||
|
|
23f3fbfadf | ||
|
|
434e87b074 | ||
|
|
081fb7ce2e | ||
|
|
bd43ba8a6d | ||
|
|
bd2860e225 | ||
|
|
daeaf0a59d | ||
|
|
9cc7ea09d6 | ||
|
|
4b6f283bf3 | ||
|
|
e695bad1c6 | ||
|
|
fe31081907 | ||
|
|
248ccb3718 | ||
|
|
2260174ec2 | ||
|
|
cd3a867422 | ||
|
|
05a63dd110 | ||
|
|
cfc0c3d5a1 | ||
|
|
d6dbca25ce | ||
|
|
d21ad14e89 | ||
|
|
8d00726322 | ||
|
|
af11c304d3 | ||
|
|
223276f6af | ||
|
|
a6fdfe0dfa | ||
|
|
6154164b1c | ||
|
|
1cdb6c56a5 | ||
|
|
c63310a2db | ||
|
|
9f681a7459 | ||
|
|
2610032a38 | ||
|
|
d11e8112e0 | ||
|
|
df5e346cf1 | ||
|
|
9892d14a62 | ||
|
|
8c61f79885 | ||
|
|
ffa6638d3d | ||
|
|
f9ef12bd3a | ||
|
|
b79216f2b5 | ||
|
|
2597a63718 | ||
|
|
126a21a6b5 | ||
|
|
3abfbd5302 | ||
|
|
efdbce2d08 | ||
|
|
09eea16d60 | ||
|
|
71697a09b6 | ||
|
|
3583a2b962 | ||
|
|
2825d5ddd8 | ||
|
|
2e66174c4a | ||
|
|
e78069ad17 | ||
|
|
4c97993c5f | ||
|
|
a452173d9a | ||
|
|
60a38be923 | ||
|
|
6c3d286282 | ||
|
|
32c7bbd3f9 | ||
|
|
426dbc2e46 | ||
|
|
9882dea960 | ||
|
|
eb9a05e90c | ||
|
|
4e59e736ed | ||
|
|
9f91ebf289 | ||
|
|
b80de402bd | ||
|
|
e3c535276c | ||
|
|
add22b0bd0 | ||
|
|
48f855144e | ||
|
|
67291f0cbe | ||
|
|
45b302c698 | ||
|
|
f897edab5f | ||
|
|
dffb9f3dd8 | ||
|
|
573e1966ae | ||
|
|
d161aa98a0 | ||
|
|
f10d93c22e | ||
|
|
17a98fba68 | ||
|
|
dee28397cb | ||
|
|
c4055eb37c | ||
|
|
91049bebd9 | ||
|
|
9f6c35b9ec | ||
|
|
f0ed7c0b39 | ||
|
|
e64c4fc0f8 | ||
|
|
cd19cec4f7 | ||
|
|
070fc53685 | ||
|
|
b232c55843 | ||
|
|
55a14b3fbe | ||
|
|
60fde1711e | ||
|
|
31ca9d4e8b | ||
|
|
bd47a09d1e | ||
|
|
744322a398 | ||
|
|
70de0e3ebd | ||
|
|
935ef83c4f | ||
|
|
93370095e9 | ||
|
|
e8e9a5a5d3 | ||
|
|
a5fbf6991c | ||
|
|
a5f8017ab7 | ||
|
|
201fa4d564 | ||
|
|
5e23d4446b | ||
|
|
ef4e3fe28e | ||
|
|
6d6d86692a | ||
|
|
ada9724e54 | ||
|
|
6347b728e4 | ||
|
|
5079812745 | ||
|
|
c2ed9b2577 | ||
|
|
6ef1ba5b57 |
17
.eslintrc.json
Normal file
17
.eslintrc.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"ignorePatterns": ["./**/*.js", "./webpack/*.config.js", "./e2e/*.ts"],
|
||||
"rules": {
|
||||
"no-throw-literal": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"curly": "error",
|
||||
"class-methods-use-this": "warn"
|
||||
}
|
||||
}
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -2,7 +2,7 @@
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: 'Issue: '
|
||||
labels: ''
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Documentation
|
||||
url: https://frontmatter.codes/docs
|
||||
about: See our documentation.
|
||||
- name: Changelog
|
||||
url: https://frontmatter.codes/updates
|
||||
about: See our changelog.
|
||||
- name: Front Matter website
|
||||
url: https://frontmatter.codes
|
||||
about: Our website.
|
||||
- name: Support Front Matter
|
||||
url: https://github.com/sponsors/estruyf
|
||||
about: Support Front Matter development.
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -2,7 +2,7 @@
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: 'Enhancement: '
|
||||
labels: ''
|
||||
labels: 'enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
33
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
33
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# PR Details
|
||||
|
||||
<!--- Provide a general summary of your changes in the Title above -->
|
||||
|
||||
## Description
|
||||
|
||||
<!--- Describe your changes in detail -->
|
||||
|
||||
## Related Issue
|
||||
|
||||
<!--- This project only accepts pull requests related to open issues -->
|
||||
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
|
||||
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
|
||||
<!--- Please link to the issue here: -->
|
||||
|
||||
## Motivation and Context
|
||||
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
|
||||
## How Has This Been Tested
|
||||
|
||||
<!--- Please describe in detail how you tested your changes. -->
|
||||
<!--- Include details of your testing environment, and the tests you ran to -->
|
||||
<!--- see how your change affects other areas of the code, etc. -->
|
||||
|
||||
## Types of changes
|
||||
|
||||
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
||||
|
||||
- [ ] Docs change / refactoring / dependency upgrade
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -68,4 +68,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
90
.github/workflows/project-labelling.yml
vendored
Normal file
90
.github/workflows/project-labelling.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
name: Project labelling
|
||||
|
||||
on:
|
||||
project_card:
|
||||
types: [created, moved, deleted]
|
||||
|
||||
jobs:
|
||||
process-project:
|
||||
name: Add/remove the project label and set the matrix variable
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.setMatrixData.outputs.matrix }}
|
||||
statusLabel: ${{ steps.setStatusLabel.outputs.statusLabel }}
|
||||
steps:
|
||||
- name: Fetch project data
|
||||
run: |
|
||||
echo 'PROJECT_DATA<<EOF' >> $GITHUB_ENV
|
||||
curl --request GET --url '${{ github.event.project_card.project_url }}' --header 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' >> $GITHUB_ENV
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
|
||||
### Add or remove the project label ###
|
||||
- name: Add the project label
|
||||
uses: andymckay/labeler@master
|
||||
if: ${{ contains(github.event.action, 'created') || contains(github.event.action, 'moved') }}
|
||||
with:
|
||||
add-labels: "Project: ${{ fromJSON(env.PROJECT_DATA).name }}"
|
||||
|
||||
- name: Remove the project label
|
||||
uses: andymckay/labeler@master
|
||||
if: ${{ contains(github.event.action, 'deleted') }}
|
||||
with:
|
||||
remove-labels: "Project: ${{ fromJSON(env.PROJECT_DATA).name }}"
|
||||
|
||||
### Fetch project columns ###
|
||||
- name: Fetch all columns
|
||||
run: |
|
||||
echo 'ALL_COLUMNS_DATA<<EOF' >> $GITHUB_ENV
|
||||
curl --request GET --url '${{ fromJSON(env.PROJECT_DATA).columns_url }}' --header 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' | jq --compact-output '["Status: " + .[].name]' >> $GITHUB_ENV
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
|
||||
- name: Fetch column info
|
||||
run: |
|
||||
echo 'COLUMN_DATA<<EOF' >> $GITHUB_ENV
|
||||
curl --request GET --url '${{ github.event.project_card.column_url }}' --header 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' >> $GITHUB_ENV
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/github-script@v6
|
||||
id: setMatrixData
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const columnData = JSON.parse(process.env.COLUMN_DATA)
|
||||
const allColumnsData = JSON.parse(process.env.ALL_COLUMNS_DATA)
|
||||
|
||||
const matrix = allColumnsData.filter((label) => {
|
||||
return label !== `Status: ${columnData.name}`
|
||||
});
|
||||
|
||||
core.setOutput('matrix', matrix)
|
||||
|
||||
- name: Set the status label
|
||||
id: setStatusLabel
|
||||
run: |
|
||||
echo "statusLabel=${{ fromJSON(env.COLUMN_DATA).name }}" >> $GITHUB_OUTPUT
|
||||
|
||||
remove-labels:
|
||||
runs-on: ubuntu-latest
|
||||
needs: process-project
|
||||
if: ${{ contains(github.event.action, 'deleted') || contains(github.event.action, 'moved') }}
|
||||
strategy:
|
||||
matrix:
|
||||
label: ${{fromJson(needs.process-project.outputs.matrix)}}
|
||||
steps:
|
||||
- name: Remove the status label
|
||||
uses: andymckay/labeler@master
|
||||
with:
|
||||
remove-labels: ${{ matrix.label }}
|
||||
|
||||
add-labels:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- process-project
|
||||
- remove-labels
|
||||
if: ${{ contains(github.event.action, 'created') || contains(github.event.action, 'moved') }}
|
||||
steps:
|
||||
- name: Add the status label
|
||||
uses: andymckay/labeler@master
|
||||
with:
|
||||
add-labels: "Status: ${{ needs.process-project.outputs.statusLabel }}"
|
||||
|
||||
2
.github/workflows/release-beta.yml
vendored
2
.github/workflows/release-beta.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
run: node scripts/beta-release.js $GITHUB_RUN_ID
|
||||
|
||||
- name: Publish
|
||||
run: npx vsce publish -p ${{ secrets.VSCE_PAT }} --baseImagesUrl https://raw.githubusercontent.com/estruyf/vscode-front-matter/dev
|
||||
run: npx @vscode/vsce publish -p ${{ secrets.VSCE_PAT }} --baseImagesUrl https://raw.githubusercontent.com/estruyf/vscode-front-matter/dev
|
||||
|
||||
- name: Publish to open-vsx.org
|
||||
run: npx ovsx publish -p ${{ secrets.OPEN_VSX_PAT }}
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
run: node scripts/main-release.js
|
||||
|
||||
- name: Publish
|
||||
run: npx vsce publish -p ${{ secrets.VSCE_PAT }}
|
||||
run: npx @vscode/vsce publish -p ${{ secrets.VSCE_PAT }}
|
||||
|
||||
- name: Publish to open-vsx.org
|
||||
run: npx ovsx publish -p ${{ secrets.OPEN_VSX_PAT }}
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -4,4 +4,8 @@ node_modules
|
||||
*.vsix
|
||||
.DS_Store
|
||||
dist
|
||||
todo.md
|
||||
todo.md
|
||||
|
||||
e2e/storage
|
||||
e2e/extensions
|
||||
e2e/sample
|
||||
|
||||
7
.prettierrc
Normal file
7
.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none"
|
||||
}
|
||||
10
.vscode/extensions.json
vendored
10
.vscode/extensions.json
vendored
@@ -1,7 +1,5 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"ms-vscode.vscode-typescript-tslint-plugin"
|
||||
]
|
||||
}
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": ["eliostruyf.vscode-typescript-exportallmodules", "esbenp.prettier-vscode"]
|
||||
}
|
||||
|
||||
56
.vscode/launch.json
vendored
56
.vscode/launch.json
vendored
@@ -3,46 +3,24 @@
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Extension",
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
|
||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
||||
"preLaunchTask": "npm: build:ext"
|
||||
},
|
||||
{
|
||||
"name": "Attach Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: build:ext"
|
||||
},
|
||||
{
|
||||
"name": "Attach Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Extension Tests",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--extensionTestsPath=${workspaceFolder}/out/test"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/test/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: test-compile"
|
||||
}
|
||||
]
|
||||
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
|
||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
26
.vscode/recoil.code-snippets
vendored
26
.vscode/recoil.code-snippets
vendored
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"Recoil Atom": {
|
||||
"prefix": "sq-atom",
|
||||
"body": [
|
||||
"Recoil Atom": {
|
||||
"prefix": "sq-atom",
|
||||
"body": [
|
||||
"import { atom } from 'recoil';",
|
||||
"",
|
||||
"export const ${1:CollectionId}Atom = atom({",
|
||||
@@ -12,9 +12,9 @@
|
||||
"description": "Creates a new atom",
|
||||
"scope": "typescript"
|
||||
},
|
||||
"Recoil Selector (sync)": {
|
||||
"prefix": "sq-selector-sync",
|
||||
"body": [
|
||||
"Recoil Selector (sync)": {
|
||||
"prefix": "sq-selector-sync",
|
||||
"body": [
|
||||
"import { selector } from 'recoil';",
|
||||
"",
|
||||
"export const ${1:CollectionData}Selector = selector({",
|
||||
@@ -27,9 +27,9 @@
|
||||
"description": "Creates a new synchronous selector",
|
||||
"scope": "typescript"
|
||||
},
|
||||
"Recoil Selector (async)": {
|
||||
"prefix": "sq-selector-async",
|
||||
"body": [
|
||||
"Recoil Selector (async)": {
|
||||
"prefix": "sq-selector-async",
|
||||
"body": [
|
||||
"import { selector } from 'recoil';",
|
||||
"",
|
||||
"export const ${1:CollectionData}Selector = selector({",
|
||||
@@ -42,9 +42,9 @@
|
||||
"description": "Creates a new asynchronous selector",
|
||||
"scope": "typescript"
|
||||
},
|
||||
"Recoil selectorFamily": {
|
||||
"prefix": "sq-selector-fam",
|
||||
"body": [
|
||||
"Recoil selectorFamily": {
|
||||
"prefix": "sq-selector-fam",
|
||||
"body": [
|
||||
"import { selectorFamily } from 'recoil';",
|
||||
"",
|
||||
"export const ${1:CollectionData}Selector = selectorFamily({",
|
||||
@@ -63,4 +63,4 @@
|
||||
"description": "Include the translations",
|
||||
"scope": "typescriptreact"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
61
.vscode/settings.json
vendored
61
.vscode/settings.json
vendored
@@ -1,17 +1,52 @@
|
||||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.exclude": {
|
||||
"out": false // set this to true to hide the "out" folder with the compiled JS files
|
||||
"files.exclude": {
|
||||
"out": false // set this to true to hide the "out" folder with the compiled JS files
|
||||
},
|
||||
"search.exclude": {
|
||||
"out": true // set this to false to include "out" folder in search results
|
||||
},
|
||||
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||
"typescript.tsc.autoDetect": "off",
|
||||
"eliostruyf.writingstyleguide.terms.isDisabled": true,
|
||||
"eliostruyf.writingstyleguide.biasFree.isDisabled": true,
|
||||
"squarl.groups": [
|
||||
{
|
||||
"id": "dashboard",
|
||||
"name": "Dashboard"
|
||||
},
|
||||
"search.exclude": {
|
||||
"out": true // set this to false to include "out" folder in search results
|
||||
{
|
||||
"id": "panel",
|
||||
"name": "Panel"
|
||||
}
|
||||
],
|
||||
"squarl.bookmarks": [
|
||||
{
|
||||
"name": "App.tsx",
|
||||
"path": "src/dashboardWebView/components/App.tsx",
|
||||
"description": "Start of dashboard",
|
||||
"type": "file",
|
||||
"groupId": "dashboard"
|
||||
},
|
||||
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||
"typescript.tsc.autoDetect": "off",
|
||||
"eliostruyf.writingstyleguide.terms.isDisabled": true,
|
||||
"eliostruyf.writingstyleguide.biasFree.isDisabled": true,
|
||||
"exportall.config.folderListener": [
|
||||
"/src/pagesView/state/atom",
|
||||
"/src/pagesView/state/selectors"
|
||||
]
|
||||
}
|
||||
{
|
||||
"name": "ViewPanel.tsx",
|
||||
"path": "src/panelWebView/ViewPanel.tsx",
|
||||
"description": "Start of panel",
|
||||
"type": "file",
|
||||
"groupId": "panel"
|
||||
},
|
||||
{
|
||||
"name": "styles.css",
|
||||
"path": "src/panelWebView/styles.css",
|
||||
"description": "Panel styles",
|
||||
"type": "file",
|
||||
"groupId": "panel"
|
||||
},
|
||||
{
|
||||
"name": "settings.ts",
|
||||
"path": "src/constants/settings.ts",
|
||||
"description": "Settings names",
|
||||
"type": "file"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
48
.vscode/tasks.json
vendored
48
.vscode/tasks.json
vendored
@@ -1,28 +1,28 @@
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build:ext",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build:ext",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ src/**
|
||||
.gitignore
|
||||
vsc-extension-quickstart.md
|
||||
**/tsconfig.json
|
||||
**/tslint.json
|
||||
**/*.map
|
||||
**/*.ts
|
||||
webpack.config.js
|
||||
@@ -26,4 +25,6 @@ dist/*.html
|
||||
frontmatter.json
|
||||
.frontmatter
|
||||
webpack
|
||||
README.beta.md
|
||||
README.beta.md
|
||||
e2e
|
||||
storage
|
||||
|
||||
249
CHANGELOG.md
249
CHANGELOG.md
@@ -1,9 +1,248 @@
|
||||
# Change Log
|
||||
|
||||
## [8.3.0] - 2022-02-14 - [Release notes](https://beta.frontmatter.codes/updates/v8.3.0)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [#407](https://github.com/estruyf/vscode-front-matter/issues/407): External config support
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#425](https://github.com/estruyf/vscode-front-matter/issues/425): Added support for placeholders in the content paths and previews
|
||||
- [#473](https://github.com/estruyf/vscode-front-matter/issues/473): Allow setting the SEO title name with the `frontMatter.taxonomy.seoTitleField` setting
|
||||
- [#474](https://github.com/estruyf/vscode-front-matter/issues/474): Allow to define the file prefix on content types
|
||||
- [#484](https://github.com/estruyf/vscode-front-matter/issues/484): Support for overriding scripts per environment type
|
||||
- [#494](https://github.com/estruyf/vscode-front-matter/issues/494): Support for external image URLs in previews
|
||||
- [#497](https://github.com/estruyf/vscode-front-matter/issues/497): Support for movie media previews in the content dashboard
|
||||
- [#502](https://github.com/estruyf/vscode-front-matter/issues/502): Keyboard bindings added to open dashboard, insert media, and insert snippet
|
||||
- [#503](https://github.com/estruyf/vscode-front-matter/issues/503): Allow making changes to the preview URL in the webview
|
||||
- [#504](https://github.com/estruyf/vscode-front-matter/issues/504): Allow specifying the filename for your page bundles
|
||||
- [#505](https://github.com/estruyf/vscode-front-matter/issues/505): Experimental Visual Studio Code theming support
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
- [#496](https://github.com/estruyf/vscode-front-matter/issues/496): Make use of the `storageUri` and `globalStorageUri` for storing larger states
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#469](https://github.com/estruyf/vscode-front-matter/issues/469): Fix for using the root folder as content folder
|
||||
- [#470](https://github.com/estruyf/vscode-front-matter/issues/470): Fix `initialize project` dashboard description
|
||||
- [#480](https://github.com/estruyf/vscode-front-matter/issues/480): Updated _add missing fields_ label to _add missing fields to content-type_
|
||||
- [#482](https://github.com/estruyf/vscode-front-matter/issues/482): Update the description when you want to overwrite the default content type description
|
||||
- [#488](https://github.com/estruyf/vscode-front-matter/issues/488): Fix an issue where the `.frontmatter` folder gets created before initializing the project
|
||||
- [#493](https://github.com/estruyf/vscode-front-matter/issues/493): Fix an issue where a custom placeholder value is replaced by an `array` instead of a `string`
|
||||
|
||||
## [8.2.0] - 2022-12-08 - [Release notes](https://beta.frontmatter.codes/updates/v8.2.0)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [#362](https://github.com/estruyf/vscode-front-matter/issues/362): Support for conditional metadata
|
||||
- [#412](https://github.com/estruyf/vscode-front-matter/issues/412): Allow `frontmatter.json` to be split in multiple files
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#360](https://github.com/estruyf/vscode-front-matter/issues/360): Define which content types can be used on your page folders
|
||||
- [#406](https://github.com/estruyf/vscode-front-matter/issues/406): Added support for single data entries in the data dashboard
|
||||
- [#428](https://github.com/estruyf/vscode-front-matter/issues/428): Improved UX for inserting images to your content
|
||||
- [#430](https://github.com/estruyf/vscode-front-matter/issues/430): Support for HEXO its `post_asset_folder` setting (image location)
|
||||
- [#434](https://github.com/estruyf/vscode-front-matter/issues/434): Webview errors are logged in the extension output
|
||||
- [#440](https://github.com/estruyf/vscode-front-matter/issues/440): Type to search/filter in the snippets dashboard
|
||||
- [#447](https://github.com/estruyf/vscode-front-matter/issues/447): Allow to use placeholders on git commit messages
|
||||
- [#449](https://github.com/estruyf/vscode-front-matter/issues/449): Show `filename` if the `title` is not set
|
||||
- [#450](https://github.com/estruyf/vscode-front-matter/issues/450): Additional time placeholders added `{{hour12}}`, `{{hour24}}`, `{{ampm}}`, and `{{minute}}`
|
||||
- [#458](https://github.com/estruyf/vscode-front-matter/issues/458): Ability to configure the file prefix on folder level
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
- [#431](https://github.com/estruyf/vscode-front-matter/issues/431): Performance improvements for the content dashboard
|
||||
- [#448](https://github.com/estruyf/vscode-front-matter/issues/448): Retrieving files fails when content folder name and workspace folder name are the same
|
||||
- [#455](https://github.com/estruyf/vscode-front-matter/issues/455): Show a description for the SEO section when title nor description is set
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- Fix field error message color
|
||||
- [#433](https://github.com/estruyf/vscode-front-matter/issues/433): Fix issue with rendering an incorrect title value on the content dashboard
|
||||
- [#462](https://github.com/estruyf/vscode-front-matter/issues/462): Fix issue in script error notification
|
||||
- [#465](https://github.com/estruyf/vscode-front-matter/issues/465): Deleted content does not get added in git when syncing
|
||||
- [#471](https://github.com/estruyf/vscode-front-matter/issues/471): Fix typo on data dashboard
|
||||
|
||||
## [8.1.2] - 2022-10-06
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#435](https://github.com/estruyf/vscode-front-matter/issues/435): Fix required fields text color
|
||||
- [#436](https://github.com/estruyf/vscode-front-matter/issues/436): Fix inserting image/video snippets without defined fields
|
||||
|
||||
## [8.1.1] - 2022-09-23
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#422](https://github.com/estruyf/vscode-front-matter/issues/422): Fix in panel initialization logic
|
||||
|
||||
## [8.1.0] - 2022-09-22 - [Release notes](https://beta.frontmatter.codes/updates/v8.1.0)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [#369](https://github.com/estruyf/vscode-front-matter/issues/369): New `required` property to specify if a content-type field is required
|
||||
- [#376](https://github.com/estruyf/vscode-front-matter/issues/376): Ability to run scripts after content was created
|
||||
- [#377](https://github.com/estruyf/vscode-front-matter/issues/377): Git sync actions added on panel and content dashboard (pull and push your changes to remote)
|
||||
- [#379](https://github.com/estruyf/vscode-front-matter/issues/377): New `frontMatter.config.reload` command to reload the configuration file + reinitialize its listeners
|
||||
- [#391](https://github.com/estruyf/vscode-front-matter/issues/391): New `description` property to show a message underneath the input field
|
||||
- [#401](https://github.com/estruyf/vscode-front-matter/issues/401): Content dashboard now has pagination enabled and can be disabled via the `frontMatter.dashboard.content.pagination` setting
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#352](https://github.com/estruyf/vscode-front-matter/issues/352): Custom placeholders now support scripting
|
||||
- [#370](https://github.com/estruyf/vscode-front-matter/issues/370): Define the tags and categories as reserved keywords for custom taxonomy
|
||||
- [#372](https://github.com/estruyf/vscode-front-matter/issues/372): Rename Taxonomy tab to Taxonomies
|
||||
- [#374](https://github.com/estruyf/vscode-front-matter/issues/374): Hide the front matter section to use the panel instead
|
||||
- [#383](https://github.com/estruyf/vscode-front-matter/issues/383): Add the item menu to the content list view
|
||||
- [#385](https://github.com/estruyf/vscode-front-matter/issues/385): If no default value for the draft field is defined, the field value will be set to `true`
|
||||
- [#388](https://github.com/estruyf/vscode-front-matter/issues/388): New stop server action has been added to the panel
|
||||
- [#390](https://github.com/estruyf/vscode-front-matter/issues/390): Implement another JSON parser in order to be able to parse the `frontmatter.json` file better
|
||||
- [#394](https://github.com/estruyf/vscode-front-matter/issues/394): Ordering of snippet fields is based on their field definition
|
||||
- [#395](https://github.com/estruyf/vscode-front-matter/issues/395): Added support for custom snippet fields on media snippets
|
||||
- [#402](https://github.com/estruyf/vscode-front-matter/issues/402): Custom sorting of content now supports `number` fields
|
||||
- [#417](https://github.com/estruyf/vscode-front-matter/issues/417): New `hyperlink` wysiwyg option
|
||||
- [#418](https://github.com/estruyf/vscode-front-matter/issues/418): New `heading` and `divider` fields for your content-type definition
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
- Internal post message optimizations to the webviews
|
||||
- Preview tab now shows the title of the page/content if present
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#378](https://github.com/estruyf/vscode-front-matter/issues/378): Fix last modified update only to content in content folders
|
||||
- [#384](https://github.com/estruyf/vscode-front-matter/issues/384): Fix issue `title` field in sub-fields
|
||||
- [#393](https://github.com/estruyf/vscode-front-matter/issues/393): Fix Windows file path for retrieving the preview path
|
||||
- [#396](https://github.com/estruyf/vscode-front-matter/issues/396): Fix for `index` and `_index` page previews
|
||||
- [#398](https://github.com/estruyf/vscode-front-matter/issues/398): Fix Windows folder path parsing in data folder retrieval
|
||||
- [#400](https://github.com/estruyf/vscode-front-matter/issues/400): Fix for draft/published content grouping
|
||||
- [#403](https://github.com/estruyf/vscode-front-matter/issues/403): Fix for media files with spaces on importing in article content
|
||||
- [#404](https://github.com/estruyf/vscode-front-matter/issues/404): Fix for published sorting option in media dashboard
|
||||
- [#408](https://github.com/estruyf/vscode-front-matter/issues/408): Fix for missing `dashboard.taxonomy.view` view mode in the JSON schema
|
||||
|
||||
## [8.0.1] - 2022-07-13
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- Fix `PSD` media card icon image
|
||||
- Fix missing clipboard icon for the media card action
|
||||
- Fix in tags rendering on content cards
|
||||
|
||||
## [8.0.0] - 2022-07-11 - [Release notes](https://beta.frontmatter.codes/updates/v8.0.0)
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
- [#291](https://github.com/estruyf/vscode-front-matter/issues/291): New taxonomy dashboard for managing tags, categories, and custom taxonomies
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- Ignore the SEO `keywords` field for missing content type field
|
||||
- [#307](https://github.com/estruyf/vscode-front-matter/issues/307): New `list` field which allows to create a list of items
|
||||
- [#345](https://github.com/estruyf/vscode-front-matter/issues/345): Media dashboard UI improvements to visualize the content and public folders
|
||||
- [#349](https://github.com/estruyf/vscode-front-matter/issues/349): New `slug` field which allows you to manage the slug of your post from the Front Matter panel
|
||||
- [#350](https://github.com/estruyf/vscode-front-matter/issues/350): New `previewPath` property for the `frontMatter.content.pageFolders` setting. This allows you to specify a section prefix for all content created in that directory.
|
||||
- [#351](https://github.com/estruyf/vscode-front-matter/issues/351): New `template` property for content types which allows you to combine templates and content types for content creation
|
||||
- [#353](https://github.com/estruyf/vscode-front-matter/issues/353): Add the default content type on project initialization
|
||||
- [#366](https://github.com/estruyf/vscode-front-matter/issues/366): Better support for using block fields in another block field
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#348](https://github.com/estruyf/vscode-front-matter/issues/348): Fix media dashboard breadcrumb when multiple page folders are in use
|
||||
- [#356](https://github.com/estruyf/vscode-front-matter/issues/356): Re-introduce the `labelField` to the `frontMatter.taxonomy.fieldGroups` setting
|
||||
- [#358](https://github.com/estruyf/vscode-front-matter/issues/358): Fix for relative path of the public folder
|
||||
- [#364](https://github.com/estruyf/vscode-front-matter/issues/364): Honour file ending rules in data files
|
||||
- [#365](https://github.com/estruyf/vscode-front-matter/issues/365): Show spinner on the initial load of the content dashboard
|
||||
|
||||
## [7.3.4] - 2022-06-13
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#354](https://github.com/estruyf/vscode-front-matter/issues/354): Fix Windows file path parsing for inserting media files
|
||||
|
||||
## [7.3.3] - 2022-06-11
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- Card render when taxonomy is not an array value
|
||||
- Double pages on contents dashboard
|
||||
|
||||
## [7.3.2] - 2022-06-01
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#346](https://github.com/estruyf/vscode-front-matter/issues/346): Fix media dashboard refresh action
|
||||
|
||||
## [7.3.1] - 2022-05-26
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#343](https://github.com/estruyf/vscode-front-matter/issues/343): Fix in the schema for the `frontMatter.taxonomy.fieldGroups` setting
|
||||
|
||||
## [7.3.0] - 2022-05-25 - [Release notes](https://beta.frontmatter.codes/updates/v7.3.0)
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- JSON schema enhancements for working with data files
|
||||
- [#330](https://github.com/estruyf/vscode-front-matter/issues/330): Allow custom scripts to easily update front matter
|
||||
- [#331](https://github.com/estruyf/vscode-front-matter/issues/331): Added functionality to run other type of scripts
|
||||
- [#332](https://github.com/estruyf/vscode-front-matter/issues/332): New `dataFile` field which allows you to create data file references
|
||||
- [#333](https://github.com/estruyf/vscode-front-matter/issues/333): Automatically mark Jekyll posts in `_drafts` folder as draft
|
||||
- [#335](https://github.com/estruyf/vscode-front-matter/issues/335): Merge media snippets with content snippets to allow you to define multiple media snippets and use these in your content
|
||||
- [#336](https://github.com/estruyf/vscode-front-matter/issues/336): Support added for inverting the draft field so that SSGs/authors can use a published field instead
|
||||
- [#337](https://github.com/estruyf/vscode-front-matter/issues/337): Allow multiple front matter types to be used
|
||||
- [#338](https://github.com/estruyf/vscode-front-matter/issues/338): Ability to disable the templates functionality (default is disabled)
|
||||
- [#340](https://github.com/estruyf/vscode-front-matter/issues/340): Show an error message when there is a content folder registered that does not exist in the project
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#334](https://github.com/estruyf/vscode-front-matter/issues/334): Fix for locked content folders retrieval
|
||||
- [#339](https://github.com/estruyf/vscode-front-matter/issues/339): Fix for content folders without a title
|
||||
|
||||
## [7.2.0] - 2022-05-02 - [Release notes](https://beta.frontmatter.codes/updates/v7.2.0)
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- New tag design for the tags, category, and taxonomy fields
|
||||
- [#263](https://github.com/estruyf/vscode-front-matter/issues/263): WYSIWYG string field option
|
||||
- [#308](https://github.com/estruyf/vscode-front-matter/issues/308): New `File` field
|
||||
- [#314](https://github.com/estruyf/vscode-front-matter/issues/314): New preview actions to open the page in the browser and refresh the preview
|
||||
- [#322](https://github.com/estruyf/vscode-front-matter/issues/322): Show parent folder name when file is an index page (`index.md` / `_index.md`)
|
||||
- [#323](https://github.com/estruyf/vscode-front-matter/issues/323): Added 11ty, jekyll, and docusaurus to the framework selection list
|
||||
- [#325](https://github.com/estruyf/vscode-front-matter/issues/325): Better welcome experience that allows you to add content folders straight from the welcome view
|
||||
- [#326](https://github.com/estruyf/vscode-front-matter/issues/326): Content type actions to create, update, or set according to the current file
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
- [#316](https://github.com/estruyf/vscode-front-matter/issues/316): Suppress file parsing errors when closing the dashboard
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- Updated JSON schema link to supported version by VS Code (draft-07)
|
||||
- Hide the view mode action from the Front Matter panel if no custom modes are defined
|
||||
- Fix in decode base64 uploaded video files
|
||||
- Fix for a lightbox on other types of documents (pdf, etc.)
|
||||
- Fix for hiding the image preview on slide-over for none image documents
|
||||
- [#324](https://github.com/estruyf/vscode-front-matter/issues/324): Fix for the framework selection on the welcome screen
|
||||
|
||||
## [7.1.2] - 2022-04-11
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#315](https://github.com/estruyf/vscode-front-matter/issues/315): Fix draft tab navigation
|
||||
|
||||
## [7.1.1] - 2022-04-08
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- Fix in menu item with `stopPropagation` not defined.
|
||||
|
||||
## [7.1.0] - 2022-04-07 - [Release notes](https://beta.frontmatter.codes/updates/v7.1.0)
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
|
||||
- [#240](https://github.com/estruyf/vscode-front-matter/issues/240): Capability added to define display modes
|
||||
- [#246](https://github.com/estruyf/vscode-front-matter/issues/246): Support to add multiple tags/keywords/taxonomy via comma separated values
|
||||
- [#293](https://github.com/estruyf/vscode-front-matter/issues/293): Support added for setting preview images in block fields
|
||||
@@ -23,7 +262,7 @@
|
||||
- [#304](https://github.com/estruyf/vscode-front-matter/issues/304): Fix yaml stringify which caused additional fields to be added
|
||||
- [#305](https://github.com/estruyf/vscode-front-matter/issues/305): Fix for overflow issue in taxonomy picker
|
||||
- [#306](https://github.com/estruyf/vscode-front-matter/issues/306): Fix for default value of content type fields
|
||||
- [#311](https://github.com/estruyf/vscode-front-matter/issues/311): Fix for updating snippets
|
||||
- [#311](https://github.com/estruyf/vscode-front-matter/issues/311): Fix for updating snippets
|
||||
|
||||
## [7.0.0] - 2022-03-21 - [Release notes](https://beta.frontmatter.codes/updates/v7.0.0)
|
||||
|
||||
@@ -199,7 +438,7 @@ As from this version onwards, the extension will be published to [open-vsx.org](
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#173](https://github.com/estruyf/vscode-front-matter/issues/173): Allow to specify your own sorting for the content dashboard
|
||||
- [#174](https://github.com/estruyf/vscode-front-matter/issues/174): Added option to exclude sub-directories from page/markdown content retrieval
|
||||
- [#174](https://github.com/estruyf/vscode-front-matter/issues/174): Added option to exclude sub-directories from page/markdown content retrieval
|
||||
|
||||
## [5.4.0] - 2021-11-05
|
||||
|
||||
@@ -345,10 +584,10 @@ As from this version onwards, the extension will be published to [open-vsx.org](
|
||||
|
||||
- Fix typo in the `package.json` file for the preview command
|
||||
|
||||
## [2.5.0] - 2020-08-19
|
||||
## [2.5.0] - 2020-08-19
|
||||
|
||||
- Moved the center layout button to the other actions section
|
||||
- [#60](https://github.com/estruyf/vscode-front-matter/issues/60): Added the ability to open a site preview in VS Code
|
||||
- [#60](https://github.com/estruyf/vscode-front-matter/issues/60): Added the ability to open a site preview in VS Code
|
||||
|
||||
## [2.4.1] - 2020-08-16
|
||||
|
||||
|
||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
elio@struyfconsulting.be.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
59
CONTRIBUTING.md
Normal file
59
CONTRIBUTING.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Contributing to Front Matter
|
||||
|
||||
First of all, it is amazing you want to contribute to Front Matter 💚.
|
||||
|
||||
There are various ways in how you can contribute to the project, it can be as simple from opening a bug report to implementing fixes or features.
|
||||
|
||||
## How you can help us
|
||||
|
||||
- Testing out the extension and providing feedback
|
||||
- Reporting issues and bugs
|
||||
- Suggesting new features
|
||||
- Fixing an issue
|
||||
- Updating documentation
|
||||
- UI improvements
|
||||
- Tutorials
|
||||
- etc.
|
||||
|
||||
Eager to start contributing? Great 🤩, you can contribute to the following projects:
|
||||
|
||||
- [Extension](https://github.com/estruyf/vscode-front-matter)
|
||||
- [Documentation](https://github.com/FrontMatter/web-documentation-nextjs)
|
||||
- [Sample Projects](https://github.com/FrontMatter/project-samples)
|
||||
|
||||
## How to get started
|
||||
|
||||
- Start by forking this project;
|
||||
- Clone your fork to your local machine;
|
||||
- Run `pnpm i`;
|
||||
- Open the project in VS Code;
|
||||
- To start developing, run `pnpm dev:ext` and press `f5` to start the debugging session.
|
||||
|
||||
### Tips
|
||||
|
||||
- Ensure that the main branch on your fork is in sync with the original **vscode-front-matter** repository
|
||||
|
||||
```bash
|
||||
# assuming you are in the folder of your locally cloned fork....
|
||||
git checkout main
|
||||
|
||||
# assuming you have a remote named `upstream` pointing to the official **vscode-front-matter** repo
|
||||
git fetch upstream
|
||||
|
||||
# update your local main to be a mirror of what's in the main repo
|
||||
git pull --rebase upstream main
|
||||
```
|
||||
|
||||
- Create a feature branch in your fork. In case you get stuck, or have issues with merging your PR, this will allow you to have a clean main branch that you can use for contributing other changes.
|
||||
|
||||
```bash
|
||||
git checkout -b issue/<id>
|
||||
```
|
||||
|
||||
## Pull request
|
||||
|
||||
Once you are done with implementing the fix or feature. Please create a PR to our `dev` branch.
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under its MIT License.
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter" title="Check it out on the Visual Studio Marketplace">
|
||||
<img src="https://vsmarketplacebadge.apphb.com/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
<img src="https://vsmarketplacebadges.dev/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
</a>
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
<img src="https://vsmarketplacebadges.dev/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
<img src="https://vsmarketplacebadges.dev/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<a href="https://github.com/sponsors/estruyf" title="Become a sponsor" style="margin-left:10px">
|
||||
<img src="https://img.shields.io/github/sponsors/estruyf?color=%23CE2E7C&logo=github&style=flat" alt="Sponsor the project" style="display: inline-block" />
|
||||
@@ -54,6 +54,12 @@ A couple of our extension highlights that hopefully get you interested in giving
|
||||
|
||||
> If you see something missing in your article creation flow, please feel free to reach out.
|
||||
|
||||
**Version 8**
|
||||
|
||||
The taxonomy dashboard got introduced on which you can manage your tags, categories, and custom taxonomy.
|
||||
|
||||

|
||||
|
||||
**Version 7**
|
||||
|
||||
Snippets support for Front Matter has been added!
|
||||
@@ -166,27 +172,7 @@ You can open showcase issues for the following things:
|
||||
## 🖤 Backers & Sponsors 👇 🤘
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/jmatthewpryor" title="Andre Powell">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/850570" />
|
||||
</a>
|
||||
<a href="https://github.com/apowell656" title="Andre Powell">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/1969515" />
|
||||
</a>
|
||||
<a href="https://github.com/timschps" title="Tim Schaeps">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/13098307" />
|
||||
</a>
|
||||
<a href="https://github.com/grahampcharles" title="Graham Charles">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/3606679?v=4" />
|
||||
</a>
|
||||
<a href="https://github.com/zivbk1" title="Bryan Klein">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/6154767" />
|
||||
</a>
|
||||
<a href="https://github.com/flikteoh" title="FlikTeoh">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/1472065" />
|
||||
</a>
|
||||
<a href="https://github.com/themefisher" title="FlikTeoh">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/10640964" />
|
||||
</a>
|
||||
<img src="https://frontmatter.codes/api/img-sponsors" />
|
||||
</p>
|
||||
|
||||
<br />
|
||||
@@ -205,6 +191,6 @@ You can open showcase issues for the following things:
|
||||
|
||||
<p align="center">
|
||||
<a href="https://visitorbadge.io">
|
||||
<img src="https://estruyf-github.azurewebsites.net/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" height="25px" />
|
||||
</a>
|
||||
<img src="https://api.visitorbadge.io/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" height="25px" />
|
||||
</a>
|
||||
</p>
|
||||
56
README.md
56
README.md
@@ -8,12 +8,12 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter" title="Check it out on the Visual Studio Marketplace">
|
||||
<img src="https://vsmarketplacebadge.apphb.com/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
<img src="https://vsmarketplacebadges.dev/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
</a>
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
<img src="https://vsmarketplacebadges.dev/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<img src="https://vsmarketplacebadges.dev/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<a href="https://github.com/sponsors/estruyf" title="Become a sponsor" style="margin-left:10px">
|
||||
<img src="https://img.shields.io/github/sponsors/estruyf?color=%23CE2E7C&logo=github&style=flat" alt="Sponsor the project" style="display: inline-block" />
|
||||
@@ -52,6 +52,12 @@ A couple of our extension highlights that hopefully get you interested in giving
|
||||
|
||||
> If you see something missing in your article creation flow, please feel free to reach out.
|
||||
|
||||
**Version 8**
|
||||
|
||||
The taxonomy dashboard got introduced on which you can manage your tags, categories, and custom taxonomy.
|
||||
|
||||

|
||||
|
||||
**Version 7**
|
||||
|
||||
Snippets support for Front Matter has been added!
|
||||
@@ -109,7 +115,7 @@ You can get the extension via:
|
||||
If you have the courage to test out the beta features, we made available a beta version as well. You can install this via:
|
||||
|
||||
- Uninstall the main Front Matter version
|
||||
- Install the beta version
|
||||
- Install the beta version
|
||||
- VS Code marketplace: [VS Code Marketplace - Front Matter BETA](https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter-beta).
|
||||
- The extension CLI: `ext install eliostruyf.vscode-front-matter-beta`
|
||||
- Or by clicking on the following link: <a href="" title="open extension in VS Code" data-vscode="vscode:extension/eliostruyf.vscode-front-matter-beta">open extension in VS Code</a>
|
||||
@@ -157,41 +163,29 @@ You can open showcase issues for the following things:
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/estruyf/vscode-front-matter/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=estruyf/vscode-front-matter" />
|
||||
<img src="https://contrib.rocks/image?repo=estruyf/vscode-front-matter" alt="Front Matter contributors" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 🖤 Backers & Sponsors 👇 🤘
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/jmatthewpryor" title="Andre Powell">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/850570" />
|
||||
</a>
|
||||
<a href="https://github.com/apowell656" title="Andre Powell">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/1969515" />
|
||||
</a>
|
||||
<a href="https://github.com/timschps" title="Tim Schaeps">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/13098307" />
|
||||
</a>
|
||||
<a href="https://github.com/grahampcharles" title="Graham Charles">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/3606679?v=4" />
|
||||
</a>
|
||||
<a href="https://github.com/zivbk1" title="Bryan Klein">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/6154767" />
|
||||
</a>
|
||||
<a href="https://github.com/flikteoh" title="FlikTeoh">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/1472065" />
|
||||
</a>
|
||||
<a href="https://github.com/themefisher" title="FlikTeoh">
|
||||
<img height="64px" style="border-radius:50%" src="https://avatars.githubusercontent.com/u/10640964" />
|
||||
</a>
|
||||
<img src="https://frontmatter.codes/api/img-sponsors" alt="Front Matter sponsors" />
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<p align="center" title="Powered by Vercel">
|
||||
<a href="https://vercel.com/?utm_source=vscode-frontmatter&utm_campaign=oss">
|
||||
<img src="https://frontmatter.codes/assets/sponsors/powered-by-vercel.png" alt="Powered by Vercel" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<p align="center">
|
||||
<a href="https://vercel.com/?utm_source=vscode-frontmatter&utm_campaign=oss">
|
||||
<img src="https://frontmatter.codes/assets/sponsors/powered-by-vercel.png" />
|
||||
<a href="http://bejs.io/" title="Supported by the BEJS Community">
|
||||
<img src="https://frontmatter.codes/assets/sponsors/bejs-community.png" alt="Supported by the BEJS Community" height="50px"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -204,6 +198,6 @@ You can open showcase issues for the following things:
|
||||
|
||||
<p align="center">
|
||||
<a href="https://visitorbadge.io">
|
||||
<img src="https://estruyf-github.azurewebsites.net/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" height="25px" />
|
||||
<img src="https://api.visitorbadge.io/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" height="25px" alt="Front Matter visitors" />
|
||||
</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
}
|
||||
|
||||
.collapsible__body,
|
||||
.ext_settings {
|
||||
.ext_settings,
|
||||
.git_actions,
|
||||
.initialize_actions {
|
||||
padding: 1rem 1.25rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -163,36 +165,6 @@
|
||||
border: 1px solid rgba(0, 0, 0, .9);
|
||||
}
|
||||
|
||||
.article__tags__input input {
|
||||
border: 1px solid var(--vscode-inputValidation-infoBorder);
|
||||
}
|
||||
|
||||
.article__tags__input input:disabled {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.article__tags__input.freeform {
|
||||
position: relative;
|
||||
outline: 1px solid var(--vscode-inputValidation-infoBorder);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
.article__tags__input.freeform input {
|
||||
padding-right: 35px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.article__tags__input button {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 30px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.article__tags ul {
|
||||
color: var(--vscode-dropdown-foreground);
|
||||
background-color: var(--vscode-dropdown-background);
|
||||
@@ -221,60 +193,6 @@
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.article__tags__items__item {
|
||||
display: inline-flex;
|
||||
margin-bottom: .5rem;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.article__tags__items__item {
|
||||
display: inline-block;
|
||||
margin-bottom: .5rem;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.article__tags__items__item_add,
|
||||
.article__tags__items__item_delete {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.article__tags__items__item svg {
|
||||
display: inline;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.article__tags__items__item_delete span {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
.article__tags__items__pill_notexists {
|
||||
color: var(--vscode-inputValidation-errorForeground);
|
||||
background-color: var(--vscode-inputValidation-errorBackground);
|
||||
padding-left: .5rem;
|
||||
}
|
||||
|
||||
.article__tags__items__pill_notexists:hover {
|
||||
color: var(--vscode-inputValidation-errorForeground);
|
||||
background-color: var(--vscode-inputValidation-errorBackground);
|
||||
|
||||
filter: contrast(60%);
|
||||
}
|
||||
|
||||
.article__tags__items__item_add {
|
||||
color: var(--vscode-inputValidation-infoForeground);
|
||||
background-color: var(--vscode-inputValidation-infoBackground);
|
||||
border-right: 1px solid var(--vscode-inputValidation-infoBorder);
|
||||
}
|
||||
|
||||
.article__tags__items__item_add:hover {
|
||||
color: var(--vscode-inputValidation-infoForeground);
|
||||
background-color: var(--vscode-inputValidation-infoBackground);
|
||||
border-right: 1px solid var(--vscode-inputValidation-infoBorder);
|
||||
|
||||
filter: contrast(60%);
|
||||
}
|
||||
|
||||
.article__actions > * + *,
|
||||
.other_actions > * + *,
|
||||
.base__actions > * + *,
|
||||
@@ -355,6 +273,11 @@
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
}
|
||||
|
||||
.ext_link_block a:hover,
|
||||
.ext_link_block button:hover {
|
||||
background-color: var(--vscode-button-secondaryHoverBackground);
|
||||
}
|
||||
|
||||
.table__cell {
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -449,162 +372,6 @@ input:checked + .field__toggle__slider:before {
|
||||
}
|
||||
|
||||
/* Metadata */
|
||||
.metadata_field {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.vscode-dark .metadata_field__box {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px dashed rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.vscode-light .metadata_field__box {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border: 1px dashed rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.metadata_field__box {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px dashed rgba(255, 255, 255, 0.2);
|
||||
margin-bottom: .5rem;
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
|
||||
.metadata_field__label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.metadata_field__label.metadata_field__label_parent {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.metadata_field__label svg {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.metadata_field__error {
|
||||
color: var(--vscode-errorForeground);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.metadata_field__error button {
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
background-color: var(--vscode-button-secondaryBackground);
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.metadata_field__error button:hover {
|
||||
background-color: var(--vscode-button-secondaryHoverBackground);
|
||||
}
|
||||
|
||||
.metadata_field__input, .metadata_field__input:focus,
|
||||
.metadata_field__textarea, .metadata_field__textarea:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.metadata_field__limit {
|
||||
color: var(--vscode-inputValidation-warningBorder);
|
||||
margin-top: .25rem;
|
||||
}
|
||||
|
||||
.metadata_field__number {
|
||||
border: 1px solid var(--vscode-inputValidation-infoBorder) !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.metadata_field__choice__toggle {
|
||||
color: var(--vscode-input-placeholderForeground);
|
||||
border: 1px solid var(--vscode-inputValidation-infoBorder) !important;
|
||||
outline: none !important;
|
||||
width: 100%;
|
||||
padding: var(--input-padding-vertical) var(--input-padding-horizontal);
|
||||
background-color: var(--vscode-input-background);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.metadata_field__choice__toggle:hover,
|
||||
.metadata_field__choice__toggle:focus,
|
||||
.metadata_field__choice__toggle:active,
|
||||
.metadata_field__choice__toggle:disabled {
|
||||
background-color: var(--vscode-input-background);
|
||||
}
|
||||
|
||||
.metadata_field__choice__toggle span {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.metadata_field__choice__toggle svg.icon {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
margin-left: .25rem;
|
||||
|
||||
position: absolute;
|
||||
right: .25rem;
|
||||
}
|
||||
|
||||
.metadata_field__choice_list {
|
||||
width: 90%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
list-style: none;
|
||||
overflow: auto;
|
||||
max-height: 200px;
|
||||
|
||||
color: var(--vscode-dropdown-foreground);
|
||||
background-color: var(--vscode-dropdown-background);
|
||||
}
|
||||
|
||||
.metadata_field__choice_list.open {
|
||||
border: 1px solid rgba(0, 0, 0, .9);
|
||||
}
|
||||
|
||||
.metadata_field__choice_list li {
|
||||
padding: var(--input-padding-vertical) var(--input-padding-horizontal);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.metadata_field__choice_list li:active {
|
||||
color: var(--vscode-button-foreground);
|
||||
background-color: var(--vscode-button-background);
|
||||
}
|
||||
|
||||
.metadata_field__choice_list li[aria-selected="true"] {
|
||||
color: var(--vscode-button-foreground);
|
||||
background-color: var(--vscode-button-hoverBackground);
|
||||
}
|
||||
|
||||
.metadata_field__choice_list li[aria-disabled="true"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.metadata_field__choice_list__item {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.metadata_field__choice__button {
|
||||
margin-top: .5rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.metadata_field__choice__button_icon {
|
||||
height: 1.25rem;
|
||||
width: 1.25rem;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
.metadata_field__datetime {
|
||||
display: flex;
|
||||
@@ -627,71 +394,6 @@ input:checked + .field__toggle__slider:before {
|
||||
background-color: var(--vscode-button-secondaryHoverBackground);
|
||||
}
|
||||
|
||||
.metadata_field__multiple_images {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.metadata_field__preview_image img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-height: 16rem;
|
||||
}
|
||||
|
||||
.metadata_field__preview_image__button {
|
||||
background-color: transparent;
|
||||
border: 1px dashed var(--vscode-button-background);
|
||||
padding: 1.5rem;
|
||||
filter: brightness(85%);
|
||||
}
|
||||
|
||||
.metadata_field__preview_image__button:hover {
|
||||
background-color: rgba(255, 255, 255, .1);
|
||||
filter: brightness(100%);
|
||||
}
|
||||
|
||||
.metadata_field__preview_image__button svg {
|
||||
color: var(--vscode-foreground);
|
||||
display: block;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.metadata_field__preview_image__button span {
|
||||
color: var(--vscode-foreground);
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.vscode-light .metadata_field__preview_image__preview {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.vscode-dark .metadata_field__preview_image__preview {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.metadata_field__preview_image__preview {
|
||||
background-color: var(--vscode-button-secondaryBackground);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.metadata_field__preview_image__remove {
|
||||
background-color: var(--vscode-inputValidation-errorBackground);
|
||||
color: var(--vscode-inputValidation-errorForeground);
|
||||
}
|
||||
|
||||
.metadata_field__preview_image__remove:hover {
|
||||
background-color: var(--vscode-inputValidation-errorBackground);
|
||||
color: var(--vscode-inputValidation-errorForeground);
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
/* File list */
|
||||
.file_list vscode-label {
|
||||
border-bottom: 1px solid var(--vscode-foreground);
|
||||
@@ -773,8 +475,12 @@ input:checked + .field__toggle__slider:before {
|
||||
}
|
||||
|
||||
/* Timepicker */
|
||||
.react-datepicker button {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.react-datepicker button:hover {
|
||||
background-color: none !important;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.react-datepicker__triangle {
|
||||
|
||||
78
e2e/src/command.test.ts
Normal file
78
e2e/src/command.test.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { By, VSBrowser, EditorView, WebView, Workbench, Notification, StatusBar, NotificationType } from "vscode-extension-tester";
|
||||
import { expect } from "chai";
|
||||
import { sleep } from "./utils";
|
||||
import { join } from "path";
|
||||
|
||||
// https://github.com/microsoft/vscode-java-dependency/blob/4256fa6adcaff5ec24dbdbb8d9a516fad21431c5/test/ui/index.ts
|
||||
// https://github.com/microsoft/vscode-java-dependency/blob/4256fa6adcaff5ec24dbdbb8d9a516fad21431c5/test/ui/command.test.ts
|
||||
|
||||
describe("Initialization testing", function() {
|
||||
this.timeout(2 * 60 * 1000 /*ms*/);
|
||||
|
||||
let workbench: Workbench;
|
||||
let view: WebView;
|
||||
|
||||
before(async function() {
|
||||
await VSBrowser.instance.openResources(join(__dirname, '../sample'));
|
||||
await sleep(3000);
|
||||
workbench = new Workbench();
|
||||
|
||||
await workbench.executeCommand("frontMatter.dashboard");
|
||||
await sleep(3000);
|
||||
|
||||
await new EditorView().openEditor(`FrontMatter Dashboard`);
|
||||
|
||||
view = new WebView();
|
||||
await view.switchToFrame();
|
||||
});
|
||||
|
||||
it("1. Open welcome dashboard", async function() {
|
||||
const element = await view.findWebElement(By.css('h1'));
|
||||
|
||||
const title = await element.getText();
|
||||
|
||||
expect(title).has.string(`Front Matter`);
|
||||
});
|
||||
|
||||
it("2. Initialize project", async function() {
|
||||
const btn = await view.findWebElement(By.css('[data-test="welcome-init"] button'));
|
||||
expect(btn).to.exist;
|
||||
|
||||
await btn.click();
|
||||
|
||||
await sleep(1000);
|
||||
|
||||
await VSBrowser.instance.driver.wait(() => {
|
||||
return notificationExists(workbench, 'Front Matter:');
|
||||
}, 2000) as Notification;
|
||||
|
||||
const notifications = await workbench.getNotifications();
|
||||
|
||||
let notification!: Notification;
|
||||
for (const not of notifications) {
|
||||
console.log(not);
|
||||
|
||||
// const message = await not.get;
|
||||
// console.log(message);
|
||||
// if (message.includes('Front Matter:')) {
|
||||
// notification = not;
|
||||
// }
|
||||
}
|
||||
|
||||
expect(await notification.getMessage()).has.string(`Project initialized successfully.`);
|
||||
});
|
||||
|
||||
it("3. Check if project file is created", async function() {});
|
||||
});
|
||||
|
||||
|
||||
async function notificationExists(workbench: Workbench, text: string): Promise<Notification | undefined> {
|
||||
const notifications = await (await (new StatusBar()).openNotificationsCenter()).getNotifications(NotificationType.Info);
|
||||
|
||||
for (const notification of notifications) {
|
||||
const message = await notification.getMessage();
|
||||
if (message.indexOf(text) >= 0) {
|
||||
return notification;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
e2e/src/runTests.ts
Normal file
33
e2e/src/runTests.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as path from 'path'
|
||||
import * as semver from 'semver'
|
||||
import { ExTester, ReleaseQuality } from 'vscode-extension-tester'
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const vsCodeVersion: semver.SemVer = new semver.SemVer(`1.66.0`)
|
||||
const version = vsCodeVersion.version
|
||||
|
||||
const storageFolder = path.join(__dirname, '..', 'storage')
|
||||
const extFolder = path.join(__dirname, '..', 'extensions')
|
||||
|
||||
try {
|
||||
const testPath = path.join(__dirname, 'command.test.js')
|
||||
|
||||
const exTester = new ExTester(storageFolder, ReleaseQuality.Stable, extFolder)
|
||||
await exTester.downloadCode(version)
|
||||
await exTester.installVsix({ useYarn: false })
|
||||
// await exTester.installFromMarketplace("eliostruyf.vscode-front-matter");
|
||||
await exTester.downloadChromeDriver(version)
|
||||
// await exTester.setupRequirements({vscodeVersion: version});
|
||||
const result = await exTester.runTests(testPath, {
|
||||
vscodeVersion: version,
|
||||
resources: [storageFolder],
|
||||
})
|
||||
|
||||
process.exit(result)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
1
e2e/src/utils/index.ts
Normal file
1
e2e/src/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './sleep';
|
||||
3
e2e/src/utils/sleep.ts
Normal file
3
e2e/src/utils/sleep.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export async function sleep(time: number) {
|
||||
await new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
@@ -50,6 +50,28 @@
|
||||
],
|
||||
"openingTags": "{{",
|
||||
"closingTags": "}}"
|
||||
},
|
||||
"Issue link": {
|
||||
"description": "Link to a GitHub issue",
|
||||
"body": "- [#{{id}}](https://github.com/estruyf/vscode-front-matter/issues/{{id}}): {{title}}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"title": "Issue ID",
|
||||
"type": "string",
|
||||
"single": true,
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"title": "Title",
|
||||
"type": "string",
|
||||
"single": true,
|
||||
"default": ""
|
||||
}
|
||||
],
|
||||
"openingTags": "{{",
|
||||
"closingTags": "}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
17579
package-lock.json
generated
17579
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
670
package.json
670
package.json
File diff suppressed because it is too large
Load Diff
7603
pnpm-lock.yaml
generated
Normal file
7603
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,10 @@
|
||||
const tailwindcss = require('tailwindcss');
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('postcss-nested'),
|
||||
tailwindcss('./tailwind.config.js'),
|
||||
require('autoprefixer'),
|
||||
],
|
||||
plugins: {
|
||||
'postcss-import': {},
|
||||
'tailwindcss/nesting': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const core = require('@actions/core');
|
||||
|
||||
const packageJson = require('../package.json');
|
||||
const version = packageJson.version.split('.');
|
||||
@@ -7,14 +8,31 @@ const version = packageJson.version.split('.');
|
||||
packageJson.version = `${version[0]}.${version[1]}.${process.argv[process.argv.length-1].substr(0, 7)}`;
|
||||
packageJson.preview = true;
|
||||
packageJson.name = "vscode-front-matter-beta";
|
||||
packageJson.displayName = `${packageJson.displayName} BETA`;
|
||||
packageJson.displayName = `${packageJson.displayName} (BETA)`;
|
||||
packageJson.description = `BETA Version of Front Matter. ${packageJson.description}`;
|
||||
packageJson.icon = "assets/frontmatter-beta.png";
|
||||
packageJson.homepage = "https://beta.frontmatter.codes";
|
||||
|
||||
console.log(packageJson.version);
|
||||
|
||||
core.summary.addHeading(`Version info`).addRaw(`Version: ${packageJson.version}`).write();
|
||||
|
||||
const scripts = packageJson.scripts;
|
||||
for (const key in scripts) {
|
||||
if (key.startsWith(`prod:`)) {
|
||||
scripts[key] = scripts[key].replace("production", "development");
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(packageJson.scripts, null, 2));
|
||||
|
||||
fs.writeFileSync(path.join(path.resolve('.'), 'package.json'), JSON.stringify(packageJson, null, 2));
|
||||
|
||||
let readme = fs.readFileSync(path.join(__dirname, '../README.beta.md'), 'utf8');
|
||||
fs.writeFileSync(path.join(__dirname, '../README.md'), readme);
|
||||
fs.writeFileSync(path.join(__dirname, '../README.md'), readme);
|
||||
|
||||
// Update the .vscodeignore file
|
||||
const ignoreFilePath = path.join(path.resolve('.'), '.vscodeignore');
|
||||
let vscodeignore = fs.readFileSync(ignoreFilePath, 'utf8');
|
||||
vscodeignore = vscodeignore.replace(`**/*.map`, '');
|
||||
fs.writeFileSync(ignoreFilePath, vscodeignore);
|
||||
43
scripts/settings-export.js
Normal file
43
scripts/settings-export.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
for (const key of Object.keys(packageJson.contributes.configuration.properties)) {
|
||||
const type = packageJson.contributes.configuration.properties[key].type;
|
||||
|
||||
if (type.includes('object') || type.includes('array')) {
|
||||
console.log(`${key} - ${packageJson.contributes.configuration.properties[key].type}`);
|
||||
}
|
||||
}
|
||||
|
||||
// TO IGNORE
|
||||
// frontMatter.extends - array
|
||||
// frontMatter.dashboard.mediaSnippet - array
|
||||
|
||||
// TO PROCESS AS A WHOLE OBJECT
|
||||
// frontMatter.content.draftField - object
|
||||
// frontMatter.content.supportedFileTypes - array
|
||||
// frontMatter.global.notifications - array
|
||||
// frontMatter.global.disabledNotificaitons - array
|
||||
// frontMatter.media.supportedMimeTypes - array
|
||||
// frontMatter.taxonomy.commaSeparatedFields - array
|
||||
|
||||
// MERGE ARRAYS
|
||||
// frontMatter.taxonomy.categories - array
|
||||
// frontMatter.taxonomy.tags - array
|
||||
// frontMatter.taxonomy.noPropertyValueQuotes - array
|
||||
|
||||
// PROCESS ITEM BY ITEM
|
||||
// frontMatter.custom.scripts - array - id
|
||||
// frontMatter.taxonomy.contentTypes - array,null - name
|
||||
// frontMatter.data.files - array - id
|
||||
// frontMatter.data.folders - array - id
|
||||
// frontMatter.data.types - array - id
|
||||
// frontMatter.content.pageFolders - array - path
|
||||
// frontMatter.content.placeholders - array - id
|
||||
// frontMatter.content.sorting - array - id
|
||||
// frontMatter.global.modes - array - id
|
||||
// frontMatter.taxonomy.fieldGroups - array - id
|
||||
// frontMatter.taxonomy.customTaxonomy - array - id
|
||||
|
||||
|
||||
|
||||
// frontMatter.content.snippets - object
|
||||
@@ -1,9 +1,20 @@
|
||||
import { Folders } from './Folders';
|
||||
import { DEFAULT_CONTENT_TYPE } from './../constants/ContentType';
|
||||
import { isValidFile } from './../helpers/isValidFile';
|
||||
import { SETTING_AUTO_UPDATE_DATE, SETTING_MODIFIED_FIELD, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TEMPLATES_PREFIX, CONFIG_KEY, SETTING_DATE_FORMAT, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_CONTENT_PLACEHOLDERS, TelemetryEvent } from './../constants';
|
||||
import {
|
||||
SETTING_AUTO_UPDATE_DATE,
|
||||
SETTING_SLUG_UPDATE_FILE_NAME,
|
||||
SETTING_TEMPLATES_PREFIX,
|
||||
CONFIG_KEY,
|
||||
SETTING_DATE_FORMAT,
|
||||
SETTING_SLUG_PREFIX,
|
||||
SETTING_SLUG_SUFFIX,
|
||||
SETTING_CONTENT_PLACEHOLDERS,
|
||||
TelemetryEvent
|
||||
} from './../constants';
|
||||
import * as vscode from 'vscode';
|
||||
import { Field, TaxonomyType } from "../models";
|
||||
import { format } from "date-fns";
|
||||
import { CustomPlaceholder, Field, TaxonomyType } from '../models';
|
||||
import { format } from 'date-fns';
|
||||
import { ArticleHelper, Settings, SlugHelper } from '../helpers';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import { extname, basename, parse, dirname } from 'path';
|
||||
@@ -17,36 +28,40 @@ import { MediaListener } from '../listeners/panel';
|
||||
import { NavigationType } from '../dashboardWebView/models';
|
||||
import { processKnownPlaceholders } from '../helpers/PlaceholderHelper';
|
||||
|
||||
|
||||
export class Article {
|
||||
/**
|
||||
* Insert taxonomy
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
* Insert taxonomy
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
public static async insert(type: TaxonomyType) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const article = Article.getCurrent();
|
||||
const article = ArticleHelper.getCurrent();
|
||||
|
||||
if (!article) {
|
||||
return;
|
||||
}
|
||||
|
||||
let options: vscode.QuickPickItem[] = [];
|
||||
const matterProp: string = type === TaxonomyType.Tag ? "tags" : "categories";
|
||||
const matterProp: string = type === TaxonomyType.Tag ? 'tags' : 'categories';
|
||||
|
||||
// Add the selected options to the options array
|
||||
if (article.data[matterProp]) {
|
||||
const propData = article.data[matterProp];
|
||||
if (propData && propData.length > 0) {
|
||||
options = [...propData].filter(p => p).map(p => ({
|
||||
label: p,
|
||||
picked: true
|
||||
} as vscode.QuickPickItem));
|
||||
options = [...propData]
|
||||
.filter((p) => p)
|
||||
.map(
|
||||
(p) =>
|
||||
({
|
||||
label: p,
|
||||
picked: true
|
||||
} as vscode.QuickPickItem)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +69,7 @@ export class Article {
|
||||
const crntOptions = Settings.getTaxonomy(type);
|
||||
if (crntOptions && crntOptions.length > 0) {
|
||||
for (const crntOpt of crntOptions) {
|
||||
if (!options.find(o => o.label === crntOpt)) {
|
||||
if (!options.find((o) => o.label === crntOpt)) {
|
||||
options.push({
|
||||
label: crntOpt
|
||||
});
|
||||
@@ -63,17 +78,18 @@ export class Article {
|
||||
}
|
||||
|
||||
if (options.length === 0) {
|
||||
Notifications.info(`No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`);
|
||||
Notifications.info(`No ${type === TaxonomyType.Tag ? 'tags' : 'categories'} configured.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedOptions = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: `Select your ${type === TaxonomyType.Tag ? "tags" : "categories"} to insert`,
|
||||
canPickMany: true
|
||||
placeHolder: `Select your ${type === TaxonomyType.Tag ? 'tags' : 'categories'} to insert`,
|
||||
canPickMany: true,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (selectedOptions) {
|
||||
article.data[matterProp] = selectedOptions.map(o => o.label);
|
||||
article.data[matterProp] = selectedOptions.map((o) => o.label);
|
||||
}
|
||||
|
||||
ArticleHelper.update(editor, article);
|
||||
@@ -93,21 +109,23 @@ export class Article {
|
||||
return;
|
||||
}
|
||||
|
||||
article = this.updateDate(article, true);
|
||||
article = this.updateDate(article);
|
||||
|
||||
try {
|
||||
ArticleHelper.update(editor, article);
|
||||
} catch (e) {
|
||||
Notifications.error(`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`);
|
||||
Notifications.error(
|
||||
`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the date in the front matter
|
||||
* @param article
|
||||
* @param article
|
||||
*/
|
||||
public static updateDate(article: ParsedFrontMatter, forceCreate: boolean = false) {
|
||||
article.data = ArticleHelper.updateDates(article.data);
|
||||
public static updateDate(article: ParsedFrontMatter) {
|
||||
article.data = ArticleHelper.updateDates(article.data);
|
||||
return article;
|
||||
}
|
||||
|
||||
@@ -122,14 +140,11 @@ export class Article {
|
||||
|
||||
const updatedArticle = this.setLastModifiedDateInner(editor.document);
|
||||
|
||||
if (typeof updatedArticle === "undefined") {
|
||||
if (typeof updatedArticle === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
ArticleHelper.update(
|
||||
editor,
|
||||
updatedArticle as ParsedFrontMatter
|
||||
);
|
||||
ArticleHelper.update(editor, updatedArticle as ParsedFrontMatter);
|
||||
}
|
||||
|
||||
public static async setLastModifiedDateOnSave(
|
||||
@@ -137,7 +152,7 @@ export class Article {
|
||||
): Promise<vscode.TextEdit[]> {
|
||||
const updatedArticle = this.setLastModifiedDateInner(document);
|
||||
|
||||
if (typeof updatedArticle === "undefined") {
|
||||
if (typeof updatedArticle === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -161,21 +176,43 @@ export class Article {
|
||||
try {
|
||||
cloneArticle.data[dateField] = Article.formatDate(new Date());
|
||||
return cloneArticle;
|
||||
} catch (e: any) {
|
||||
Notifications.error(`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`);
|
||||
} catch (e: unknown) {
|
||||
Notifications.error(
|
||||
`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the new slug
|
||||
*/
|
||||
public static generateSlug(title: string) {
|
||||
if (!title) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prefix = Settings.get(SETTING_SLUG_PREFIX) as string;
|
||||
const suffix = Settings.get(SETTING_SLUG_SUFFIX) as string;
|
||||
|
||||
const slug = SlugHelper.createSlug(title);
|
||||
|
||||
if (slug) {
|
||||
return {
|
||||
slug,
|
||||
slugWithPrefixAndSuffix: `${prefix}${slug}${suffix}`
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the slug based on the article title
|
||||
*/
|
||||
public static async generateSlug() {
|
||||
Telemetry.send(TelemetryEvent.generateSlug);
|
||||
|
||||
const prefix = Settings.get(SETTING_SLUG_PREFIX) as string;
|
||||
const suffix = Settings.get(SETTING_SLUG_SUFFIX) as string;
|
||||
public static async updateSlug() {
|
||||
Telemetry.send(TelemetryEvent.generateSlug);
|
||||
|
||||
const updateFileName = Settings.get(SETTING_SLUG_UPDATE_FILE_NAME) as string;
|
||||
const filePrefix = Settings.get<string>(SETTING_TEMPLATES_PREFIX);
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
|
||||
if (!editor) {
|
||||
@@ -187,31 +224,41 @@ export class Article {
|
||||
return;
|
||||
}
|
||||
|
||||
let filePrefix = Settings.get<string>(SETTING_TEMPLATES_PREFIX);
|
||||
const contentType = ArticleHelper.getContentType(article.data);
|
||||
const titleField = "title";
|
||||
filePrefix = ArticleHelper.getFilePrefix(editor.document.uri.fsPath, contentType);
|
||||
|
||||
const titleField = 'title';
|
||||
const articleTitle: string = article.data[titleField];
|
||||
|
||||
const slug = SlugHelper.createSlug(articleTitle);
|
||||
if (slug) {
|
||||
let slugFieldValue = `${prefix}${slug}${suffix}`;
|
||||
article.data["slug"] = slugFieldValue;
|
||||
const slugInfo = Article.generateSlug(articleTitle);
|
||||
|
||||
if (slugInfo && slugInfo.slug && slugInfo.slugWithPrefixAndSuffix) {
|
||||
article.data['slug'] = slugInfo.slugWithPrefixAndSuffix;
|
||||
|
||||
if (contentType) {
|
||||
// Update the fields containing the slug placeholder
|
||||
let fieldsToUpdate: Field[] = contentType.fields.filter(f => f.default === "{{slug}}");
|
||||
const fieldsToUpdate: Field[] = contentType.fields.filter((f) => f.default === '{{slug}}');
|
||||
for (const field of fieldsToUpdate) {
|
||||
article.data[field.name] = slug;
|
||||
article.data[field.name] = slugInfo.slug;
|
||||
}
|
||||
|
||||
// Update the fields containing a custom placeholder that depends on slug
|
||||
const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS);
|
||||
const customPlaceholders = placeholders?.filter(p => p.value.includes("{{slug}}"));
|
||||
const placeholders = Settings.get<CustomPlaceholder[]>(SETTING_CONTENT_PLACEHOLDERS);
|
||||
const customPlaceholders = placeholders?.filter(
|
||||
(p) => p.value && p.value.includes('{{slug}}')
|
||||
);
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
for (const customPlaceholder of (customPlaceholders || [])) {
|
||||
const customPlaceholderFields = contentType.fields.filter(f => f.default === `{{${customPlaceholder.id}}}`);
|
||||
for (const customPlaceholder of customPlaceholders || []) {
|
||||
const customPlaceholderFields = contentType.fields.filter(
|
||||
(f) => f.default === `{{${customPlaceholder.id}}}`
|
||||
);
|
||||
for (const pField of customPlaceholderFields) {
|
||||
article.data[pField.name] = customPlaceholder.value;
|
||||
article.data[pField.name] = processKnownPlaceholders(article.data[pField.name], articleTitle, dateFormat);
|
||||
article.data[pField.name] = processKnownPlaceholders(
|
||||
article.data[pField.name],
|
||||
articleTitle,
|
||||
dateFormat
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,13 +272,13 @@ export class Article {
|
||||
if (editor) {
|
||||
const ext = extname(editor.document.fileName);
|
||||
const fileName = basename(editor.document.fileName);
|
||||
|
||||
let slugName = slug.startsWith("/") ? slug.substring(1) : slug;
|
||||
slugName = slugName.endsWith("/") ? slugName.substring(0, slugName.length - 1) : slugName;
|
||||
|
||||
let slugName = slugInfo.slug.startsWith('/') ? slugInfo.slug.substring(1) : slugInfo.slug;
|
||||
slugName = slugName.endsWith('/') ? slugName.substring(0, slugName.length - 1) : slugName;
|
||||
|
||||
let newFileName = `${slugName}${ext}`;
|
||||
if (filePrefix && typeof filePrefix === "string") {
|
||||
newFileName = `${format(new Date(), DateHelper.formatUpdate(filePrefix) as string)}-${newFileName}`;
|
||||
if (filePrefix && typeof filePrefix === 'string') {
|
||||
newFileName = `${filePrefix}-${newFileName}`;
|
||||
}
|
||||
|
||||
const newPath = editor.document.uri.fsPath.replace(fileName, newFileName);
|
||||
@@ -242,13 +289,13 @@ export class Article {
|
||||
await vscode.workspace.fs.rename(editor.document.uri, vscode.Uri.file(newPath), {
|
||||
overwrite: false
|
||||
});
|
||||
} catch (e: any) {
|
||||
Notifications.error(`Failed to rename file: ${e?.message || e}`);
|
||||
} catch (e: unknown) {
|
||||
Notifications.error(`Failed to rename file: ${(e as Error).message || e}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the slug from the front matter
|
||||
@@ -267,7 +314,7 @@ export class Article {
|
||||
|
||||
const parsedFile = parse(file);
|
||||
|
||||
if (parsedFile.name.toLowerCase() !== "index") {
|
||||
if (parsedFile.name.toLowerCase() !== 'index') {
|
||||
return parsedFile.name;
|
||||
}
|
||||
|
||||
@@ -288,8 +335,8 @@ export class Article {
|
||||
return;
|
||||
}
|
||||
|
||||
const newDraftStatus = !article.data["draft"];
|
||||
article.data["draft"] = newDraftStatus;
|
||||
const newDraftStatus = !article.data['draft'];
|
||||
article.data['draft'] = newDraftStatus;
|
||||
ArticleHelper.update(editor, article);
|
||||
}
|
||||
|
||||
@@ -302,6 +349,14 @@ export class Article {
|
||||
if (document && ArticleHelper.isSupportedFile(document)) {
|
||||
const autoUpdate = Settings.get(SETTING_AUTO_UPDATE_DATE);
|
||||
|
||||
// Is article located in one of the content folders
|
||||
const folders = Folders.get();
|
||||
const documentPath = parseWinPath(document.fileName);
|
||||
const folder = folders.find((f) => documentPath.startsWith(f.path));
|
||||
if (!folder) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (autoUpdate) {
|
||||
event.waitUntil(Article.setLastModifiedDateOnSave(document));
|
||||
}
|
||||
@@ -314,46 +369,51 @@ export class Article {
|
||||
public static formatDate(dateValue: Date): string {
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
|
||||
if (dateFormat && typeof dateFormat === "string") {
|
||||
if (dateFormat && typeof dateFormat === 'string') {
|
||||
return format(dateValue, DateHelper.formatUpdate(dateFormat) as string);
|
||||
} else {
|
||||
return typeof dateValue.toISOString === 'function' ? dateValue.toISOString() : dateValue?.toString();
|
||||
return typeof dateValue.toISOString === 'function'
|
||||
? dateValue.toISOString()
|
||||
: dateValue?.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an image from the media dashboard into the article
|
||||
*/
|
||||
public static async insertImage() {
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
public static async insertMedia() {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
const contentType = article && article.data ? ArticleHelper.getContentType(article.data) : DEFAULT_CONTENT_TYPE;
|
||||
const contentType =
|
||||
article && article.data ? ArticleHelper.getContentType(article.data) : DEFAULT_CONTENT_TYPE;
|
||||
|
||||
const position = editor.selection.active;
|
||||
const selectionText = editor.document.getText(editor.selection);
|
||||
|
||||
await vscode.commands.executeCommand(COMMAND_NAME.dashboard, {
|
||||
type: "media",
|
||||
type: 'media',
|
||||
data: {
|
||||
pageBundle: !!contentType.pageBundle,
|
||||
filePath: editor.document.uri.fsPath,
|
||||
fieldName: basename(editor.document.uri.fsPath),
|
||||
position
|
||||
position,
|
||||
selection: selectionText
|
||||
}
|
||||
} as DashboardData);
|
||||
|
||||
// Let the editor panel know you are selecting an image
|
||||
MediaListener.getMediaSelection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a snippet into the article
|
||||
*/
|
||||
public static async insertSnippet() {
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
@@ -366,41 +426,24 @@ export class Article {
|
||||
await vscode.commands.executeCommand(COMMAND_NAME.dashboard, {
|
||||
type: NavigationType.Snippets,
|
||||
data: {
|
||||
fileTitle: article?.data.title || "",
|
||||
fileTitle: article?.data.title || '',
|
||||
filePath: editor.document.uri.fsPath,
|
||||
fieldName: basename(editor.document.uri.fsPath),
|
||||
position,
|
||||
selection: selectionText
|
||||
}
|
||||
} as DashboardData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current article
|
||||
*/
|
||||
private static getCurrent(): ParsedFrontMatter | undefined {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
if (!article) {
|
||||
return;
|
||||
}
|
||||
|
||||
return article;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the article date and return it
|
||||
* @param article
|
||||
* @param dateFormat
|
||||
* @param field
|
||||
* @param forceCreate
|
||||
* @param article
|
||||
* @param dateFormat
|
||||
* @param field
|
||||
* @param forceCreate
|
||||
*/
|
||||
private static articleDate(article: ParsedFrontMatter, field: string, forceCreate: boolean) {
|
||||
if (typeof article.data[field] !== "undefined" || forceCreate) {
|
||||
if (typeof article.data[field] !== 'undefined' || forceCreate) {
|
||||
article.data[field] = Article.formatDate(new Date());
|
||||
}
|
||||
return article;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { commands, ExtensionContext } from 'vscode';
|
||||
import { CONTEXT } from '../constants';
|
||||
import { COMMAND_NAME, CONTEXT } from '../constants';
|
||||
import { Extension } from '../helpers';
|
||||
import { Credentials } from "../services/Credentials";
|
||||
import fetch from "node-fetch";
|
||||
import { Credentials } from '../services/Credentials';
|
||||
import fetch from 'node-fetch';
|
||||
import { ExplorerView } from '../explorerView/ExplorerView';
|
||||
import { Dashboard } from './Dashboard';
|
||||
import { SettingsListener } from '../listeners/panel';
|
||||
@@ -17,7 +17,7 @@ export class Backers {
|
||||
Backers.tryUsernameCheck();
|
||||
|
||||
context.subscriptions.push(
|
||||
commands.registerCommand('frontMatter.authenticate', async () => {
|
||||
commands.registerCommand(COMMAND_NAME.authenticate, async () => {
|
||||
Backers.tryUsernameCheck();
|
||||
})
|
||||
);
|
||||
@@ -26,16 +26,16 @@ export class Backers {
|
||||
public static async tryUsernameCheck() {
|
||||
try {
|
||||
const username = await Backers.getUsername();
|
||||
Backers.validate(username || "");
|
||||
Backers.validate(username || '');
|
||||
} catch (e) {
|
||||
Backers.validate("");
|
||||
Backers.validate('');
|
||||
}
|
||||
}
|
||||
|
||||
public static async getUsername() {
|
||||
const octokit = await Backers.creds?.getOctokit();
|
||||
const user = await octokit?.users.getAuthenticated();
|
||||
|
||||
|
||||
if (user?.data?.login) {
|
||||
return user?.data?.login;
|
||||
}
|
||||
@@ -52,7 +52,9 @@ export class Backers {
|
||||
|
||||
const isBeta = ext.isBetaVersion();
|
||||
|
||||
const response = await fetch(`https://${isBeta ? `beta.` : ``}frontmatter.codes/api/backers?backer=${username}`);
|
||||
const response = await fetch(
|
||||
`https://${isBeta ? `beta.` : ``}frontmatter.codes/api/backers?backer=${username}`
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const prevData = await ext.getState<boolean>(CONTEXT.backer, 'global');
|
||||
@@ -63,7 +65,7 @@ export class Backers {
|
||||
if (explorerView.visible) {
|
||||
SettingsListener.getSettings();
|
||||
}
|
||||
|
||||
|
||||
if (Dashboard.isOpen) {
|
||||
Dashboard.reload();
|
||||
}
|
||||
@@ -72,4 +74,4 @@ export class Backers {
|
||||
ext.setState(CONTEXT.backer, false, 'global');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
32
src/commands/Cache.ts
Normal file
32
src/commands/Cache.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { commands } from 'vscode';
|
||||
import { COMMAND_NAME, ExtensionState } from '../constants';
|
||||
import { Extension, Notifications } from '../helpers';
|
||||
|
||||
export class Cache {
|
||||
public static async registerCommands() {
|
||||
const ext = Extension.getInstance();
|
||||
const subscriptions = ext.subscriptions;
|
||||
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.clearCache, Cache.clear));
|
||||
}
|
||||
|
||||
public static async get<T>(key: string, type: 'workspace' | 'global'): Promise<T | undefined> {
|
||||
const ext = Extension.getInstance();
|
||||
const cache = await ext.getState<T>(key, type);
|
||||
return cache || undefined;
|
||||
}
|
||||
|
||||
public static async set(key: string, data: unknown, type: 'workspace' | 'global' = 'workspace') {
|
||||
await Extension.getInstance().setState(key, data, type);
|
||||
}
|
||||
|
||||
private static async clear() {
|
||||
const ext = Extension.getInstance();
|
||||
|
||||
await ext.setState(ExtensionState.Dashboard.Pages.Cache, undefined, 'workspace', true);
|
||||
await ext.setState(ExtensionState.Dashboard.Pages.Index, undefined, 'workspace', true);
|
||||
await ext.setState(ExtensionState.Settings.Extends, undefined, 'workspace', true);
|
||||
|
||||
Notifications.info('Cache cleared');
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,31 @@
|
||||
import { commands, QuickPickItem, window } from 'vscode';
|
||||
import { COMMAND_NAME } from '../constants';
|
||||
import { commands, QuickPickItem, window } from 'vscode';
|
||||
import { COMMAND_NAME, SETTING_TEMPLATES_ENABLED } from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
|
||||
export class Content {
|
||||
|
||||
public static async create() {
|
||||
const templatesEnabled = await Settings.get(SETTING_TEMPLATES_ENABLED);
|
||||
if (!templatesEnabled) {
|
||||
commands.executeCommand(COMMAND_NAME.createByContentType);
|
||||
return;
|
||||
}
|
||||
|
||||
const options: QuickPickItem[] = [{
|
||||
label: "Create content by content type",
|
||||
description: "Select if you want to create new content by the available content type(s)"
|
||||
}, {
|
||||
label: "Create content by template",
|
||||
description: "Select if you want to create new content by the available template(s)"
|
||||
} as QuickPickItem];
|
||||
const options: QuickPickItem[] = [
|
||||
{
|
||||
label: 'Create content by content type',
|
||||
description: 'Select if you want to create new content by the available content type(s)'
|
||||
},
|
||||
{
|
||||
label: 'Create content by template',
|
||||
description: 'Select if you want to create new content by the available template(s)'
|
||||
} as QuickPickItem
|
||||
];
|
||||
|
||||
const selectedOption = await window.showQuickPick(options, {
|
||||
title: 'Create content',
|
||||
placeHolder: `Select how you want to create your new content`,
|
||||
canPickMany: false
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (selectedOption) {
|
||||
@@ -28,4 +38,4 @@ export class Content {
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
import { SETTING_DASHBOARD_OPENONSTART, CONTEXT } from '../constants';
|
||||
import { join } from "path";
|
||||
import { commands, Uri, ViewColumn, Webview, WebviewPanel, window } from "vscode";
|
||||
import {
|
||||
SETTING_DASHBOARD_OPENONSTART,
|
||||
CONTEXT,
|
||||
ExtensionState,
|
||||
SETTING_EXPERIMENTAL
|
||||
} from '../constants';
|
||||
import { join } from 'path';
|
||||
import { commands, Uri, ViewColumn, Webview, WebviewPanel, window } from 'vscode';
|
||||
import { Logger, Settings as SettingsHelper } from '../helpers';
|
||||
import { DashboardCommand } from '../dashboardWebView/DashboardCommand';
|
||||
import { Extension } from '../helpers/Extension';
|
||||
import { WebviewHelper } from '@estruyf/vscode';
|
||||
import { DashboardData } from '../models/DashboardData';
|
||||
import { MediaLibrary } from '../helpers/MediaLibrary';
|
||||
import { DashboardListener, MediaListener, SettingsListener, TelemetryListener, DataListener, PagesListener, ExtensionListener, SnippetListener } from '../listeners/dashboard';
|
||||
import { MediaListener as PanelMediaListener } from '../listeners/panel'
|
||||
import { ModeListener } from '../listeners/general';
|
||||
import {
|
||||
DashboardListener,
|
||||
MediaListener,
|
||||
SettingsListener,
|
||||
TelemetryListener,
|
||||
DataListener,
|
||||
PagesListener,
|
||||
ExtensionListener,
|
||||
SnippetListener,
|
||||
TaxonomyListener,
|
||||
LogListener
|
||||
} from '../listeners/dashboard';
|
||||
import { MediaListener as PanelMediaListener } from '../listeners/panel';
|
||||
import { GitListener, ModeListener } from '../listeners/general';
|
||||
|
||||
export class Dashboard {
|
||||
private static webview: WebviewPanel | null = null;
|
||||
private static _viewData: DashboardData | undefined;
|
||||
private static isDisposed: boolean = true;
|
||||
private static isDisposed = true;
|
||||
|
||||
public static get viewData(): DashboardData | undefined {
|
||||
return Dashboard._viewData;
|
||||
@@ -34,15 +49,13 @@ export class Dashboard {
|
||||
* Open or reveal the dashboard
|
||||
*/
|
||||
public static async open(data?: DashboardData) {
|
||||
MediaLibrary.getInstance();
|
||||
|
||||
Dashboard._viewData = data;
|
||||
|
||||
if (Dashboard.isOpen) {
|
||||
Dashboard.reveal(!!data);
|
||||
} else {
|
||||
Dashboard.create();
|
||||
}
|
||||
Dashboard.reveal(!!data);
|
||||
} else {
|
||||
Dashboard.create();
|
||||
}
|
||||
|
||||
await commands.executeCommand('setContext', CONTEXT.isDashboardOpen, true);
|
||||
}
|
||||
@@ -57,12 +70,15 @@ export class Dashboard {
|
||||
/**
|
||||
* Reveal the dashboard if it is open
|
||||
*/
|
||||
public static reveal(hasData: boolean = false) {
|
||||
public static reveal(hasData = false) {
|
||||
if (Dashboard.webview) {
|
||||
Dashboard.webview.reveal();
|
||||
|
||||
if (hasData) {
|
||||
Dashboard.postWebviewMessage({ command: DashboardCommand.viewData, data: Dashboard.viewData });
|
||||
Dashboard.postWebviewMessage({
|
||||
command: DashboardCommand.viewData,
|
||||
data: Dashboard.viewData
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +90,11 @@ export class Dashboard {
|
||||
public static reload() {
|
||||
if (Dashboard.isOpen) {
|
||||
Dashboard.webview?.dispose();
|
||||
Extension.getInstance().setState(
|
||||
ExtensionState.Dashboard.Pages.Cache,
|
||||
undefined,
|
||||
'workspace'
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
Dashboard.open();
|
||||
@@ -84,7 +105,7 @@ export class Dashboard {
|
||||
public static resetViewData() {
|
||||
Dashboard._viewData = undefined;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the dashboard webview
|
||||
*/
|
||||
@@ -109,14 +130,20 @@ export class Dashboard {
|
||||
light: Uri.file(join(extensionUri.fsPath, 'assets/icons/frontmatter-short-light.svg'))
|
||||
};
|
||||
|
||||
Dashboard.webview.webview.html = Dashboard.getWebviewContent(Dashboard.webview.webview, extensionUri);
|
||||
Dashboard.webview.webview.html = Dashboard.getWebviewContent(
|
||||
Dashboard.webview.webview,
|
||||
extensionUri
|
||||
);
|
||||
|
||||
Dashboard.webview.onDidChangeViewState(async () => {
|
||||
if (!this.webview?.visible) {
|
||||
Dashboard._viewData = undefined;
|
||||
PanelMediaListener.getMediaSelection();
|
||||
|
||||
Dashboard.postWebviewMessage({ command: DashboardCommand.viewData, data: null });
|
||||
Dashboard.postWebviewMessage({
|
||||
command: DashboardCommand.viewData,
|
||||
data: null
|
||||
});
|
||||
}
|
||||
|
||||
await commands.executeCommand('setContext', CONTEXT.isDashboardOpen, this.webview?.visible);
|
||||
@@ -129,13 +156,13 @@ export class Dashboard {
|
||||
await commands.executeCommand('setContext', CONTEXT.isDashboardOpen, false);
|
||||
});
|
||||
|
||||
SettingsHelper.onConfigChange((global?: any) => {
|
||||
SettingsListener.getSettings();
|
||||
SettingsHelper.onConfigChange(() => {
|
||||
SettingsListener.getSettings(true);
|
||||
});
|
||||
|
||||
Dashboard.webview.webview.onDidReceiveMessage(async (msg) => {
|
||||
Logger.info(`Receiving message from webview: ${msg.command}`);
|
||||
|
||||
|
||||
DashboardListener.process(msg);
|
||||
ExtensionListener.process(msg);
|
||||
MediaListener.process(msg);
|
||||
@@ -145,6 +172,9 @@ export class Dashboard {
|
||||
TelemetryListener.process(msg);
|
||||
SnippetListener.process(msg);
|
||||
ModeListener.process(msg);
|
||||
GitListener.process(msg);
|
||||
TaxonomyListener.process(msg);
|
||||
LogListener.process(msg);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -158,9 +188,9 @@ export class Dashboard {
|
||||
|
||||
/**
|
||||
* Post data to the dashboard
|
||||
* @param msg
|
||||
* @param msg
|
||||
*/
|
||||
public static postWebviewMessage(msg: { command: DashboardCommand, data?: any }) {
|
||||
public static postWebviewMessage(msg: { command: DashboardCommand; data?: unknown }) {
|
||||
if (Dashboard.isDisposed) {
|
||||
return;
|
||||
}
|
||||
@@ -169,22 +199,24 @@ export class Dashboard {
|
||||
Dashboard.webview?.webview.postMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the webview HTML contents
|
||||
* @param webView
|
||||
* @param webView
|
||||
*/
|
||||
private static getWebviewContent(webView: Webview, extensionPath: Uri): string {
|
||||
const dashboardFile = "dashboardWebView.js";
|
||||
const dashboardFile = 'dashboardWebView.js';
|
||||
const localPort = `9000`;
|
||||
const localServerUrl = `localhost:${localPort}`;
|
||||
|
||||
let scriptUri = "";
|
||||
let scriptUri = '';
|
||||
const isProd = Extension.getInstance().isProductionMode;
|
||||
if (isProd) {
|
||||
scriptUri = webView.asWebviewUri(Uri.joinPath(extensionPath, 'dist', dashboardFile)).toString();
|
||||
scriptUri = webView
|
||||
.asWebviewUri(Uri.joinPath(extensionPath, 'dist', dashboardFile))
|
||||
.toString();
|
||||
} else {
|
||||
scriptUri = `http://${localServerUrl}/${dashboardFile}`;
|
||||
scriptUri = `http://${localServerUrl}/${dashboardFile}`;
|
||||
}
|
||||
|
||||
const nonce = WebviewHelper.getNonce();
|
||||
@@ -193,13 +225,27 @@ export class Dashboard {
|
||||
const version = ext.getVersion();
|
||||
const isBeta = ext.isBetaVersion();
|
||||
|
||||
// Get experimental setting
|
||||
const experimental = SettingsHelper.get(SETTING_EXPERIMENTAL);
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
`img-src ${`vscode-file://vscode-app`} ${webView.cspSource} https://api.visitorbadge.io 'self' 'unsafe-inline'`,
|
||||
`script-src ${isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`} 'unsafe-eval'`,
|
||||
`img-src ${`vscode-file://vscode-app`} ${
|
||||
webView.cspSource
|
||||
} https://api.visitorbadge.io 'self' 'unsafe-inline' https://*`,
|
||||
`media-src ${`vscode-file://vscode-app`} ${
|
||||
webView.cspSource
|
||||
} 'self' 'unsafe-inline' https://*`,
|
||||
`script-src ${
|
||||
isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`
|
||||
} 'unsafe-eval'`,
|
||||
`style-src ${webView.cspSource} 'self' 'unsafe-inline'`,
|
||||
`font-src ${webView.cspSource}`,
|
||||
`connect-src https://o1022172.ingest.sentry.io ${isProd ? `` : `ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort}`}`
|
||||
`connect-src https://o1022172.ingest.sentry.io ${
|
||||
isProd
|
||||
? ``
|
||||
: `ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort}`
|
||||
}`
|
||||
];
|
||||
|
||||
return `
|
||||
@@ -212,14 +258,18 @@ export class Dashboard {
|
||||
|
||||
<title>Front Matter Dashboard</title>
|
||||
</head>
|
||||
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden" class="bg-gray-100 text-vulcan-500 dark:bg-vulcan-500 dark:text-whisper-500">
|
||||
<div id="app" data-isProd="${isProd}" data-environment="${isBeta ? "BETA" : "main"}" data-version="${version.usedVersion}" style="width:100%;height:100%;margin:0;padding:0;" ${version.usedVersion ? "" : `data-showWelcome="true"`}></div>
|
||||
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden">
|
||||
<div id="app" class="bg-gray-100 text-vulcan-500 dark:bg-vulcan-500 dark:text-whisper-500" data-isProd="${isProd}" data-environment="${
|
||||
isBeta ? 'BETA' : 'main'
|
||||
}" data-version="${version.usedVersion}" style="width:100%;height:100%;margin:0;padding:0;" ${
|
||||
version.usedVersion ? '' : `data-showWelcome="true"`
|
||||
} ${experimental ? `data-experimental="${experimental}"` : ''} ></div>
|
||||
|
||||
<img style="display:none" src="https://api.visitorbadge.io/api/combined?user=estruyf&repo=frontmatter-usage&countColor=%23263759&slug=${`dashboard-${version.installedVersion}`}" alt="Daily usage" />
|
||||
|
||||
<script ${isProd ? `nonce="${nonce}"` : ""} src="${scriptUri}"></script>
|
||||
<script ${isProd ? `nonce="${nonce}"` : ''} src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Folders } from "./Folders";
|
||||
import { ViewColumn, workspace } from "vscode";
|
||||
import ContentProvider from "../providers/ContentProvider";
|
||||
import { join } from "path";
|
||||
import { ContentFolder } from "../models";
|
||||
|
||||
import { Folders } from './Folders';
|
||||
import { ViewColumn, workspace } from 'vscode';
|
||||
import ContentProvider from '../providers/ContentProvider';
|
||||
import { join } from 'path';
|
||||
import { ContentFolder } from '../models';
|
||||
import { Settings } from '../helpers/SettingsHelper';
|
||||
|
||||
export class Diagnostics {
|
||||
|
||||
public static async show() {
|
||||
const folders = Folders.get();
|
||||
const projectName = Folders.getProjectFolderName();
|
||||
@@ -25,11 +24,11 @@ ${projectName}
|
||||
|
||||
# Folders
|
||||
|
||||
${folders.map(f => `- ${f.title}: "${f.path}"`).join("\n")}
|
||||
${folders.map((f) => `- ${f.title}: "${f.path}"`).join('\n')}
|
||||
|
||||
# Workspace folder
|
||||
|
||||
${wsFolder ? wsFolder.fsPath : "No workspace folder"}
|
||||
${wsFolder ? wsFolder.fsPath : 'No workspace folder'}
|
||||
|
||||
# Total files
|
||||
|
||||
@@ -37,10 +36,16 @@ ${all}
|
||||
|
||||
# Folders to search files
|
||||
|
||||
${folderData.join("\n")}
|
||||
${folderData.join('\n')}
|
||||
|
||||
# Complete frontmatter.json config
|
||||
|
||||
\`\`\`json
|
||||
${JSON.stringify(Settings.globalConfig, null, 2)}
|
||||
\`\`\`
|
||||
`;
|
||||
|
||||
ContentProvider.show(logging, `${projectName} diagnostics`, "markdown", ViewColumn.One);
|
||||
ContentProvider.show(logging, `${projectName} diagnostics`, 'markdown', ViewColumn.One);
|
||||
}
|
||||
|
||||
private static async allProjectFiles() {
|
||||
@@ -50,14 +55,26 @@ ${folderData.join("\n")}
|
||||
|
||||
private static async processFolder(folder: ContentFolder, projectName: string) {
|
||||
let projectStart = folder.path.split(projectName).pop();
|
||||
projectStart = projectStart || "";
|
||||
projectStart = projectStart || '';
|
||||
projectStart = projectStart?.replace(/\\/g, '/');
|
||||
projectStart = projectStart?.startsWith('/') ? projectStart.substr(1) : projectStart;
|
||||
projectStart = projectStart?.startsWith('/') ? projectStart.substring(1) : projectStart;
|
||||
|
||||
const mdFiles = await workspace.findFiles(join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.md'));
|
||||
const mdxFiles = await workspace.findFiles(join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.mdx'));
|
||||
const markdownFiles = await workspace.findFiles(join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.markdown'));
|
||||
const mdFiles = await workspace.findFiles(
|
||||
join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.md')
|
||||
);
|
||||
const mdxFiles = await workspace.findFiles(
|
||||
join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.mdx')
|
||||
);
|
||||
const markdownFiles = await workspace.findFiles(
|
||||
join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.markdown')
|
||||
);
|
||||
|
||||
return `- Project start length: ${projectStart.length} | Search in: "${join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.*')}" | mdFiles: ${mdFiles.length} | mdxFiles: ${mdxFiles.length} | markdownFiles: ${markdownFiles.length}`;
|
||||
return `- Project start length: ${projectStart.length} | Search in: "${join(
|
||||
projectStart,
|
||||
folder.excludeSubdir ? '/' : '**/',
|
||||
'*.*'
|
||||
)}" | mdFiles: ${mdFiles.length} | mdxFiles: ${mdxFiles.length} | markdownFiles: ${
|
||||
markdownFiles.length
|
||||
}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +1,63 @@
|
||||
import { STATIC_FOLDER_PLACEHOLDER } from './../constants/StaticFolderPlaceholder';
|
||||
import { Questions } from './../helpers/Questions';
|
||||
import { SETTING_CONTENT_PAGE_FOLDERS, SETTING_CONTENT_STATIC_FOLDER, SETTING_CONTENT_SUPPORTED_FILETYPES, TelemetryEvent } from './../constants';
|
||||
import { commands, Uri, workspace, window } from "vscode";
|
||||
import { basename, dirname, join, sep } from "path";
|
||||
import { ContentFolder, FileInfo, FolderInfo } from "../models";
|
||||
import uniqBy = require("lodash.uniqby");
|
||||
import { Template } from "./Template";
|
||||
import { Notifications } from "../helpers/Notifications";
|
||||
import { Settings } from "../helpers";
|
||||
import { existsSync, mkdirSync } from 'fs';
|
||||
import {
|
||||
SETTING_CONTENT_PAGE_FOLDERS,
|
||||
SETTING_CONTENT_STATIC_FOLDER,
|
||||
SETTING_CONTENT_SUPPORTED_FILETYPES,
|
||||
SETTING_DATE_FORMAT,
|
||||
TelemetryEvent
|
||||
} from './../constants';
|
||||
import { commands, Uri, workspace, window } from 'vscode';
|
||||
import { basename, dirname, join, relative, sep } from 'path';
|
||||
import { ContentFolder, FileInfo, FolderInfo } from '../models';
|
||||
import uniqBy = require('lodash.uniqby');
|
||||
import { Template } from './Template';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import { Logger, processKnownPlaceholders, Settings } from '../helpers';
|
||||
import { existsSync } from 'fs';
|
||||
import { format } from 'date-fns';
|
||||
import { Dashboard } from './Dashboard';
|
||||
import { parseWinPath } from '../helpers/parseWinPath';
|
||||
import { MediaHelpers } from '../helpers/MediaHelpers';
|
||||
import { MediaListener, PagesListener } from '../listeners/dashboard';
|
||||
import { MediaListener, PagesListener, SettingsListener } from '../listeners/dashboard';
|
||||
import { DEFAULT_FILE_TYPES } from '../constants/DefaultFileTypes';
|
||||
import { Telemetry } from '../helpers/Telemetry';
|
||||
import { glob } from 'glob';
|
||||
import { mkdirAsync } from '../utils/mkdirAsync';
|
||||
import { existsAsync } from '../utils';
|
||||
|
||||
export const WORKSPACE_PLACEHOLDER = `[[workspace]]`;
|
||||
|
||||
export class Folders {
|
||||
|
||||
/**
|
||||
* Add a media folder
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
public static async addMediaFolder(data?: {selectedFolder?: string}) {
|
||||
let wsFolder = Folders.getWorkspaceFolder();
|
||||
const staticFolder = Settings.get<string>(SETTING_CONTENT_STATIC_FOLDER);
|
||||
public static async addMediaFolder(data?: { selectedFolder?: string }) {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const staticFolder = Folders.getStaticFolderRelativePath();
|
||||
|
||||
let startPath = "";
|
||||
let startPath = '';
|
||||
|
||||
if (data?.selectedFolder) {
|
||||
startPath = data.selectedFolder.replace(parseWinPath(wsFolder?.fsPath || ""), "");
|
||||
startPath = data.selectedFolder.replace(parseWinPath(wsFolder?.fsPath || ''), '');
|
||||
} else if (staticFolder) {
|
||||
startPath = `/${staticFolder}`;
|
||||
}
|
||||
|
||||
if (startPath && !startPath.endsWith("/")) {
|
||||
startPath += "/";
|
||||
if (startPath && !startPath.endsWith('/')) {
|
||||
startPath += '/';
|
||||
}
|
||||
|
||||
const folderName = await window.showInputBox({
|
||||
if (startPath.includes(STATIC_FOLDER_PLACEHOLDER.hexo.placeholder)) {
|
||||
startPath = startPath.replace(
|
||||
STATIC_FOLDER_PLACEHOLDER.hexo.placeholder,
|
||||
STATIC_FOLDER_PLACEHOLDER.hexo.postsFolder
|
||||
);
|
||||
}
|
||||
|
||||
const folderName = await window.showInputBox({
|
||||
title: `Add media folder`,
|
||||
prompt: `Which name would you like to give to your folder (use "/" to create multi-level folders)?`,
|
||||
value: startPath,
|
||||
ignoreFocusOut: true,
|
||||
@@ -51,23 +68,18 @@ export class Folders {
|
||||
Notifications.warning(`No folder name was specified.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const folders = folderName.split("/").filter(f => f);
|
||||
let parentFolders: string[] = [];
|
||||
|
||||
for (const folder of folders) {
|
||||
const folderPath = join(parseWinPath(wsFolder?.fsPath || ""), parentFolders.join("/"), folder);
|
||||
await Folders.createFolder(join(parseWinPath(wsFolder?.fsPath || ''), folderName));
|
||||
}
|
||||
|
||||
parentFolders.push(folder);
|
||||
|
||||
if (!existsSync(folderPath)) {
|
||||
mkdirSync(folderPath);
|
||||
}
|
||||
public static async createFolder(folderPath: string) {
|
||||
if (!(await existsAsync(folderPath))) {
|
||||
await mkdirAsync(folderPath, { recursive: true });
|
||||
}
|
||||
|
||||
if (Dashboard.isOpen) {
|
||||
MediaHelpers.resetMedia();
|
||||
MediaListener.sendMediaFiles(0, folderName);
|
||||
MediaListener.sendMediaFiles(0, folderPath);
|
||||
}
|
||||
|
||||
Telemetry.send(TelemetryEvent.addMediaFolder);
|
||||
@@ -75,7 +87,7 @@ export class Folders {
|
||||
|
||||
/**
|
||||
* Create content in a registered folder
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
public static async create() {
|
||||
const selectedFolder = await Questions.SelectContentFolder();
|
||||
@@ -84,7 +96,7 @@ export class Folders {
|
||||
}
|
||||
|
||||
const folders = Folders.get();
|
||||
const location = folders.find(f => f.title === selectedFolder);
|
||||
const location = folders.find((f) => f.title === selectedFolder);
|
||||
if (location) {
|
||||
const folderPath = Folders.getFolderPath(Uri.file(location.path));
|
||||
if (folderPath) {
|
||||
@@ -95,68 +107,98 @@ export class Folders {
|
||||
|
||||
/**
|
||||
* Register the new folder path
|
||||
* @param folder
|
||||
* @param folderInfo
|
||||
*/
|
||||
public static async register(folder: Uri) {
|
||||
public static async register(folderInfo: { title: string; path: Uri } | Uri) {
|
||||
let folderName = folderInfo instanceof Uri ? undefined : folderInfo.title;
|
||||
const folder = folderInfo instanceof Uri ? folderInfo : folderInfo.path;
|
||||
|
||||
if (folder && folder.fsPath) {
|
||||
const wslPath = folder.fsPath.replace(/\//g, '\\');
|
||||
|
||||
let folders = Folders.get();
|
||||
|
||||
const exists = folders.find(f => f.path.includes(folder.fsPath) || f.path.includes(wslPath));
|
||||
const exists = folders.find(
|
||||
(f) => f.path.includes(folder.fsPath) || f.path.includes(wslPath)
|
||||
);
|
||||
|
||||
if (exists) {
|
||||
Notifications.warning(`Folder is already registered`);
|
||||
return;
|
||||
}
|
||||
|
||||
const folderName = await window.showInputBox({
|
||||
prompt: `Which name would you like to specify for this folder?`,
|
||||
placeHolder: `Folder name`,
|
||||
value: basename(folder.fsPath)
|
||||
});
|
||||
if (!folderName) {
|
||||
folderName = await window.showInputBox({
|
||||
title: `Register folder`,
|
||||
prompt: `Which name would you like to specify for this folder?`,
|
||||
placeHolder: `Folder name`,
|
||||
value: basename(folder.fsPath),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
}
|
||||
|
||||
folders.push({
|
||||
title: folderName,
|
||||
path: folder.fsPath
|
||||
} as ContentFolder);
|
||||
|
||||
folders = uniqBy(folders, f => f.path);
|
||||
folders = uniqBy(folders, (f) => f.path);
|
||||
await Folders.update(folders);
|
||||
|
||||
Notifications.info(`Folder registered`);
|
||||
|
||||
Telemetry.send(TelemetryEvent.registerFolder);
|
||||
Telemetry.send(TelemetryEvent.registerFolder);
|
||||
|
||||
SettingsListener.getSettings(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a folder path
|
||||
* @param folder
|
||||
* @param folder
|
||||
*/
|
||||
public static async unregister(folder: Uri) {
|
||||
if (folder && folder.path) {
|
||||
let folders = Folders.get();
|
||||
folders = folders.filter(f => f.path !== folder.fsPath);
|
||||
folders = folders.filter((f) => f.path !== folder.fsPath);
|
||||
await Folders.update(folders);
|
||||
|
||||
Telemetry.send(TelemetryEvent.unregisterFolder);
|
||||
Telemetry.send(TelemetryEvent.unregisterFolder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the static folder its relative path
|
||||
* @returns
|
||||
*/
|
||||
public static getStaticFolderRelativePath(): string | undefined {
|
||||
let staticFolder = Settings.get<string>(SETTING_CONTENT_STATIC_FOLDER);
|
||||
|
||||
if (staticFolder && staticFolder.includes(WORKSPACE_PLACEHOLDER)) {
|
||||
staticFolder = Folders.getAbsFilePath(staticFolder);
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
if (wsFolder) {
|
||||
const relativePath = relative(parseWinPath(wsFolder.fsPath), parseWinPath(staticFolder));
|
||||
return relativePath;
|
||||
}
|
||||
}
|
||||
|
||||
return staticFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the folder path
|
||||
* @param folder
|
||||
* @returns
|
||||
* @param folder
|
||||
* @returns
|
||||
*/
|
||||
public static getFolderPath(folder: Uri) {
|
||||
let folderPath = "";
|
||||
let folderPath = '';
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
if (folder && folder.fsPath) {
|
||||
folderPath = folder.fsPath;
|
||||
} else if (wsFolder) {
|
||||
folderPath = wsFolder.fsPath;
|
||||
}
|
||||
if (folder && folder.fsPath) {
|
||||
folderPath = folder.fsPath;
|
||||
} else if (wsFolder) {
|
||||
folderPath = wsFolder.fsPath;
|
||||
}
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
@@ -165,12 +207,12 @@ export class Folders {
|
||||
*/
|
||||
public static getWorkspaceFolder(): Uri | undefined {
|
||||
const folders = workspace.workspaceFolders;
|
||||
|
||||
|
||||
if (folders && folders.length === 1) {
|
||||
return folders[0].uri;
|
||||
} else if (folders && folders.length > 1) {
|
||||
let projectFolder = undefined;
|
||||
|
||||
let projectFolder = undefined;
|
||||
|
||||
for (const folder of folders) {
|
||||
if (!projectFolder && existsSync(join(folder.uri.fsPath, Settings.globalFile))) {
|
||||
projectFolder = folder.uri;
|
||||
@@ -178,20 +220,22 @@ export class Folders {
|
||||
}
|
||||
|
||||
if (!projectFolder) {
|
||||
window.showWorkspaceFolderPick({
|
||||
placeHolder: `Please select the main workspace folder for Front Matter to use.`
|
||||
}).then(selectedFolder => {
|
||||
if (selectedFolder) {
|
||||
Settings.createGlobalFile(selectedFolder.uri);
|
||||
// Full reload to make sure the whole extension is reloaded correctly
|
||||
commands.executeCommand(`workbench.action.reloadWindow`);
|
||||
}
|
||||
});
|
||||
window
|
||||
.showWorkspaceFolderPick({
|
||||
placeHolder: `Please select the main workspace folder for Front Matter to use.`
|
||||
})
|
||||
.then(async (selectedFolder) => {
|
||||
if (selectedFolder) {
|
||||
await Settings.createGlobalFile(selectedFolder.uri);
|
||||
// Full reload to make sure the whole extension is reloaded correctly
|
||||
commands.executeCommand(`workbench.action.reloadWindow`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return projectFolder;
|
||||
}
|
||||
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -203,7 +247,7 @@ export class Folders {
|
||||
if (wsFolder) {
|
||||
return basename(wsFolder.fsPath);
|
||||
}
|
||||
return "";
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,26 +256,36 @@ export class Folders {
|
||||
public static async getInfo(limit?: number): Promise<FolderInfo[] | null> {
|
||||
const supportedFiles = Settings.get<string[]>(SETTING_CONTENT_SUPPORTED_FILETYPES);
|
||||
const folders = Folders.get();
|
||||
const wsFolder = parseWinPath(Folders.getWorkspaceFolder()?.fsPath || '');
|
||||
|
||||
if (folders && folders.length > 0) {
|
||||
let folderInfo: FolderInfo[] = [];
|
||||
|
||||
const folderInfo: FolderInfo[] = [];
|
||||
|
||||
for (const folder of folders) {
|
||||
try {
|
||||
const projectName = Folders.getProjectFolderName();
|
||||
let projectStart = folder.path.split(projectName).pop();
|
||||
|
||||
if (projectStart) {
|
||||
let projectStart = parseWinPath(folder.path).replace(wsFolder, '');
|
||||
|
||||
if (typeof projectStart === 'string') {
|
||||
projectStart = projectStart.replace(/\\/g, '/');
|
||||
projectStart = projectStart.startsWith('/') ? projectStart.substr(1) : projectStart;
|
||||
projectStart = projectStart.startsWith('/') ? projectStart.substring(1) : projectStart;
|
||||
|
||||
let files: Uri[] = [];
|
||||
|
||||
for (const fileType of (supportedFiles || DEFAULT_FILE_TYPES)) {
|
||||
const filePath = join(projectStart, folder.excludeSubdir ? '/' : '**', `*${fileType.startsWith('.') ? '' : '.'}${fileType}`);
|
||||
|
||||
for (const fileType of supportedFiles || DEFAULT_FILE_TYPES) {
|
||||
let filePath = join(
|
||||
projectStart,
|
||||
folder.excludeSubdir ? '/' : '**',
|
||||
`*${fileType.startsWith('.') ? '' : '.'}${fileType}`
|
||||
);
|
||||
|
||||
if (projectStart === '' && folder.excludeSubdir) {
|
||||
filePath = `*${fileType.startsWith('.') ? '' : '.'}${fileType}`;
|
||||
}
|
||||
|
||||
const foundFiles = await workspace.findFiles(filePath, '**/node_modules/**');
|
||||
files = [...files, ...foundFiles];
|
||||
}
|
||||
|
||||
|
||||
if (files) {
|
||||
let fileStats: FileInfo[] = [];
|
||||
|
||||
@@ -239,7 +293,7 @@ export class Folders {
|
||||
try {
|
||||
const fileName = basename(file.fsPath);
|
||||
const folderName = dirname(file.fsPath).split(sep).pop();
|
||||
|
||||
|
||||
const stats = await workspace.fs.stat(file);
|
||||
|
||||
fileStats.push({
|
||||
@@ -254,7 +308,7 @@ export class Folders {
|
||||
}
|
||||
|
||||
fileStats = fileStats.sort((a, b) => b.mtime - a.mtime);
|
||||
|
||||
|
||||
if (limit) {
|
||||
fileStats = fileStats.slice(0, limit);
|
||||
}
|
||||
@@ -279,28 +333,59 @@ export class Folders {
|
||||
|
||||
/**
|
||||
* Get the folder settings
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
public static get(): ContentFolder[] {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const folders: ContentFolder[] = Settings.get(SETTING_CONTENT_PAGE_FOLDERS) as ContentFolder[];
|
||||
|
||||
return folders.map(folder => ({
|
||||
...folder,
|
||||
path: Folders.absWsFolder(folder, wsFolder)
|
||||
}));
|
||||
|
||||
const contentFolders = folders.map((folder) => {
|
||||
if (!folder.title) {
|
||||
folder.title = basename(folder.path);
|
||||
}
|
||||
|
||||
let folderPath: string | undefined = Folders.absWsFolder(folder, wsFolder);
|
||||
if (folderPath.includes(`{{`) && folderPath.includes(`}}`)) {
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
folderPath = processKnownPlaceholders(folderPath, undefined, dateFormat);
|
||||
} else {
|
||||
if (folderPath && !existsSync(folderPath)) {
|
||||
Notifications.errorShowOnce(
|
||||
`Folder "${folder.title} (${folder.path})" does not exist. Please remove it from the settings.`,
|
||||
'Remove folder',
|
||||
'Create folder'
|
||||
).then((answer) => {
|
||||
if (answer === 'Remove folder') {
|
||||
const folders = Folders.get();
|
||||
Folders.update(folders.filter((f) => f.path !== folder.path));
|
||||
} else if (answer === 'Create folder') {
|
||||
mkdirAsync(folderPath as string, { recursive: true });
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...folder,
|
||||
originalPath: folder.path,
|
||||
path: folderPath
|
||||
};
|
||||
});
|
||||
|
||||
return contentFolders.filter((folder) => folder !== null) as ContentFolder[];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the folder settings
|
||||
* @param folders
|
||||
* @param folders
|
||||
*/
|
||||
public static async update(folders: ContentFolder[]) {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
|
||||
let folderDetails = folders.map(folder => ({
|
||||
const folderDetails = folders.map((folder) => ({
|
||||
...folder,
|
||||
path: Folders.relWsFolder(folder, wsFolder)
|
||||
path: Folders.relWsFolder(folder, wsFolder)
|
||||
}));
|
||||
|
||||
await Settings.update(SETTING_CONTENT_PAGE_FOLDERS, folderDetails, true);
|
||||
@@ -311,40 +396,141 @@ export class Folders {
|
||||
|
||||
/**
|
||||
* Retrieve the absolute file path
|
||||
* @param filePath
|
||||
* @returns
|
||||
* @param filePath
|
||||
* @returns
|
||||
*/
|
||||
public static getAbsFilePath(filePath: string): string {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const isWindows = process.platform === 'win32';
|
||||
let absPath = filePath.replace(WORKSPACE_PLACEHOLDER, parseWinPath(wsFolder?.fsPath || ""));
|
||||
let absPath = filePath.replace(WORKSPACE_PLACEHOLDER, parseWinPath(wsFolder?.fsPath || ''));
|
||||
absPath = isWindows ? absPath.split('/').join('\\') : absPath;
|
||||
return absPath;
|
||||
return parseWinPath(absPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the absolute URL for the workspace
|
||||
* @param folder
|
||||
* @param wsFolder
|
||||
* @returns
|
||||
* @param folder
|
||||
* @param wsFolder
|
||||
* @returns
|
||||
*/
|
||||
private static absWsFolder(folder: ContentFolder, wsFolder?: Uri) {
|
||||
const isWindows = process.platform === 'win32';
|
||||
let absPath = folder.path.replace(WORKSPACE_PLACEHOLDER, parseWinPath(wsFolder?.fsPath || ""));
|
||||
let absPath = folder.path.replace(WORKSPACE_PLACEHOLDER, parseWinPath(wsFolder?.fsPath || ''));
|
||||
absPath = isWindows ? absPath.split('/').join('\\') : absPath;
|
||||
return absPath;
|
||||
return parseWinPath(absPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate relative folder path
|
||||
* @param folder
|
||||
* @param wsFolder
|
||||
* @returns
|
||||
* @param folder
|
||||
* @param wsFolder
|
||||
* @returns
|
||||
*/
|
||||
public static relWsFolder(folder: ContentFolder, wsFolder?: Uri) {
|
||||
const isWindows = process.platform === 'win32';
|
||||
let absPath = parseWinPath(folder.path).replace(parseWinPath(wsFolder?.fsPath || ""), WORKSPACE_PLACEHOLDER);
|
||||
let absPath = parseWinPath(folder.path).replace(
|
||||
parseWinPath(wsFolder?.fsPath || ''),
|
||||
WORKSPACE_PLACEHOLDER
|
||||
);
|
||||
absPath = isWindows ? absPath.split('\\').join('/') : absPath;
|
||||
return absPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the content folders
|
||||
*/
|
||||
public static async getContentFolders() {
|
||||
// Find folders that contain files
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const supportedFiles =
|
||||
Settings.get<string[]>(SETTING_CONTENT_SUPPORTED_FILETYPES) || DEFAULT_FILE_TYPES;
|
||||
const patterns = supportedFiles.map(
|
||||
(fileType) =>
|
||||
`${join(
|
||||
parseWinPath(wsFolder?.fsPath || ''),
|
||||
'**',
|
||||
`*${fileType.startsWith('.') ? '' : '.'}${fileType}`
|
||||
)}`
|
||||
);
|
||||
let folders: string[] = [];
|
||||
|
||||
for (const pattern of patterns) {
|
||||
try {
|
||||
folders = [...folders, ...(await this.findFolders(pattern))];
|
||||
} catch (e) {
|
||||
Logger.error(
|
||||
`Something went wrong while searching for folders with pattern "${pattern}": ${
|
||||
(e as Error).message
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out the workspace folder
|
||||
if (wsFolder) {
|
||||
folders = folders.filter((folder) => folder !== wsFolder.fsPath);
|
||||
}
|
||||
|
||||
const uniqueFolders = [...new Set(folders)];
|
||||
return uniqueFolders.map((folder) => relative(wsFolder?.path || '', folder));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file prefix for the given folder path
|
||||
* @param folderPath
|
||||
* @returns
|
||||
*/
|
||||
public static getFilePrefixByFolderPath(folderPath: string) {
|
||||
const folders = Folders.get();
|
||||
const pageFolder = folders.find((f) => parseWinPath(f.path) === parseWinPath(folderPath));
|
||||
|
||||
if (pageFolder && typeof pageFolder.filePrefix !== 'undefined') {
|
||||
return pageFolder.filePrefix;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file prefix for the given file path
|
||||
* @param filePath
|
||||
* @returns
|
||||
*/
|
||||
public static getFilePrefixBeFilePath(filePath: string) {
|
||||
const folders = Folders.get();
|
||||
if (folders.length > 0) {
|
||||
filePath = parseWinPath(filePath);
|
||||
|
||||
let selectedFolder: ContentFolder | null = null;
|
||||
for (const folder of folders) {
|
||||
const folderPath = parseWinPath(folder.path);
|
||||
if (filePath.startsWith(folderPath)) {
|
||||
if (!selectedFolder || selectedFolder.path.length < folderPath.length) {
|
||||
selectedFolder = folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedFolder && typeof selectedFolder.filePrefix !== 'undefined') {
|
||||
return selectedFolder.filePrefix;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all content folders
|
||||
* @param pattern
|
||||
* @returns
|
||||
*/
|
||||
private static findFolders(pattern: string): Promise<string[]> {
|
||||
return new Promise((resolve) => {
|
||||
glob(pattern, { ignore: '**/node_modules/**' }, (err, files) => {
|
||||
const allFolders = files.map((file) => dirname(file));
|
||||
const uniqueFolders = [...new Set(allFolders)];
|
||||
resolve(uniqueFolders);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,36 @@
|
||||
import { processFmPlaceholders } from './../helpers/processFmPlaceholders';
|
||||
import { processPathPlaceholders } from './../helpers/processPathPlaceholders';
|
||||
import { Telemetry } from './../helpers/Telemetry';
|
||||
import { SETTING_PREVIEW_HOST, SETTING_PREVIEW_PATHNAME, CONTEXT, TelemetryEvent } from './../constants';
|
||||
import {
|
||||
SETTING_PREVIEW_HOST,
|
||||
SETTING_PREVIEW_PATHNAME,
|
||||
CONTEXT,
|
||||
TelemetryEvent,
|
||||
PreviewCommands,
|
||||
SETTING_EXPERIMENTAL,
|
||||
SETTING_DATE_FORMAT
|
||||
} from './../constants';
|
||||
import { ArticleHelper } from './../helpers/ArticleHelper';
|
||||
import { join } from "path";
|
||||
import { commands, env, Uri, ViewColumn, window } from "vscode";
|
||||
import { Settings } from '../helpers';
|
||||
import { PreviewSettings } from '../models';
|
||||
import { join } from 'path';
|
||||
import { commands, env, Uri, ViewColumn, window } from 'vscode';
|
||||
import { Extension, parseWinPath, processKnownPlaceholders, Settings } from '../helpers';
|
||||
import { ContentFolder, ContentType, PreviewSettings } from '../models';
|
||||
import { format } from 'date-fns';
|
||||
import { DateHelper } from '../helpers/DateHelper';
|
||||
import { Article } from '.';
|
||||
import { urlJoin } from 'url-join-ts';
|
||||
|
||||
import { WebviewHelper } from '@estruyf/vscode';
|
||||
import { Folders } from './Folders';
|
||||
|
||||
export class Preview {
|
||||
|
||||
/**
|
||||
/**
|
||||
* Init the preview
|
||||
*/
|
||||
public static async init() {
|
||||
const settings = Preview.getSettings();
|
||||
await commands.executeCommand('setContext', CONTEXT.canOpenPreview, !!settings.host);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open the markdown preview in the editor
|
||||
*/
|
||||
@@ -30,14 +40,57 @@ export class Preview {
|
||||
if (!settings.host) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const editor = window.activeTextEditor;
|
||||
const article = editor ? ArticleHelper.getFrontMatter(editor) : null;
|
||||
let slug = article?.data ? article.data.slug : "";
|
||||
let slug = article?.data ? article.data.slug : '';
|
||||
|
||||
let pathname = settings.pathname;
|
||||
|
||||
let selectedFolder: ContentFolder | undefined | null = null;
|
||||
const filePath = parseWinPath(editor?.document.uri.fsPath);
|
||||
|
||||
let contentType: ContentType | undefined = undefined;
|
||||
if (article?.data) {
|
||||
contentType = ArticleHelper.getContentType(article.data);
|
||||
}
|
||||
|
||||
// Check if there is a pathname defined on content folder level
|
||||
const folders = Folders.get();
|
||||
if (folders.length > 0) {
|
||||
const foldersWithPath = folders.filter((folder) => folder.previewPath);
|
||||
|
||||
for (const folder of foldersWithPath) {
|
||||
const folderPath = parseWinPath(folder.path);
|
||||
if (filePath.startsWith(folderPath)) {
|
||||
if (!selectedFolder || selectedFolder.path.length < folderPath.length) {
|
||||
selectedFolder = folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedFolder && article?.data && contentType && !contentType.previewPath) {
|
||||
// Try to find the folder by content type
|
||||
const crntFolders = folders.filter((folder) =>
|
||||
folder.contentTypes?.includes((contentType as ContentType).name)
|
||||
);
|
||||
|
||||
if (crntFolders && crntFolders.length === 1) {
|
||||
selectedFolder = crntFolders[0];
|
||||
} else if (crntFolders && crntFolders.length > 1) {
|
||||
selectedFolder = await Preview.askUserToPickFolder(crntFolders);
|
||||
} else {
|
||||
selectedFolder = await Preview.askUserToPickFolder(folders.filter((f) => f.previewPath));
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedFolder && selectedFolder.previewPath) {
|
||||
pathname = selectedFolder.previewPath;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is a pathname defined on content type level
|
||||
if (article?.data) {
|
||||
const contentType = ArticleHelper.getContentType(article.data);
|
||||
if (contentType && contentType.previewPath) {
|
||||
pathname = contentType.previewPath;
|
||||
}
|
||||
@@ -48,19 +101,52 @@ export class Preview {
|
||||
}
|
||||
|
||||
if (pathname) {
|
||||
const articleDate = ArticleHelper.getDate(article);
|
||||
// Known placeholders
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
pathname = processKnownPlaceholders(pathname, article?.data?.title, dateFormat);
|
||||
|
||||
// Custom placeholders
|
||||
pathname = await ArticleHelper.processCustomPlaceholders(
|
||||
pathname,
|
||||
article?.data?.title,
|
||||
filePath
|
||||
);
|
||||
|
||||
// Process the path placeholders - {{pathToken.<integer>}}
|
||||
if (filePath) {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
// Get relative file path
|
||||
const folderPath = wsFolder ? parseWinPath(wsFolder.fsPath) : '';
|
||||
const relativePath = filePath.replace(folderPath, '');
|
||||
pathname = processPathPlaceholders(pathname, relativePath, filePath, selectedFolder);
|
||||
}
|
||||
|
||||
// Support front matter placeholders - {{fm.<field>}}
|
||||
pathname = processFmPlaceholders(pathname, article?.data);
|
||||
|
||||
try {
|
||||
slug = join(format(articleDate || new Date(), DateHelper.formatUpdate(pathname) as string), slug);
|
||||
const articleDate = ArticleHelper.getDate(article);
|
||||
slug = join(
|
||||
format(articleDate || new Date(), DateHelper.formatUpdate(pathname) as string),
|
||||
slug
|
||||
);
|
||||
} catch (error) {
|
||||
slug = join(pathname, slug);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure there are no backslashes in the slug
|
||||
slug = parseWinPath(slug);
|
||||
|
||||
// Verify if the slug doesn't end with _index or index
|
||||
if (slug.endsWith('_index') || slug.endsWith('index')) {
|
||||
slug = slug.substring(0, slug.endsWith('_index') ? slug.length - 6 : slug.length - 5);
|
||||
}
|
||||
|
||||
// Create the preview webview
|
||||
const webView = window.createWebviewPanel(
|
||||
'frontMatterPreview',
|
||||
'FrontMatter Preview',
|
||||
article?.data?.title ? `Preview: ${article?.data?.title}` : 'FrontMatter Preview',
|
||||
{
|
||||
viewColumn: ViewColumn.Beside,
|
||||
preserveFocus: true
|
||||
@@ -73,67 +159,85 @@ export class Preview {
|
||||
webView.iconPath = {
|
||||
dark: Uri.file(join(extensionPath, 'assets/icons/frontmatter-short-dark.svg')),
|
||||
light: Uri.file(join(extensionPath, 'assets/icons/frontmatter-short-light.svg'))
|
||||
}
|
||||
};
|
||||
|
||||
const localhostUrl = await env.asExternalUri(
|
||||
Uri.parse(settings.host)
|
||||
);
|
||||
const localhostUrl = await env.asExternalUri(Uri.parse(settings.host));
|
||||
|
||||
const cspSource = webView.webview.cspSource;
|
||||
|
||||
webView.webview.html = `<!DOCTYPE html>
|
||||
<head>
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; frame-src ${localhostUrl} ${cspSource} http: https:; img-src ${localhostUrl} ${cspSource} http: https:; script-src ${localhostUrl} ${cspSource} 'unsafe-inline'; style-src ${localhostUrl} ${cspSource} 'self' 'unsafe-inline' http: https:;"
|
||||
/>
|
||||
<style>
|
||||
html,body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: white;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
webView.webview.onDidReceiveMessage((message) => {
|
||||
switch (message.command) {
|
||||
case PreviewCommands.toVSCode.open:
|
||||
if (message.data) {
|
||||
commands.executeCommand('vscode.open', message.data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
border: 0;
|
||||
margin-top: 30px;
|
||||
}
|
||||
const dashboardFile = 'dashboardWebView.js';
|
||||
const localPort = `9000`;
|
||||
const localServerUrl = `localhost:${localPort}`;
|
||||
|
||||
.slug {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: var(--vscode-editor-background);
|
||||
border-bottom: 1px solid var(--vscode-focusBorder);
|
||||
}
|
||||
const nonce = WebviewHelper.getNonce();
|
||||
|
||||
input {
|
||||
color: var(--vscode-editor-foreground);
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: none;
|
||||
border: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="slug">
|
||||
<input type="text" value="${urlJoin(localhostUrl.toString(), slug || '')}" disabled />
|
||||
</div>
|
||||
<iframe src="${urlJoin(localhostUrl.toString(), slug || '')}" >
|
||||
</body>
|
||||
</html>`;
|
||||
const ext = Extension.getInstance();
|
||||
const isProd = ext.isProductionMode;
|
||||
const version = ext.getVersion();
|
||||
const isBeta = ext.isBetaVersion();
|
||||
const extensionUri = ext.extensionPath;
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
`img-src ${localhostUrl} ${cspSource} http: https:;`,
|
||||
`script-src ${
|
||||
isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`
|
||||
} 'unsafe-eval'`,
|
||||
`style-src ${cspSource} 'self' 'unsafe-inline' http: https:`,
|
||||
`connect-src https://o1022172.ingest.sentry.io ${
|
||||
isProd
|
||||
? ``
|
||||
: `ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort}`
|
||||
}`,
|
||||
`frame-src ${localhostUrl} ${cspSource} http: https:;`
|
||||
];
|
||||
|
||||
let scriptUri = '';
|
||||
if (isProd) {
|
||||
scriptUri = webView.webview
|
||||
.asWebviewUri(Uri.joinPath(extensionUri, 'dist', dashboardFile))
|
||||
.toString();
|
||||
} else {
|
||||
scriptUri = `http://${localServerUrl}/${dashboardFile}`;
|
||||
}
|
||||
|
||||
// Get experimental setting
|
||||
const experimental = Settings.get(SETTING_EXPERIMENTAL);
|
||||
|
||||
webView.webview.html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="width:100%;height:100%;margin:0;padding:0;">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="${csp.join('; ')}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Front Matter Preview</title>
|
||||
</head>
|
||||
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden">
|
||||
<div id="app" data-type="preview" data-url="${urlJoin(
|
||||
localhostUrl.toString(),
|
||||
slug || ''
|
||||
)}" data-isProd="${isProd}" data-environment="${
|
||||
isBeta ? 'BETA' : 'main'
|
||||
}" data-version="${version.usedVersion}" ${
|
||||
experimental ? `data-experimental="${experimental}"` : ''
|
||||
} style="width:100%;height:100%;margin:0;padding:0;"></div>
|
||||
|
||||
<script ${isProd ? `nonce="${nonce}"` : ''} src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
Telemetry.send(TelemetryEvent.openPreview);
|
||||
}
|
||||
@@ -150,4 +254,32 @@ export class Preview {
|
||||
pathname
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the user to select the folder of the article to preview
|
||||
* @param crntFolders
|
||||
* @returns
|
||||
*/
|
||||
private static async askUserToPickFolder(
|
||||
crntFolders: ContentFolder[]
|
||||
): Promise<ContentFolder | undefined> {
|
||||
let selectedFolder: ContentFolder | undefined = undefined;
|
||||
|
||||
if (crntFolders.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Ask the user to select the folder
|
||||
const folderNames = crntFolders.map((folder) => folder.title);
|
||||
const selectedFolderName = await window.showQuickPick(folderNames, {
|
||||
canPickMany: false,
|
||||
title: 'Select the folder of the article to preview'
|
||||
});
|
||||
|
||||
if (selectedFolderName) {
|
||||
selectedFolder = crntFolders.find((folder) => folder.title === selectedFolderName);
|
||||
}
|
||||
|
||||
return selectedFolder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
import { DEFAULT_CONTENT_TYPE } from './../constants/ContentType';
|
||||
import { Telemetry } from './../helpers/Telemetry';
|
||||
import { workspace, Uri } from "vscode";
|
||||
import { join } from "path";
|
||||
import * as fs from "fs";
|
||||
import { Notifications } from "../helpers/Notifications";
|
||||
import { Template } from "./Template";
|
||||
import { Folders } from "./Folders";
|
||||
import { Logger, Settings } from "../helpers";
|
||||
import { SETTING_CONTENT_DEFAULT_FILETYPE, TelemetryEvent } from "../constants";
|
||||
import { workspace, Uri } from 'vscode';
|
||||
import { join } from 'path';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import { Template } from './Template';
|
||||
import { Folders } from './Folders';
|
||||
import { FrameworkDetector, Logger, MediaLibrary, Settings } from '../helpers';
|
||||
import {
|
||||
SETTING_CONTENT_DEFAULT_FILETYPE,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES,
|
||||
TelemetryEvent
|
||||
} from '../constants';
|
||||
import { SettingsListener } from '../listeners/dashboard';
|
||||
import { existsAsync, writeFileAsync } from '../utils';
|
||||
|
||||
export class Project {
|
||||
|
||||
private static content = `---
|
||||
title:
|
||||
slug:
|
||||
description:
|
||||
author:
|
||||
author:
|
||||
date: 2019-08-22T15:20:28.000Z
|
||||
lastmod: 2019-08-22T15:20:28.000Z
|
||||
draft: true
|
||||
@@ -24,41 +28,81 @@ categories: []
|
||||
---
|
||||
`;
|
||||
|
||||
public static isInitialized() {
|
||||
const hasProjectFile = Settings.hasProjectFile();
|
||||
// If it has a project file, initialize the media library
|
||||
if (hasProjectFile) {
|
||||
MediaLibrary.getInstance();
|
||||
}
|
||||
return hasProjectFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a new "Project" instance.
|
||||
*/
|
||||
public static async init(sampleTemplate: boolean = true) {
|
||||
public static async init(sampleTemplate?: boolean) {
|
||||
try {
|
||||
Settings.createTeamSettings();
|
||||
const fileType = Settings.get<string>(SETTING_CONTENT_DEFAULT_FILETYPE);
|
||||
await Settings.createTeamSettings();
|
||||
|
||||
const folder = Template.getSettings();
|
||||
const templatePath = Project.templatePath();
|
||||
// Add the default content type
|
||||
await Settings.update(SETTING_TAXONOMY_CONTENT_TYPES, [DEFAULT_CONTENT_TYPE], true);
|
||||
|
||||
if (!folder || !templatePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const article = Uri.file(join(templatePath.fsPath, `article.${fileType}`));
|
||||
|
||||
if (!fs.existsSync(templatePath.fsPath)) {
|
||||
await workspace.fs.createDirectory(templatePath);
|
||||
if (sampleTemplate !== undefined) {
|
||||
await Project.createSampleTemplate();
|
||||
} else {
|
||||
Notifications.info('Project initialized successfully.');
|
||||
}
|
||||
|
||||
if (sampleTemplate) {
|
||||
fs.writeFileSync(article.fsPath, Project.content, { encoding: "utf-8" });
|
||||
Notifications.info("Project initialized successfully.");
|
||||
// Initialize the media library
|
||||
MediaLibrary.getInstance();
|
||||
|
||||
Telemetry.send(TelemetryEvent.initialization);
|
||||
|
||||
// Check if you can find the framework
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const framework = await FrameworkDetector.get(wsFolder?.fsPath || '');
|
||||
|
||||
if (framework) {
|
||||
await SettingsListener.setFramework(framework.name);
|
||||
}
|
||||
|
||||
Telemetry.send(TelemetryEvent.initialization)
|
||||
|
||||
SettingsListener.getSettings();
|
||||
} catch (err: any) {
|
||||
SettingsListener.getSettings(true);
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
Logger.error(`Project::init: ${err?.message || err}`);
|
||||
Notifications.error(`Sorry, something went wrong - ${err?.message || err}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the templates folder + sample if needed
|
||||
* @param sampleTemplate
|
||||
* @returns
|
||||
*/
|
||||
public static async createSampleTemplate(sampleTemplate?: boolean) {
|
||||
const fileType = Settings.get<string>(SETTING_CONTENT_DEFAULT_FILETYPE);
|
||||
|
||||
const folder = Template.getSettings();
|
||||
const templatePath = Project.templatePath();
|
||||
|
||||
if (!folder || !templatePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const article = Uri.file(join(templatePath.fsPath, `article.${fileType}`));
|
||||
|
||||
if (!(await existsAsync(templatePath.fsPath))) {
|
||||
await workspace.fs.createDirectory(templatePath);
|
||||
}
|
||||
|
||||
if (sampleTemplate) {
|
||||
await writeFileAsync(article.fsPath, Project.content, {
|
||||
encoding: 'utf-8'
|
||||
});
|
||||
Notifications.info('Sample template created.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template path for the current project
|
||||
*/
|
||||
@@ -73,4 +117,4 @@ categories: []
|
||||
const templatePath = Uri.file(join(wsFolder.fsPath, folder));
|
||||
return templatePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
import { TaxonomyHelper } from './../helpers/TaxonomyHelper';
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import { TaxonomyType } from "../models";
|
||||
import { TaxonomyType } from '../models';
|
||||
import { SETTING_TAXONOMY_TAGS, SETTING_TAXONOMY_CATEGORIES, EXTENSION_NAME } from '../constants';
|
||||
import { ArticleHelper, Settings as SettingsHelper, FilesHelper } from '../helpers';
|
||||
import { FrontMatterParser } from '../parsers';
|
||||
import { DumpOptions } from 'js-yaml';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
|
||||
export class Settings {
|
||||
|
||||
/**
|
||||
* Create a new taxonomy
|
||||
*
|
||||
* @param type
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
public static async create(type: TaxonomyType) {
|
||||
const newOption = await vscode.window.showInputBox({
|
||||
prompt: `Insert the value of the ${type === TaxonomyType.Tag ? "tag" : "category"} that you want to add to your configuration.`,
|
||||
placeHolder: `Name of the ${type === TaxonomyType.Tag ? "tag" : "category"}`
|
||||
const newOption = await vscode.window.showInputBox({
|
||||
prompt: `Insert the value of the ${
|
||||
type === TaxonomyType.Tag ? 'tag' : 'category'
|
||||
} that you want to add to your configuration.`,
|
||||
placeHolder: `Name of the ${type === TaxonomyType.Tag ? 'tag' : 'category'}`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
|
||||
if (newOption) {
|
||||
const configSetting = type === TaxonomyType.Tag ? SETTING_TAXONOMY_TAGS : SETTING_TAXONOMY_CATEGORIES;
|
||||
const configSetting =
|
||||
type === TaxonomyType.Tag ? SETTING_TAXONOMY_TAGS : SETTING_TAXONOMY_CATEGORIES;
|
||||
let options = SettingsHelper.get(configSetting, true) as string[];
|
||||
if (!options) {
|
||||
options = [];
|
||||
}
|
||||
|
||||
if (options.find(o => o === newOption)) {
|
||||
Notifications.info(`The provided ${type === TaxonomyType.Tag ? "tag" : "category"} already exists.`);
|
||||
if (options.find((o) => o === newOption)) {
|
||||
Notifications.info(
|
||||
`The provided ${type === TaxonomyType.Tag ? 'tag' : 'category'} already exists.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,9 +40,15 @@ export class Settings {
|
||||
await SettingsHelper.updateTaxonomy(type, options);
|
||||
|
||||
// Ask if the new term needs to be added to the page
|
||||
const addToPage = await vscode.window.showQuickPick(["yes", "no"], { canPickMany: false, placeHolder: `Do you want to add the new ${type === TaxonomyType.Tag ? "tag" : "category"} to the page?` });
|
||||
const addToPage = await vscode.window.showQuickPick(['yes', 'no'], {
|
||||
canPickMany: false,
|
||||
placeHolder: `Do you want to add the new ${
|
||||
type === TaxonomyType.Tag ? 'tag' : 'category'
|
||||
} to the page?`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (addToPage && addToPage === "yes") {
|
||||
if (addToPage && addToPage === 'yes') {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
@@ -49,11 +59,11 @@ export class Settings {
|
||||
return;
|
||||
}
|
||||
|
||||
const matterProp: string = type === TaxonomyType.Tag ? "tags" : "categories";
|
||||
const matterProp: string = type === TaxonomyType.Tag ? 'tags' : 'categories';
|
||||
// Add the selected options to the options array
|
||||
if (article.data[matterProp]) {
|
||||
const propData: string[] = article.data[matterProp];
|
||||
if (propData && !propData.find(o => o === newOption)) {
|
||||
if (propData && !propData.find((o) => o === newOption)) {
|
||||
propData.push(newOption);
|
||||
}
|
||||
} else {
|
||||
@@ -65,195 +75,149 @@ export class Settings {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export the tags/categories front matter to the user settings
|
||||
*/
|
||||
public static async export() {
|
||||
// Retrieve all the Markdown files
|
||||
const allMdFiles = await FilesHelper.getMdFiles();
|
||||
const allMdFiles = await FilesHelper.getAllFiles();
|
||||
if (!allMdFiles) {
|
||||
return;
|
||||
}
|
||||
|
||||
vscode.window.withProgress({
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: `${EXTENSION_NAME}: exporting tags and categories`,
|
||||
cancellable: false
|
||||
}, async (progress) => {
|
||||
// Fetching all tags and categories from MD files
|
||||
let tags: string[] = [];
|
||||
let categories: string[] = [];
|
||||
vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: `${EXTENSION_NAME}: exporting tags and categories`,
|
||||
cancellable: false
|
||||
},
|
||||
async (progress) => {
|
||||
// Fetching all tags and categories from MD files
|
||||
let tags: string[] = [];
|
||||
let categories: string[] = [];
|
||||
|
||||
// Set the initial progress
|
||||
const progressNr = allMdFiles.length/100;
|
||||
progress.report({ increment: 0});
|
||||
// Set the initial progress
|
||||
const progressNr = allMdFiles.length / 100;
|
||||
progress.report({ increment: 0 });
|
||||
|
||||
let i = 0;
|
||||
for (const file of allMdFiles) {
|
||||
progress.report({ increment: (++i/progressNr) });
|
||||
const mdFile = await vscode.workspace.openTextDocument(file);
|
||||
if (mdFile) {
|
||||
const txtData = mdFile.getText();
|
||||
if (txtData) {
|
||||
try {
|
||||
const article = FrontMatterParser.fromFile(txtData);
|
||||
if (article && article.data) {
|
||||
const { data } = article;
|
||||
const mdTags = data["tags"];
|
||||
const mdCategories = data["categories"];
|
||||
if (mdTags) {
|
||||
tags = [...tags, ...mdTags];
|
||||
let i = 0;
|
||||
for (const file of allMdFiles) {
|
||||
progress.report({ increment: ++i / progressNr });
|
||||
const mdFile = await vscode.workspace.openTextDocument(file);
|
||||
if (mdFile) {
|
||||
const txtData = mdFile.getText();
|
||||
if (txtData) {
|
||||
try {
|
||||
const article = FrontMatterParser.fromFile(txtData);
|
||||
if (article && article.data) {
|
||||
const { data } = article;
|
||||
const mdTags = data['tags'];
|
||||
const mdCategories = data['categories'];
|
||||
if (mdTags) {
|
||||
tags = [...tags, ...mdTags];
|
||||
}
|
||||
if (mdCategories) {
|
||||
categories = [...categories, ...mdCategories];
|
||||
}
|
||||
}
|
||||
if (mdCategories) {
|
||||
categories = [...categories, ...mdCategories];
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue with the next file
|
||||
} catch (e) {
|
||||
// Continue with the next file
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the currently known tags, and add the new ones
|
||||
let crntTags: string[] = SettingsHelper.get(SETTING_TAXONOMY_TAGS, true) as string[];
|
||||
if (!crntTags) {
|
||||
crntTags = [];
|
||||
}
|
||||
crntTags = [...crntTags, ...tags];
|
||||
// Update the tags and filter out the duplicates
|
||||
crntTags = [...new Set(crntTags)];
|
||||
crntTags = crntTags.sort().filter((t) => !!t);
|
||||
await SettingsHelper.update(SETTING_TAXONOMY_TAGS, crntTags, true);
|
||||
|
||||
// Retrieve the currently known tags, and add the new ones
|
||||
let crntCategories: string[] = SettingsHelper.get(
|
||||
SETTING_TAXONOMY_CATEGORIES,
|
||||
true
|
||||
) as string[];
|
||||
if (!crntCategories) {
|
||||
crntCategories = [];
|
||||
}
|
||||
crntCategories = [...crntCategories, ...categories];
|
||||
// Update the categories and filter out the duplicates
|
||||
crntCategories = [...new Set(crntCategories)];
|
||||
crntCategories = crntCategories.sort().filter((c) => !!c);
|
||||
await SettingsHelper.update(SETTING_TAXONOMY_CATEGORIES, crntCategories, true);
|
||||
|
||||
// Done
|
||||
Notifications.info(
|
||||
`Export completed. Tags: ${crntTags.length} - Categories: ${crntCategories.length}.`
|
||||
);
|
||||
}
|
||||
|
||||
// Retrieve the currently known tags, and add the new ones
|
||||
let crntTags: string[] = SettingsHelper.get(SETTING_TAXONOMY_TAGS, true) as string[];
|
||||
if (!crntTags) { crntTags = []; }
|
||||
crntTags = [...crntTags, ...tags];
|
||||
// Update the tags and filter out the duplicates
|
||||
crntTags = [...new Set(crntTags)];
|
||||
crntTags = crntTags.sort().filter(t => !!t);
|
||||
await SettingsHelper.update(SETTING_TAXONOMY_TAGS, crntTags, true);
|
||||
|
||||
// Retrieve the currently known tags, and add the new ones
|
||||
let crntCategories: string[] = SettingsHelper.get(SETTING_TAXONOMY_CATEGORIES, true) as string[];
|
||||
if (!crntCategories) { crntCategories = []; }
|
||||
crntCategories = [...crntCategories, ...categories];
|
||||
// Update the categories and filter out the duplicates
|
||||
crntCategories = [...new Set(crntCategories)];
|
||||
crntCategories = crntCategories.sort().filter(c => !!c);
|
||||
await SettingsHelper.update(SETTING_TAXONOMY_CATEGORIES, crntCategories, true);
|
||||
|
||||
// Done
|
||||
Notifications.info(`Export completed. Tags: ${crntTags.length} - Categories: ${crntCategories.length}.`);
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remap a tag or category to a new one
|
||||
*/
|
||||
public static async remap() {
|
||||
const taxType = await vscode.window.showQuickPick([
|
||||
"Tag",
|
||||
"Category"
|
||||
], {
|
||||
const taxType = await vscode.window.showQuickPick(['Tag', 'Category'], {
|
||||
title: `Remap`,
|
||||
placeHolder: `What do you want to remap?`,
|
||||
canPickMany: false
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!taxType) {
|
||||
return;
|
||||
}
|
||||
|
||||
const type = taxType === "Tag" ? TaxonomyType.Tag : TaxonomyType.Category;
|
||||
let options = SettingsHelper.getTaxonomy(type);
|
||||
|
||||
const type = taxType === 'Tag' ? TaxonomyType.Tag : TaxonomyType.Category;
|
||||
const options = SettingsHelper.getTaxonomy(type);
|
||||
|
||||
if (!options || options.length === 0) {
|
||||
Notifications.info(`No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`);
|
||||
Notifications.info(`No ${type === TaxonomyType.Tag ? 'tags' : 'categories'} configured.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedOption = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: `Select your ${type === TaxonomyType.Tag ? "tags" : "categories"} to insert`,
|
||||
canPickMany: false
|
||||
const selectedOption = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: `Select your ${type === TaxonomyType.Tag ? 'tags' : 'categories'} to insert`,
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!selectedOption) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newOptionValue = await vscode.window.showInputBox({
|
||||
prompt: `Specify the value of the ${type === TaxonomyType.Tag ? "tag" : "category"} with which you want to remap "${selectedOption}". Leave the input <blank> if you want to remove the ${type === TaxonomyType.Tag ? "tag" : "category"} from all articles.`,
|
||||
placeHolder: `Name of the ${type === TaxonomyType.Tag ? "tag" : "category"}`
|
||||
const newOptionValue = await vscode.window.showInputBox({
|
||||
prompt: `Specify the value of the ${
|
||||
type === TaxonomyType.Tag ? 'tag' : 'category'
|
||||
} with which you want to remap "${selectedOption}". Leave the input <blank> if you want to remove the ${
|
||||
type === TaxonomyType.Tag ? 'tag' : 'category'
|
||||
} from all articles.`,
|
||||
placeHolder: `Name of the ${type === TaxonomyType.Tag ? 'tag' : 'category'}`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!newOptionValue) {
|
||||
const deleteAnswer = await vscode.window.showQuickPick(["yes", "no"], { canPickMany: false, placeHolder: `Delete ${selectedOption} ${type === TaxonomyType.Tag ? "tag" : "category"}?` });
|
||||
if (deleteAnswer === "no") {
|
||||
const deleteAnswer = await vscode.window.showQuickPick(['yes', 'no'], {
|
||||
canPickMany: false,
|
||||
placeHolder: `Delete ${selectedOption} ${type === TaxonomyType.Tag ? 'tag' : 'category'}?`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
if (deleteAnswer === 'no') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve all the markdown files
|
||||
const allMdFiles = await FilesHelper.getMdFiles();
|
||||
if (!allMdFiles) {
|
||||
return;
|
||||
if (newOptionValue) {
|
||||
TaxonomyHelper.process('edit', type, selectedOption, newOptionValue);
|
||||
} else {
|
||||
TaxonomyHelper.process('delete', type, selectedOption, undefined);
|
||||
}
|
||||
|
||||
let progressText = `${EXTENSION_NAME}: Remapping "${selectedOption}" ${type === TaxonomyType.Tag ? "tag" : "category"} to "${newOptionValue}".`;
|
||||
if (!newOptionValue) {
|
||||
progressText = `${EXTENSION_NAME}: Deleting "${selectedOption}" ${type === TaxonomyType.Tag ? "tag" : "category"}.`;
|
||||
}
|
||||
vscode.window.withProgress({
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: progressText,
|
||||
cancellable: false
|
||||
}, async (progress) => {
|
||||
// Set the initial progress
|
||||
const progressNr = allMdFiles.length/100;
|
||||
progress.report({ increment: 0});
|
||||
|
||||
const matterProp: string = type === TaxonomyType.Tag ? "tags" : "categories";
|
||||
|
||||
let i = 0;
|
||||
for (const file of allMdFiles) {
|
||||
progress.report({ increment: (++i/progressNr) });
|
||||
const mdFile = fs.readFileSync(file.path, { encoding: "utf8" });
|
||||
if (mdFile) {
|
||||
try {
|
||||
const article = FrontMatterParser.fromFile(mdFile);
|
||||
if (article && article.data) {
|
||||
const { data } = article;
|
||||
let taxonomies: string[] = data[matterProp];
|
||||
if (taxonomies && taxonomies.length > 0) {
|
||||
const idx = taxonomies.findIndex(o => o === selectedOption);
|
||||
if (idx !== -1) {
|
||||
if (newOptionValue) {
|
||||
taxonomies[idx] = newOptionValue;
|
||||
} else {
|
||||
taxonomies = taxonomies.filter(o => o !== selectedOption);
|
||||
}
|
||||
data[matterProp] = [...new Set(taxonomies)].sort();
|
||||
const spaces = vscode.window.activeTextEditor?.options?.tabSize;
|
||||
// Update the file
|
||||
fs.writeFileSync(file.path, FrontMatterParser.toFile(article.content, article.data, {
|
||||
indent: spaces || 2
|
||||
} as DumpOptions as any), { encoding: "utf8" });
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue with the next file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the settings
|
||||
const idx = options.findIndex(o => o === selectedOption);
|
||||
if (newOptionValue) {
|
||||
// Add or update the new option
|
||||
if (idx !== -1) {
|
||||
options[idx] = newOptionValue;
|
||||
} else {
|
||||
options.push(newOptionValue);
|
||||
}
|
||||
} else {
|
||||
// Remove the selected option
|
||||
options = options.filter(o => o !== selectedOption);
|
||||
}
|
||||
await SettingsHelper.updateTaxonomy(type, options);
|
||||
|
||||
Notifications.info(`${newOptionValue ? "Remapping" : "Deleation"} of the ${selectedOption} ${type === TaxonomyType.Tag ? "tag" : "category"} completed.`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,41 @@
|
||||
import { CONTEXT, SETTING_SEO_DESCRIPTION_FIELD, SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_TITLE_LENGTH } from './../constants';
|
||||
import { ParsedFrontMatter } from './../parsers/FrontMatterParser';
|
||||
import {
|
||||
CONTEXT,
|
||||
NOTIFICATION_TYPE,
|
||||
SETTING_SEO_DESCRIPTION_FIELD,
|
||||
SETTING_SEO_DESCRIPTION_LENGTH,
|
||||
SETTING_SEO_TITLE_FIELD,
|
||||
SETTING_SEO_TITLE_LENGTH
|
||||
} from './../constants';
|
||||
import * as vscode from 'vscode';
|
||||
import { ArticleHelper, SeoHelper, Settings } from '../helpers';
|
||||
import { ArticleHelper, Notifications, SeoHelper, Settings } from '../helpers';
|
||||
import { ExplorerView } from '../explorerView/ExplorerView';
|
||||
import { DefaultFields } from '../constants';
|
||||
import { ContentType } from '../helpers/ContentType';
|
||||
import { DataListener } from '../listeners/panel';
|
||||
import { commands } from 'vscode';
|
||||
import { Field } from '../models';
|
||||
|
||||
export class StatusListener {
|
||||
|
||||
/**
|
||||
* Update the text of the status bar
|
||||
*
|
||||
* @param frontMatterSB
|
||||
* @param collection
|
||||
*
|
||||
* @param frontMatterSB
|
||||
* @param collection
|
||||
*/
|
||||
public static async verify(frontMatterSB: vscode.StatusBarItem, collection: vscode.DiagnosticCollection) {
|
||||
const draftMsg = "in draft";
|
||||
const publishMsg = "to publish";
|
||||
public static async verify(
|
||||
frontMatterSB: vscode.StatusBarItem,
|
||||
collection: vscode.DiagnosticCollection
|
||||
) {
|
||||
const draftMsg = 'in draft';
|
||||
const publishMsg = 'to publish';
|
||||
|
||||
const draft = ContentType.getDraftField();
|
||||
if (!draft || draft.type !== "boolean") {
|
||||
if (!draft || draft.type !== 'boolean') {
|
||||
frontMatterSB.hide();
|
||||
}
|
||||
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor && ArticleHelper.isSupportedFile()) {
|
||||
try {
|
||||
commands.executeCommand('setContext', CONTEXT.isValidFile, true);
|
||||
@@ -32,37 +43,43 @@ export class StatusListener {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
|
||||
// Update the StatusBar based on the article draft state
|
||||
if (article && typeof article.data["draft"] !== "undefined") {
|
||||
if (article.data["draft"] === true) {
|
||||
if (article && typeof article.data['draft'] !== 'undefined') {
|
||||
if (article.data['draft'] === true) {
|
||||
frontMatterSB.text = `$(book) ${draftMsg}`;
|
||||
frontMatterSB.show();
|
||||
} else if (article.data["draft"] === false) {
|
||||
} else if (article.data['draft'] === false) {
|
||||
frontMatterSB.text = `$(book) ${publishMsg}`;
|
||||
frontMatterSB.show();
|
||||
}
|
||||
}
|
||||
|
||||
// Check SEO for title and description length
|
||||
// Check SEO and required fields
|
||||
if (article && article.data) {
|
||||
collection.clear();
|
||||
|
||||
// Retrieve the SEO config properties
|
||||
const titleLength = Settings.get(SETTING_SEO_TITLE_LENGTH) as number || -1;
|
||||
const descLength = Settings.get(SETTING_SEO_DESCRIPTION_LENGTH) as number || -1;
|
||||
const fieldName = Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string || DefaultFields.Description;
|
||||
|
||||
if (article.data.title && titleLength > -1) {
|
||||
SeoHelper.checkLength(editor, collection, article, "title", titleLength);
|
||||
const titleLength = (Settings.get(SETTING_SEO_TITLE_LENGTH) as number) || -1;
|
||||
const descLength = (Settings.get(SETTING_SEO_DESCRIPTION_LENGTH) as number) || -1;
|
||||
const titleField =
|
||||
(Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
|
||||
const descriptionField =
|
||||
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description;
|
||||
|
||||
if (article.data[titleField] && titleLength > -1) {
|
||||
SeoHelper.checkLength(editor, collection, article, titleField, titleLength);
|
||||
}
|
||||
|
||||
if (article.data[fieldName] && descLength > -1) {
|
||||
SeoHelper.checkLength(editor, collection, article, fieldName, descLength);
|
||||
|
||||
if (article.data[descriptionField] && descLength > -1) {
|
||||
SeoHelper.checkLength(editor, collection, article, descriptionField, descLength);
|
||||
}
|
||||
|
||||
// Check the required fields
|
||||
StatusListener.verifyRequiredFields(editor, article, collection);
|
||||
}
|
||||
|
||||
|
||||
const panel = ExplorerView.getInstance();
|
||||
if (panel && panel.visible) {
|
||||
DataListener.pushMetadata(article!.data);
|
||||
DataListener.pushMetadata(article?.data);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -80,4 +97,114 @@ export class StatusListener {
|
||||
|
||||
frontMatterSB.hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the required fields
|
||||
* @param article
|
||||
* @param collection
|
||||
*/
|
||||
private static verifyRequiredFields(
|
||||
editor: vscode.TextEditor,
|
||||
article: ParsedFrontMatter,
|
||||
collection: vscode.DiagnosticCollection
|
||||
) {
|
||||
// Check for missing fields
|
||||
const emptyFields = ContentType.findEmptyRequiredFields(article);
|
||||
const fieldsToReport = [];
|
||||
|
||||
if (emptyFields && emptyFields.length > 0) {
|
||||
const text = editor.document.getText();
|
||||
const markdown = ArticleHelper.stringifyFrontMatter('', article.data);
|
||||
const editorSpaces = vscode.window.activeTextEditor?.options?.tabSize;
|
||||
|
||||
const requiredDiagnostics: vscode.Diagnostic[] = [];
|
||||
|
||||
for (const fields of emptyFields) {
|
||||
let txtIdx = -1;
|
||||
let fieldName = '';
|
||||
let level = 0;
|
||||
|
||||
for (const field of fields) {
|
||||
const totalSpaces =
|
||||
level * (typeof editorSpaces === 'string' ? parseInt(editorSpaces) : editorSpaces || 2);
|
||||
const crntIdx = StatusListener.findFieldLine(text, txtIdx, totalSpaces, field);
|
||||
|
||||
if (crntIdx && crntIdx > txtIdx) {
|
||||
txtIdx = crntIdx;
|
||||
fieldName = field.name;
|
||||
}
|
||||
|
||||
++level;
|
||||
}
|
||||
|
||||
if (txtIdx !== -1 && txtIdx < markdown.length) {
|
||||
fieldsToReport.push(fields.map((f) => f.title).join('/'));
|
||||
|
||||
const posStart = editor.document.positionAt(txtIdx);
|
||||
const posEnd = editor.document.positionAt(txtIdx + 1 + fieldName.length);
|
||||
|
||||
const diagnostic: vscode.Diagnostic = {
|
||||
code: '',
|
||||
message: `This ${fields
|
||||
.map((f) => f.name)
|
||||
.join('/')} field is required to contain a value.`,
|
||||
range: new vscode.Range(posStart, posEnd),
|
||||
severity: vscode.DiagnosticSeverity.Error,
|
||||
source: 'Front Matter'
|
||||
};
|
||||
|
||||
requiredDiagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
if (collection.has(editor.document.uri)) {
|
||||
const otherDiag = collection.get(editor.document.uri) || [];
|
||||
collection.set(editor.document.uri, [...otherDiag, ...requiredDiagnostics]);
|
||||
} else {
|
||||
collection.set(editor.document.uri, [...requiredDiagnostics]);
|
||||
}
|
||||
|
||||
if (fieldsToReport.length > 0) {
|
||||
Notifications.showIfNotDisabled(
|
||||
NOTIFICATION_TYPE.requiredFieldValidation,
|
||||
'ERROR_ONCE',
|
||||
`The following fields are required to contain a value: ${fieldsToReport.join(', ')}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the line of the field
|
||||
* @param text
|
||||
* @param startIdx
|
||||
* @param totalSpaces
|
||||
* @param field
|
||||
* @returns
|
||||
*/
|
||||
private static findFieldLine(
|
||||
text: string,
|
||||
startIdx: number,
|
||||
totalSpaces: number,
|
||||
field: Field
|
||||
): number | undefined {
|
||||
const crntIdx = text.indexOf(field.name, startIdx === -1 ? 0 : startIdx);
|
||||
|
||||
if (crntIdx > -1) {
|
||||
// Find the linebreak before the current index
|
||||
const txtFromStart = text.substring(0, crntIdx);
|
||||
const splitLineBreaks = txtFromStart.split(/\r?\n/);
|
||||
const lastLine = splitLineBreaks[splitLineBreaks.length - 1];
|
||||
|
||||
if (lastLine.length === totalSpaces) {
|
||||
if (crntIdx > startIdx) {
|
||||
return crntIdx;
|
||||
}
|
||||
} else {
|
||||
return StatusListener.findFieldLine(text, crntIdx + field.name.length, totalSpaces, field);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,23 @@
|
||||
import { Questions } from './../helpers/Questions';
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { SETTING_CONTENT_DEFAULT_FILETYPE, SETTING_TEMPLATES_FOLDER, TelemetryEvent } from '../constants';
|
||||
import {
|
||||
SETTING_CONTENT_DEFAULT_FILETYPE,
|
||||
SETTING_TEMPLATES_FOLDER,
|
||||
TelemetryEvent
|
||||
} from '../constants';
|
||||
import { ArticleHelper, Settings } from '../helpers';
|
||||
import { Article } from '.';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import { CONTEXT } from '../constants';
|
||||
import { Project } from './Project';
|
||||
import { Folders } from './Folders';
|
||||
import { ContentType } from '../helpers/ContentType';
|
||||
import { ContentType as IContentType } from '../models';
|
||||
import { PagesListener } from '../listeners/dashboard';
|
||||
import { extname } from 'path';
|
||||
import { Telemetry } from '../helpers/Telemetry';
|
||||
import { writeFileAsync, copyFileAsync } from '../utils';
|
||||
|
||||
export class Template {
|
||||
|
||||
/**
|
||||
* Check if the template folder is available
|
||||
*/
|
||||
public static async init() {
|
||||
const isInitialized = await Template.isInitialized();
|
||||
await vscode.commands.executeCommand('setContext', CONTEXT.canInit, !isInitialized);
|
||||
|
||||
if (isInitialized) {
|
||||
await vscode.commands.executeCommand('setContext', CONTEXT.initialized, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the project is already initialized
|
||||
*/
|
||||
public static async isInitialized() {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const folder = Template.getSettings();
|
||||
|
||||
if (!folder || !wsFolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const templatePath = vscode.Uri.file(path.join(wsFolder.fsPath, folder));
|
||||
|
||||
try {
|
||||
await vscode.workspace.fs.stat(templatePath);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a template
|
||||
*/
|
||||
@@ -62,9 +30,11 @@ export class Template {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
const clonedArticle = Object.assign({}, article);
|
||||
|
||||
const titleValue = await vscode.window.showInputBox({
|
||||
const titleValue = await vscode.window.showInputBox({
|
||||
title: `Template title`,
|
||||
prompt: `What name would you like to give your template?`,
|
||||
placeHolder: `article`
|
||||
placeHolder: `article`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!titleValue) {
|
||||
@@ -72,37 +42,57 @@ export class Template {
|
||||
return;
|
||||
}
|
||||
|
||||
const keepContents = await vscode.window.showQuickPick(
|
||||
["yes", "no"],
|
||||
{
|
||||
canPickMany: false,
|
||||
placeHolder: `Do you want to keep the contents for the template?`,
|
||||
}
|
||||
);
|
||||
const keepContents = await vscode.window.showQuickPick(['yes', 'no'], {
|
||||
title: `Keep contents`,
|
||||
canPickMany: false,
|
||||
placeHolder: `Do you want to keep the contents for the template?`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!keepContents) {
|
||||
Notifications.warning(`You did not pick any of the options for keeping the template its content.`);
|
||||
Notifications.warning(
|
||||
`You did not pick any of the options for keeping the template its content.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await Project.init(false);
|
||||
const templatePath = Project.templatePath();
|
||||
if (templatePath) {
|
||||
let fileContents = ArticleHelper.stringifyFrontMatter(keepContents === "no" ? "" : clonedArticle.content, clonedArticle.data);
|
||||
const fileContents = ArticleHelper.stringifyFrontMatter(
|
||||
keepContents === 'no' ? '' : clonedArticle.content,
|
||||
clonedArticle.data
|
||||
);
|
||||
|
||||
const templateFile = path.join(templatePath.fsPath, `${titleValue}.${fileType}`);
|
||||
fs.writeFileSync(templateFile, fileContents, { encoding: "utf-8" });
|
||||
await writeFileAsync(templateFile, fileContents, { encoding: 'utf-8' });
|
||||
|
||||
Notifications.info(`Template created and is now available in your ${folder} folder.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all templates
|
||||
*/
|
||||
public static async getTemplates() {
|
||||
const folder = Settings.get<string>(SETTING_TEMPLATES_FOLDER);
|
||||
|
||||
if (!folder) {
|
||||
Notifications.warning(`No templates found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
return await vscode.workspace.findFiles(
|
||||
`${folder}/**/*`,
|
||||
'**/node_modules/**,**/archetypes/**'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from a template
|
||||
*/
|
||||
public static async create(folderPath: string) {
|
||||
const folder = Settings.get<string>(SETTING_TEMPLATES_FOLDER);
|
||||
const contentTypes = ContentType.getAll();
|
||||
|
||||
if (!folderPath) {
|
||||
@@ -110,20 +100,20 @@ export class Template {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!folder) {
|
||||
Notifications.warning(`No templates found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const templates = await vscode.workspace.findFiles(`${folder}/**/*`, "**/node_modules/**,**/archetypes/**");
|
||||
const templates = await Template.getTemplates();
|
||||
if (!templates || templates.length === 0) {
|
||||
Notifications.warning(`No templates found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedTemplate = await vscode.window.showQuickPick(templates.map(t => path.basename(t.fsPath)), {
|
||||
placeHolder: `Select the content template to use`
|
||||
});
|
||||
const selectedTemplate = await vscode.window.showQuickPick(
|
||||
templates.map((t) => path.basename(t.fsPath)),
|
||||
{
|
||||
title: `Select a template`,
|
||||
placeHolder: `Select the content template to use`,
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
if (!selectedTemplate) {
|
||||
Notifications.warning(`No template selected.`);
|
||||
return;
|
||||
@@ -135,40 +125,53 @@ export class Template {
|
||||
}
|
||||
|
||||
// Start the template read
|
||||
const template = templates.find(t => t.fsPath.endsWith(selectedTemplate));
|
||||
const template = templates.find((t) => t.fsPath.endsWith(selectedTemplate));
|
||||
if (!template) {
|
||||
Notifications.warning(`Content template could not be found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const templateData = ArticleHelper.getFrontMatterByPath(template.fsPath);
|
||||
const templateData = await ArticleHelper.getFrontMatterByPath(template.fsPath);
|
||||
let contentType: IContentType | undefined;
|
||||
if (templateData && templateData.data && templateData.data.type) {
|
||||
contentType = contentTypes?.find(t => t.name === templateData.data.type);
|
||||
contentType = contentTypes?.find((t) => t.name === templateData.data.type);
|
||||
}
|
||||
|
||||
const fileExtension = extname(template.fsPath).replace(".", "");
|
||||
let newFilePath: string | undefined = ArticleHelper.createContent(contentType, folderPath, titleValue, fileExtension);
|
||||
const fileExtension = extname(template.fsPath).replace('.', '');
|
||||
const newFilePath: string | undefined = await ArticleHelper.createContent(
|
||||
contentType,
|
||||
folderPath,
|
||||
titleValue,
|
||||
fileExtension
|
||||
);
|
||||
if (!newFilePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Start the new file creation
|
||||
fs.copyFileSync(template.fsPath, newFilePath);
|
||||
await copyFileAsync(template.fsPath, newFilePath);
|
||||
|
||||
// Update the properties inside the template
|
||||
let frontMatter = ArticleHelper.getFrontMatterByPath(newFilePath);
|
||||
let frontMatter = await ArticleHelper.getFrontMatterByPath(newFilePath);
|
||||
if (!frontMatter) {
|
||||
Notifications.warning(`Something failed when retrieving the newly created file.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (frontMatter.data) {
|
||||
frontMatter.data = ArticleHelper.updatePlaceholders(frontMatter.data, titleValue);
|
||||
frontMatter.data = await ArticleHelper.updatePlaceholders(
|
||||
frontMatter.data,
|
||||
titleValue,
|
||||
newFilePath
|
||||
);
|
||||
|
||||
frontMatter = Article.updateDate(frontMatter);
|
||||
|
||||
fs.writeFileSync(newFilePath, ArticleHelper.stringifyFrontMatter(frontMatter.content, frontMatter.data), { encoding: "utf8" });
|
||||
await writeFileAsync(
|
||||
newFilePath,
|
||||
ArticleHelper.stringifyFrontMatter(frontMatter.content, frontMatter.data),
|
||||
{ encoding: 'utf8' }
|
||||
);
|
||||
|
||||
await vscode.commands.executeCommand('vscode.open', vscode.Uri.file(newFilePath));
|
||||
}
|
||||
@@ -193,4 +196,4 @@ export class Template {
|
||||
const folder = Settings.get<string>(SETTING_TEMPLATES_FOLDER);
|
||||
return folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { commands, window, Selection, QuickPickItem } from "vscode";
|
||||
import { COMMAND_NAME, CONTEXT, SETTING_CONTENT_WYSIWYG } from "../constants";
|
||||
import { Settings } from "../helpers";
|
||||
import { commands, window, Selection, QuickPickItem, TextEditor } from 'vscode';
|
||||
import { COMMAND_NAME, CONTEXT, SETTING_CONTENT_WYSIWYG } from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
|
||||
enum MarkupType {
|
||||
bold = 1,
|
||||
@@ -12,18 +12,17 @@ enum MarkupType {
|
||||
heading,
|
||||
unorderedList,
|
||||
orderedList,
|
||||
taskList
|
||||
taskList,
|
||||
hyperlink
|
||||
}
|
||||
|
||||
export class Wysiwyg {
|
||||
|
||||
/**
|
||||
* Registers the markup commands for the WYSIWYG controls
|
||||
* @param subscriptions
|
||||
* @returns
|
||||
* @param subscriptions
|
||||
* @returns
|
||||
*/
|
||||
public static async registerCommands(subscriptions: any) {
|
||||
|
||||
public static async registerCommands(subscriptions: unknown[]) {
|
||||
const wysiwygEnabled = Settings.get(SETTING_CONTENT_WYSIWYG);
|
||||
|
||||
if (!wysiwygEnabled) {
|
||||
@@ -33,58 +32,123 @@ export class Wysiwyg {
|
||||
await commands.executeCommand('setContext', CONTEXT.wysiwyg, true);
|
||||
|
||||
// Surrounding markup
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.bold, () => this.addMarkup(MarkupType.bold)));
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.italic, () => this.addMarkup(MarkupType.italic)));
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.strikethrough, () => this.addMarkup(MarkupType.strikethrough)));
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.code, () => this.addMarkup(MarkupType.code)));
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.codeblock, () => this.addMarkup(MarkupType.codeblock)));
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.bold, () => this.addMarkup(MarkupType.bold))
|
||||
);
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.italic, () => this.addMarkup(MarkupType.italic))
|
||||
);
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.strikethrough, () =>
|
||||
this.addMarkup(MarkupType.strikethrough)
|
||||
)
|
||||
);
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.code, () => this.addMarkup(MarkupType.code))
|
||||
);
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.codeblock, () => this.addMarkup(MarkupType.codeblock))
|
||||
);
|
||||
|
||||
// Prefix markup
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.heading, () => this.addMarkup(MarkupType.heading)));
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.blockquote, () => this.addMarkup(MarkupType.blockquote)));
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.unorderedlist, () => this.addMarkup(MarkupType.unorderedList)));
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.orderedlist, () => this.addMarkup(MarkupType.orderedList)));
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.taskList, () => this.addMarkup(MarkupType.taskList)));
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.heading, () => this.addMarkup(MarkupType.heading))
|
||||
);
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.blockquote, () => this.addMarkup(MarkupType.blockquote))
|
||||
);
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.unorderedlist, () =>
|
||||
this.addMarkup(MarkupType.unorderedList)
|
||||
)
|
||||
);
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.orderedlist, () =>
|
||||
this.addMarkup(MarkupType.orderedList)
|
||||
)
|
||||
);
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.taskList, () => this.addMarkup(MarkupType.taskList))
|
||||
);
|
||||
|
||||
// Other markup
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.hyperlink, () => this.addMarkup(MarkupType.hyperlink))
|
||||
);
|
||||
|
||||
// Options
|
||||
subscriptions.push(commands.registerCommand(COMMAND_NAME.options, async () => {
|
||||
const qpItems: QuickPickItem[] = [
|
||||
{ label: "$(list-unordered) Unordered list", detail: "Add an unordered list", alwaysShow: true, },
|
||||
{ label: "$(list-ordered) Ordered list", detail: "Add an ordered list", alwaysShow: true },
|
||||
{ label: "$(tasklist) Task list", detail: "Add a task list", alwaysShow: true },
|
||||
{ label: "$(code) Code", detail: "Add inline code snippet", alwaysShow: true },
|
||||
{ label: "$(symbol-namespace) Code block", detail: "Add a code block", alwaysShow: true },
|
||||
{ label: "$(quote) Blockquote", detail: "Add a blockquote", alwaysShow: true },
|
||||
]
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.options, async () => {
|
||||
const qpItems: QuickPickItem[] = [
|
||||
{
|
||||
label: '$(list-unordered) Unordered list',
|
||||
detail: 'Add an unordered list',
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(list-ordered) Ordered list',
|
||||
detail: 'Add an ordered list',
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(tasklist) Task list',
|
||||
detail: 'Add a task list',
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(code) Code',
|
||||
detail: 'Add inline code snippet',
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(symbol-namespace) Code block',
|
||||
detail: 'Add a code block',
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(quote) Blockquote',
|
||||
detail: 'Add a blockquote',
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(symbol-text) Strikethrough',
|
||||
detail: 'Add a strikethrough',
|
||||
alwaysShow: true
|
||||
}
|
||||
];
|
||||
|
||||
const option = await window.showQuickPick([ ...qpItems ], {
|
||||
placeHolder: "Which type of markup would you like to insert?",
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: false,
|
||||
});
|
||||
const option = await window.showQuickPick([...qpItems], {
|
||||
title: 'WYSIWYG Options',
|
||||
placeHolder: 'Which type of markup would you like to insert?',
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (option) {
|
||||
if (option.label === qpItems[0].label) {
|
||||
await this.addMarkup(MarkupType.unorderedList);
|
||||
} else if (option.label === qpItems[1].label) {
|
||||
await this.addMarkup(MarkupType.orderedList);
|
||||
} else if (option.label === qpItems[2].label) {
|
||||
await this.addMarkup(MarkupType.taskList);
|
||||
} else if (option.label === qpItems[3].label) {
|
||||
await this.addMarkup(MarkupType.code);
|
||||
} else if (option.label === qpItems[4].label) {
|
||||
await this.addMarkup(MarkupType.codeblock);
|
||||
} else if (option.label === qpItems[5].label) {
|
||||
await this.addMarkup(MarkupType.blockquote);
|
||||
if (option) {
|
||||
if (option.label === qpItems[0].label) {
|
||||
await this.addMarkup(MarkupType.unorderedList);
|
||||
} else if (option.label === qpItems[1].label) {
|
||||
await this.addMarkup(MarkupType.orderedList);
|
||||
} else if (option.label === qpItems[2].label) {
|
||||
await this.addMarkup(MarkupType.taskList);
|
||||
} else if (option.label === qpItems[3].label) {
|
||||
await this.addMarkup(MarkupType.code);
|
||||
} else if (option.label === qpItems[4].label) {
|
||||
await this.addMarkup(MarkupType.codeblock);
|
||||
} else if (option.label === qpItems[5].label) {
|
||||
await this.addMarkup(MarkupType.blockquote);
|
||||
} else if (option.label === qpItems[6].label) {
|
||||
await this.addMarkup(MarkupType.strikethrough);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the markup to the content
|
||||
* @param type
|
||||
* @returns
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
private static async addMarkup(type: MarkupType) {
|
||||
const editor = window.activeTextEditor;
|
||||
@@ -95,6 +159,10 @@ export class Wysiwyg {
|
||||
const selection = editor.selection;
|
||||
const hasTextSelection = !selection.isEmpty;
|
||||
|
||||
if (type === MarkupType.hyperlink) {
|
||||
return this.addHyperlink(editor, selection);
|
||||
}
|
||||
|
||||
const markers = this.getMarkers(type);
|
||||
if (!markers) {
|
||||
return;
|
||||
@@ -106,18 +174,21 @@ export class Wysiwyg {
|
||||
// Replace the selection and surround with the markup
|
||||
const selectionText = editor.document.getText(selection);
|
||||
const txt = await this.insertText(markers, type, selectionText);
|
||||
|
||||
editor.edit(builder => {
|
||||
|
||||
editor.edit((builder) => {
|
||||
builder.replace(selection, txt);
|
||||
});
|
||||
} else {
|
||||
const txt = await this.insertText(markers, type);
|
||||
|
||||
|
||||
// Insert the markers where cursor is located.
|
||||
const markerLength = this.isMarkupWrapping(type) ? txt.length + 1 : markers.length;
|
||||
let newPosition = crntSelection.with(crntSelection.line, crntSelection.character + markerLength);
|
||||
let newPosition = crntSelection.with(
|
||||
crntSelection.line,
|
||||
crntSelection.character + markerLength
|
||||
);
|
||||
|
||||
await editor.edit(builder => {
|
||||
await editor.edit((builder) => {
|
||||
builder.insert(newPosition, txt);
|
||||
});
|
||||
|
||||
@@ -130,13 +201,61 @@ export class Wysiwyg {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the text will be wrapped
|
||||
* @param type
|
||||
* @returns
|
||||
* Add a hyperlink to the content
|
||||
* @returns void
|
||||
*/
|
||||
private static isMarkupWrapping(type: MarkupType) {
|
||||
private static async addHyperlink(editor: TextEditor, selection: Selection) {
|
||||
const hasTextSelection = !selection.isEmpty;
|
||||
const linkText = hasTextSelection ? editor.document.getText(selection) : '';
|
||||
|
||||
const link = await window.showInputBox({
|
||||
title: 'WYSIWYG Hyperlink',
|
||||
placeHolder: 'Enter the URL',
|
||||
prompt: 'Enter the URL',
|
||||
value: linkText,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
const text = await window.showInputBox({
|
||||
title: 'WYSIWYG Text',
|
||||
prompt: 'Enter the text for the hyperlink',
|
||||
placeHolder: 'Enter the text for the hyperlink',
|
||||
value: linkText,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (link) {
|
||||
const txt = `[${text || link}](${link})`;
|
||||
|
||||
if (hasTextSelection) {
|
||||
editor.edit((builder) => {
|
||||
builder.replace(selection, txt);
|
||||
});
|
||||
} else {
|
||||
const crntSelection = selection.active;
|
||||
const markerLength = txt.length;
|
||||
const newPosition = crntSelection.with(
|
||||
crntSelection.line,
|
||||
crntSelection.character + markerLength
|
||||
);
|
||||
|
||||
await editor.edit((builder) => {
|
||||
builder.insert(newPosition, txt);
|
||||
});
|
||||
|
||||
editor.selection = new Selection(newPosition, newPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the text will be wrapped
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
private static isMarkupWrapping(type: MarkupType) {
|
||||
return (
|
||||
type === MarkupType.blockquote ||
|
||||
type === MarkupType.blockquote ||
|
||||
type === MarkupType.heading ||
|
||||
type === MarkupType.unorderedList ||
|
||||
type === MarkupType.orderedList ||
|
||||
@@ -147,38 +266,39 @@ export class Wysiwyg {
|
||||
/**
|
||||
* Insert text at the current cursor position
|
||||
*/
|
||||
private static async insertText(marker: string | undefined, type: MarkupType, text: string | null = null) {
|
||||
private static async insertText(
|
||||
marker: string | undefined,
|
||||
type: MarkupType,
|
||||
text: string | null = null
|
||||
) {
|
||||
const crntText = text || this.lineBreak(type);
|
||||
|
||||
if (this.isMarkupWrapping(type)) {
|
||||
if (type === MarkupType.heading) {
|
||||
const headingLvl = await window.showQuickPick([
|
||||
"Heading 1",
|
||||
"Heading 2",
|
||||
"Heading 3",
|
||||
"Heading 4",
|
||||
"Heading 5",
|
||||
"Heading 6"
|
||||
], {
|
||||
canPickMany: false,
|
||||
placeHolder: "Which heading level do you want to insert?",
|
||||
ignoreFocusOut: false
|
||||
});
|
||||
const headingLvl = await window.showQuickPick(
|
||||
['Heading 1', 'Heading 2', 'Heading 3', 'Heading 4', 'Heading 5', 'Heading 6'],
|
||||
{
|
||||
title: 'Heading Level',
|
||||
canPickMany: false,
|
||||
placeHolder: 'Which heading level do you want to insert?',
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
|
||||
if (headingLvl) {
|
||||
const headingNr = parseInt(headingLvl.replace("Heading ", ""));
|
||||
const headingNr = parseInt(headingLvl.replace('Heading ', ''));
|
||||
return `${Array(headingNr + 1).join(marker)} ${crntText}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (type === MarkupType.unorderedList || type === MarkupType.taskList) {
|
||||
const lines = crntText.split("\n").map(line => `${marker} ${line}`);
|
||||
return lines.join("\n");
|
||||
const lines = crntText.split('\n').map((line) => `${marker} ${line}`);
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
if (type === MarkupType.orderedList) {
|
||||
const lines = crntText.split("\n").map((line, idx) => `${idx+1}. ${line}`);
|
||||
return lines.join("\n");
|
||||
const lines = crntText.split('\n').map((line, idx) => `${idx + 1}. ${line}`);
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
return `${marker} ${crntText}`;
|
||||
@@ -189,23 +309,23 @@ export class Wysiwyg {
|
||||
|
||||
/**
|
||||
* Check if linebreak needs to be added
|
||||
* @param type
|
||||
* @returns
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
private static lineBreak(type: MarkupType) {
|
||||
if (type === MarkupType.codeblock) {
|
||||
return `\n\n`;
|
||||
}
|
||||
return "";
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the type of markers
|
||||
* @param type
|
||||
* @returns
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
private static getMarkers(type: MarkupType) {
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case MarkupType.bold:
|
||||
return `**`;
|
||||
case MarkupType.italic:
|
||||
@@ -213,21 +333,21 @@ export class Wysiwyg {
|
||||
case MarkupType.strikethrough:
|
||||
return `~~`;
|
||||
case MarkupType.code:
|
||||
return "`";
|
||||
return '`';
|
||||
case MarkupType.codeblock:
|
||||
return "```";
|
||||
return '```';
|
||||
case MarkupType.blockquote:
|
||||
return ">";
|
||||
return '>';
|
||||
case MarkupType.heading:
|
||||
return "#";
|
||||
return '#';
|
||||
case MarkupType.unorderedList:
|
||||
return "-";
|
||||
return '-';
|
||||
case MarkupType.orderedList:
|
||||
return "1.";
|
||||
return '1.';
|
||||
case MarkupType.taskList:
|
||||
return "- [ ]";
|
||||
return '- [ ]';
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
export * from './Article';
|
||||
export * from './Backers';
|
||||
export * from './Cache';
|
||||
export * from './Content';
|
||||
export * from './Dashboard';
|
||||
export * from './Diagnostics';
|
||||
export * from './Folders';
|
||||
export * from './Preview';
|
||||
export * from './Project';
|
||||
export * from './Settings';
|
||||
export * from './StatusListener';
|
||||
export * from './Template';
|
||||
export * from './Wysiwyg';
|
||||
|
||||
@@ -6,9 +6,13 @@ export interface IFeatureFlagProps {
|
||||
alternative?: JSX.Element;
|
||||
}
|
||||
|
||||
export const FeatureFlag: React.FunctionComponent<IFeatureFlagProps> = ({ flag, features, alternative, children }: React.PropsWithChildren<IFeatureFlagProps>) => {
|
||||
|
||||
if (!features ||( features.length > 0 && !features.includes(flag))) {
|
||||
export const FeatureFlag: React.FunctionComponent<IFeatureFlagProps> = ({
|
||||
flag,
|
||||
features,
|
||||
alternative,
|
||||
children
|
||||
}: React.PropsWithChildren<IFeatureFlagProps>) => {
|
||||
if (!features || (features.length > 0 && !features.includes(flag))) {
|
||||
if (alternative) {
|
||||
return alternative;
|
||||
}
|
||||
@@ -16,11 +20,5 @@ export const FeatureFlag: React.FunctionComponent<IFeatureFlagProps> = ({ flag,
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
@@ -4,10 +4,22 @@ export interface ICompressIconProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const CompressIcon: React.FunctionComponent<ICompressIconProps> = ({className}: React.PropsWithChildren<ICompressIconProps>) => {
|
||||
export const CompressIcon: React.FunctionComponent<ICompressIconProps> = ({
|
||||
className
|
||||
}: React.PropsWithChildren<ICompressIconProps>) => {
|
||||
return (
|
||||
<svg className={className || ""} aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M436 192H312c-13.3 0-24-10.7-24-24V44c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v84h84c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm-276-24V44c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v84H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24zm0 300V344c0-13.3-10.7-24-24-24H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0v-84h84c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12H312c-13.3 0-24 10.7-24 24v124c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12z"></path>
|
||||
<svg
|
||||
className={className || ''}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M436 192H312c-13.3 0-24-10.7-24-24V44c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v84h84c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm-276-24V44c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v84H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24zm0 300V344c0-13.3-10.7-24-24-24H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0v-84h84c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12H312c-13.3 0-24 10.7-24 24v124c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
19
src/components/icons/MergeIcon.tsx
Normal file
19
src/components/icons/MergeIcon.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IMergeIconProps {
|
||||
className: string;
|
||||
}
|
||||
|
||||
export const MergeIcon: React.FunctionComponent<IMergeIconProps> = ({
|
||||
className
|
||||
}: React.PropsWithChildren<IMergeIconProps>) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" className={className}>
|
||||
<path
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
d="M7.586 8.00366L4 8.00366C3.44772 8.00366 3 7.55595 3 7.00366C3 6.45138 3.44772 6.00366 4 6.00366L8 6.00366C8.26509 6.00366 8.51933 6.10892 8.70685 6.2963L13.414 11H18.5845L15.2931 7.71103C14.9025 7.32065 14.9023 6.68748 15.2926 6.29681C15.683 5.90615 16.3162 5.90592 16.7068 6.2963L21.7068 11.2926C21.8945 11.4802 22 11.7346 22 11.9998C22 12.2651 21.8947 12.5195 21.7071 12.7071L16.7071 17.7071C16.3166 18.0976 15.6834 18.0976 15.2929 17.7071C14.9024 17.3166 14.9024 16.6834 15.2929 16.2929L18.5858 13H13.4142L8.70711 17.7071C8.51957 17.8947 8.26522 18 8 18H4C3.44772 18 3 17.5523 3 17C3 16.4477 3.44772 16 4 16H7.58579L11.5855 12.0003L7.586 8.00366Z"
|
||||
fill="currentcolor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as invariant from 'invariant';
|
||||
import { createAutoField } from 'uniforms';
|
||||
import { PreviewImageField } from '../../panelWebView/components/Fields/PreviewImageField';
|
||||
export { AutoFieldProps } from 'uniforms';
|
||||
|
||||
import BoolField from './BoolField';
|
||||
@@ -12,12 +11,9 @@ import RadioField from './RadioField';
|
||||
import SelectField from './SelectField';
|
||||
import TextField from './TextField';
|
||||
|
||||
const AutoField = createAutoField(props => {
|
||||
|
||||
const AutoField = createAutoField((props) => {
|
||||
if (props.allowedValues) {
|
||||
return props.checkboxes && props.fieldType !== Array
|
||||
? RadioField
|
||||
: SelectField;
|
||||
return props.checkboxes && props.fieldType !== Array ? RadioField : SelectField;
|
||||
}
|
||||
|
||||
switch (props.fieldType) {
|
||||
|
||||
@@ -23,7 +23,7 @@ export default function AutoFields({
|
||||
element,
|
||||
props,
|
||||
(fields ?? schema.getSubfields())
|
||||
.filter(field => !omitFields.includes(field))
|
||||
.map(field => createElement(autoField, { key: field, name: field })),
|
||||
.filter((field) => !omitFields.includes(field))
|
||||
.map((field) => createElement(autoField, { key: field, name: field }))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ import { AutoForm } from 'uniforms';
|
||||
|
||||
import ValidatedQuickForm from './ValidatedQuickForm';
|
||||
|
||||
function Auto(parent: any) {
|
||||
class _ extends AutoForm.Auto(parent) {
|
||||
function Auto(parent: unknown) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
class _ extends AutoForm.Auto(parent as any) {
|
||||
static Auto = Auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BaseForm } from 'uniforms';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function Unstyled(parent: any) {
|
||||
class _ extends parent {
|
||||
static Unstyled = Unstyled;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.field__toggle input {
|
||||
.field__toggle input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
@@ -18,22 +18,25 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--frontmatter-toggle-secondaryBackground, var(--vscode-button-secondaryBackground));
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
background-color: var(
|
||||
--frontmatter-toggle-secondaryBackground,
|
||||
var(--vscode-button-secondaryBackground)
|
||||
);
|
||||
-webkit-transition: 0.4s;
|
||||
transition: 0.4s;
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.field__toggle__slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
content: '';
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
-webkit-transition: 0.4s;
|
||||
transition: 0.4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@@ -49,4 +52,4 @@ input:checked + .field__toggle__slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ function Bool({
|
||||
return (
|
||||
<div {...filterDOMProps(props)}>
|
||||
<LabelField label={label} id={id} required={props.required} />
|
||||
|
||||
|
||||
<label className="field__toggle">
|
||||
<input
|
||||
checked={value || false}
|
||||
|
||||
@@ -36,7 +36,7 @@ function Date({
|
||||
max={dateFormat(max)}
|
||||
min={dateFormat(min)}
|
||||
name={name}
|
||||
onChange={event => {
|
||||
onChange={(event) => {
|
||||
const date = new DateConstructor(event.target.valueAsNumber);
|
||||
if (date.getFullYear() < 10000) {
|
||||
onChange(date);
|
||||
|
||||
@@ -4,16 +4,14 @@ import { Override, connectField, filterDOMProps } from 'uniforms';
|
||||
|
||||
export type ErrorFieldProps = Override<
|
||||
Omit<HTMLProps<HTMLDivElement>, 'onChange'>,
|
||||
{ error?: any; errorMessage?: string }
|
||||
{ error?: unknown; errorMessage?: string }
|
||||
>;
|
||||
|
||||
function Error({ children, error, errorMessage, ...props }: ErrorFieldProps) {
|
||||
return !error ? null : (
|
||||
<div {...filterDOMProps(props)}>{children || errorMessage}</div>
|
||||
);
|
||||
return !error ? null : <div {...filterDOMProps(props)}>{children || errorMessage}</div>;
|
||||
}
|
||||
|
||||
export default connectField<ErrorFieldProps>(Error, {
|
||||
initialValue: false,
|
||||
kind: 'leaf',
|
||||
kind: 'leaf'
|
||||
});
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
|
||||
.autoform-error {
|
||||
background-color: var(--frontmatter-error-background, var(--vscode-inputValidation-errorBackground));
|
||||
background-color: var(
|
||||
--frontmatter-error-background,
|
||||
var(--vscode-inputValidation-errorBackground)
|
||||
);
|
||||
border: 1px solid var(--frontmatter-error-border, var(--vscode-inputValidation-errorBorder));
|
||||
border-radius: 2px;
|
||||
margin: 20px 0px;
|
||||
@@ -15,4 +16,4 @@
|
||||
li {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export type ErrorsFieldProps = HTMLProps<HTMLDivElement>;
|
||||
export default function ErrorsField(props: ErrorsFieldProps) {
|
||||
const { error, schema } = useForm();
|
||||
return !error && !props.children ? null : (
|
||||
<div className='autoform-error'>
|
||||
<div className="autoform-error">
|
||||
<div {...filterDOMProps(props)}>
|
||||
{props.children}
|
||||
|
||||
|
||||
@@ -2,18 +2,20 @@ import * as React from 'react';
|
||||
import { HTMLProps, Ref, useEffect } from 'react';
|
||||
import { Override, filterDOMProps, useField } from 'uniforms';
|
||||
|
||||
type ValueType = string | number | readonly string[] | undefined;
|
||||
export type HiddenFieldProps = Override<
|
||||
HTMLProps<HTMLInputElement>,
|
||||
{
|
||||
inputRef?: Ref<HTMLInputElement>;
|
||||
name: string;
|
||||
noDOM?: boolean;
|
||||
value?: any;
|
||||
value?: ValueType;
|
||||
}
|
||||
>;
|
||||
|
||||
export default function HiddenField({ value, ...rawProps }: HiddenFieldProps) {
|
||||
const props = useField(rawProps.name, rawProps, { initialValue: false })[0];
|
||||
const defaultValue = (props.value as ValueType) ?? '';
|
||||
|
||||
useEffect(() => {
|
||||
if (value !== undefined && value !== props.value) {
|
||||
@@ -28,7 +30,7 @@ export default function HiddenField({ value, ...rawProps }: HiddenFieldProps) {
|
||||
readOnly={props.readOnly}
|
||||
ref={props.inputRef}
|
||||
type="hidden"
|
||||
value={value ?? props.value ?? ''}
|
||||
value={value ?? defaultValue}
|
||||
{...filterDOMProps(props)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
.autoform__label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
@@ -11,4 +9,4 @@
|
||||
color: var(--vscode-inputValidation-errorBorder);
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,19 @@ export interface ILabelFieldProps {
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
export const LabelField: React.FunctionComponent<ILabelFieldProps> = ({ label, id, required }: React.PropsWithChildren<ILabelFieldProps>) => {
|
||||
return (
|
||||
label ? (
|
||||
<label className="autoform__label" htmlFor={id}>
|
||||
{label}
|
||||
{required && <span title='Required field' className='autoform__label__required'>*</span>}
|
||||
</label>
|
||||
) : null
|
||||
);
|
||||
};
|
||||
export const LabelField: React.FunctionComponent<ILabelFieldProps> = ({
|
||||
label,
|
||||
id,
|
||||
required
|
||||
}: React.PropsWithChildren<ILabelFieldProps>) => {
|
||||
return label ? (
|
||||
<label className="autoform__label" htmlFor={id}>
|
||||
{label}
|
||||
{required && (
|
||||
<span title="Required field" className="autoform__label__required">
|
||||
*
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
) : null;
|
||||
};
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
|
||||
|
||||
.autoform__list_add_field {
|
||||
display: flex;
|
||||
padding: 5px;
|
||||
border: 1px dashed var(--frontmatter-field-border, var(--vscode-editor-foreground));
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
margin-top: .5rem;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--frontmatter-field-borderActive, var(--vscode-button-background));
|
||||
@@ -18,4 +16,4 @@
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +1,42 @@
|
||||
import { PlusIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import {
|
||||
HTMLFieldProps,
|
||||
connectField,
|
||||
filterDOMProps,
|
||||
joinName,
|
||||
useField,
|
||||
} from 'uniforms';
|
||||
import { HTMLFieldProps, connectField, filterDOMProps, joinName, useField } from 'uniforms';
|
||||
import './ListAddField.css';
|
||||
|
||||
type ParentFieldType = { initialCount?: number; maxCount?: number };
|
||||
type ValueType = string | readonly string[] | undefined;
|
||||
|
||||
export type ListAddFieldProps = HTMLFieldProps<
|
||||
unknown,
|
||||
ValueType,
|
||||
HTMLSpanElement,
|
||||
{ initialCount?: number }
|
||||
>;
|
||||
|
||||
function ListAdd({
|
||||
disabled,
|
||||
initialCount,
|
||||
name,
|
||||
readOnly,
|
||||
value,
|
||||
...props
|
||||
}: ListAddFieldProps) {
|
||||
function ListAdd({ disabled, initialCount, name, readOnly, value, ...props }: ListAddFieldProps) {
|
||||
const nameParts = joinName(null, name);
|
||||
const parentName = joinName(nameParts.slice(0, -1));
|
||||
const parent = useField<
|
||||
{ initialCount?: number; maxCount?: number },
|
||||
unknown[]
|
||||
>(parentName, { initialCount }, { absoluteName: true })[0];
|
||||
const parent = {
|
||||
maxCount: 0,
|
||||
value: [] as ValueType[],
|
||||
...useField<ParentFieldType, ValueType[]>(
|
||||
parentName,
|
||||
{ initialCount },
|
||||
{ absoluteName: true }
|
||||
)[0]
|
||||
};
|
||||
|
||||
const limitNotReached =
|
||||
!disabled && !(parent.maxCount! <= parent.value!.length);
|
||||
const limitNotReached = !disabled && !(parent.maxCount <= parent.value.length);
|
||||
|
||||
function onAction(event: React.KeyboardEvent | React.MouseEvent) {
|
||||
if (
|
||||
limitNotReached &&
|
||||
!readOnly &&
|
||||
(!('key' in event) || event.key === 'Enter')
|
||||
) {
|
||||
parent.onChange(parent.value!.concat([Object.assign({}, value)]));
|
||||
if (limitNotReached && !readOnly && (!('key' in event) || event.key === 'Enter')) {
|
||||
parent.onChange(parent.value.concat([value]));
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
className='autoform__list_add_field'
|
||||
className="autoform__list_add_field"
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
{...filterDOMProps(props as any)}
|
||||
onClick={onAction}
|
||||
onKeyDown={onAction}
|
||||
@@ -59,5 +50,5 @@ function ListAdd({
|
||||
|
||||
export default connectField<ListAddFieldProps>(ListAdd, {
|
||||
initialValue: false,
|
||||
kind: 'leaf',
|
||||
kind: 'leaf'
|
||||
});
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
|
||||
|
||||
.autoform__list_del_field {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
margin-top: .5rem;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--vscode-button-background);
|
||||
@@ -16,12 +14,12 @@
|
||||
height: 1px;
|
||||
background: var(--frontmatter-list-border, var(--vscode-editor-foreground));
|
||||
width: 100%;
|
||||
margin-right: .5rem;
|
||||
margin-top: .5rem;
|
||||
margin-right: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 1.25rem;
|
||||
width: 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import { TrashIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import {
|
||||
HTMLFieldProps,
|
||||
connectField,
|
||||
filterDOMProps,
|
||||
joinName,
|
||||
useField,
|
||||
} from 'uniforms';
|
||||
import { HTMLFieldProps, connectField, filterDOMProps, joinName, useField } from 'uniforms';
|
||||
import './ListDelField.css';
|
||||
|
||||
export type ListDelFieldProps = HTMLFieldProps<unknown, HTMLSpanElement>;
|
||||
@@ -15,26 +9,19 @@ function ListDel({ disabled, name, readOnly, ...props }: ListDelFieldProps) {
|
||||
const nameParts = joinName(null, name);
|
||||
const nameIndex = +nameParts[nameParts.length - 1];
|
||||
const parentName = joinName(nameParts.slice(0, -1));
|
||||
const parent = useField<{ minCount?: number }, unknown[]>(
|
||||
parentName,
|
||||
{},
|
||||
{ absoluteName: true },
|
||||
)[0];
|
||||
const parent = {
|
||||
minCount: 0,
|
||||
value: [],
|
||||
...useField<{ minCount?: number }, unknown[]>(parentName, {}, { absoluteName: true })[0]
|
||||
};
|
||||
|
||||
const limitNotReached =
|
||||
!disabled && !(parent.minCount! >= parent.value!.length);
|
||||
const limitNotReached = !disabled && !(parent.minCount >= parent.value.length);
|
||||
|
||||
function onAction(
|
||||
event:
|
||||
| React.KeyboardEvent<HTMLSpanElement>
|
||||
| React.MouseEvent<HTMLSpanElement, MouseEvent>,
|
||||
event: React.KeyboardEvent<HTMLSpanElement> | React.MouseEvent<HTMLSpanElement, MouseEvent>
|
||||
) {
|
||||
if (
|
||||
limitNotReached &&
|
||||
!readOnly &&
|
||||
(!('key' in event) || event.key === 'Enter')
|
||||
) {
|
||||
const value = parent.value!.slice();
|
||||
if (limitNotReached && !readOnly && (!('key' in event) || event.key === 'Enter')) {
|
||||
const value = parent.value.slice();
|
||||
value.splice(nameIndex, 1);
|
||||
parent.onChange(value);
|
||||
}
|
||||
@@ -42,22 +29,20 @@ function ListDel({ disabled, name, readOnly, ...props }: ListDelFieldProps) {
|
||||
|
||||
return (
|
||||
<span
|
||||
className='autoform__list_del_field'
|
||||
className="autoform__list_del_field"
|
||||
{...filterDOMProps(props)}
|
||||
onClick={onAction}
|
||||
onKeyDown={onAction}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className='line'></div>
|
||||
<div className="line"></div>
|
||||
<TrashIcon />
|
||||
</span>
|
||||
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default connectField<ListDelFieldProps>(ListDel, {
|
||||
initialValue: false,
|
||||
kind: 'leaf',
|
||||
kind: 'leaf'
|
||||
});
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
|
||||
.autoform__list_field {
|
||||
margin-bottom: 1rem;
|
||||
margin-top: 1rem;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--frontmatter-list-border, rgba(255, 255, 255, 0.2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,15 +27,16 @@ function List({
|
||||
<LabelField label={label} id={props.id} required={props.required} />
|
||||
|
||||
{value?.map((item, itemIndex) =>
|
||||
Children.map(children, (child, childIndex) =>
|
||||
Children.map(children as React.ReactElement[], (child: React.ReactElement, childIndex) =>
|
||||
isValidElement(child)
|
||||
? cloneElement(child, {
|
||||
key: `${itemIndex}-${childIndex}`,
|
||||
name: (child.props.name || "").replace('$', '' + itemIndex),
|
||||
...itemProps,
|
||||
// name: '',
|
||||
// name: (child.props.name || '').replace('$', '' + itemIndex),
|
||||
...itemProps
|
||||
})
|
||||
: child,
|
||||
),
|
||||
: child
|
||||
)
|
||||
)}
|
||||
|
||||
<ListAddField initialCount={initialCount} name="$" />
|
||||
|
||||
@@ -7,9 +7,7 @@ import ListDelField from './ListDelField';
|
||||
|
||||
export type ListItemFieldProps = { children?: ReactNode; value?: unknown };
|
||||
|
||||
function ListItem({
|
||||
children = <AutoField label={null} name="" />,
|
||||
}: ListItemFieldProps) {
|
||||
function ListItem({ children = <AutoField label={null} name="" /> }: ListItemFieldProps) {
|
||||
return (
|
||||
<div>
|
||||
<ListDelField name="" />
|
||||
@@ -19,5 +17,5 @@ function ListItem({
|
||||
}
|
||||
|
||||
export default connectField<ListItemFieldProps>(ListItem, {
|
||||
initialValue: false,
|
||||
initialValue: false
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ function LongText({
|
||||
disabled={disabled}
|
||||
id={id}
|
||||
name={name}
|
||||
onChange={event => onChange(event.target.value)}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
ref={inputRef}
|
||||
|
||||
@@ -4,27 +4,14 @@ import { HTMLFieldProps, connectField, filterDOMProps } from 'uniforms';
|
||||
import AutoField from './AutoField';
|
||||
import { LabelField } from './LabelField';
|
||||
|
||||
export type NestFieldProps = HTMLFieldProps<
|
||||
object,
|
||||
HTMLDivElement,
|
||||
{ itemProps?: object }
|
||||
>;
|
||||
export type NestFieldProps = HTMLFieldProps<object, HTMLDivElement, { itemProps?: object }>;
|
||||
|
||||
function Nest({
|
||||
children,
|
||||
fields,
|
||||
itemProps,
|
||||
label,
|
||||
...props
|
||||
}: NestFieldProps) {
|
||||
function Nest({ children, fields, itemProps, label, ...props }: NestFieldProps) {
|
||||
return (
|
||||
<div {...filterDOMProps(props)}>
|
||||
<LabelField label={label} id={props.id} required={props.required} />
|
||||
|
||||
{children ||
|
||||
fields.map(field => (
|
||||
<AutoField key={field} name={field} {...itemProps} />
|
||||
))}
|
||||
{children || fields.map((field) => <AutoField key={field} name={field} {...itemProps} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ function Num({
|
||||
max={max}
|
||||
min={min}
|
||||
name={name}
|
||||
onChange={event => {
|
||||
onChange={(event) => {
|
||||
const parse = decimal ? parseFloat : parseInt;
|
||||
const value = parse(event.target.value);
|
||||
onChange(isNaN(value) ? undefined : value);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable class-methods-use-this */
|
||||
import { QuickForm } from 'uniforms';
|
||||
|
||||
import AutoField from './AutoField';
|
||||
@@ -5,6 +6,7 @@ import BaseForm from './BaseForm';
|
||||
import ErrorsField from './ErrorsField';
|
||||
import SubmitField from './SubmitField';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function Quick(parent: any) {
|
||||
class _ extends QuickForm.Quick(parent) {
|
||||
static Quick = Quick;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { LabelField } from './LabelField';
|
||||
|
||||
const base64: typeof btoa =
|
||||
typeof btoa === 'undefined'
|
||||
? /* istanbul ignore next */ x => Buffer.from(x).toString('base64')
|
||||
? /* istanbul ignore next */ (x) => Buffer.from(x).toString('base64')
|
||||
: btoa;
|
||||
const escape = (x: string) => base64(encodeURIComponent(x)).replace(/=+$/, '');
|
||||
|
||||
@@ -35,7 +35,7 @@ function Radio({
|
||||
<div {...omit(filterDOMProps(props), ['checkboxes'])}>
|
||||
<LabelField label={label} id={id} required={props.required} />
|
||||
|
||||
{allowedValues?.map(item => (
|
||||
{allowedValues?.map((item) => (
|
||||
<div key={item}>
|
||||
<input
|
||||
checked={item === value}
|
||||
@@ -50,9 +50,7 @@ function Radio({
|
||||
type="radio"
|
||||
/>
|
||||
|
||||
<label htmlFor={`${id}-${escape(item)}`}>
|
||||
{transform ? transform(item) : item}
|
||||
</label>
|
||||
<label htmlFor={`${id}-${escape(item)}`}>{transform ? transform(item) : item}</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
.autoform__select_field {
|
||||
color: var(--frontmatter-select-foreground, var(--vscode-editor-foreground));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import './SelectField.css';
|
||||
|
||||
const base64: typeof btoa =
|
||||
typeof btoa === 'undefined'
|
||||
? /* istanbul ignore next */ x => Buffer.from(x).toString('base64')
|
||||
? /* istanbul ignore next */ (x) => Buffer.from(x).toString('base64')
|
||||
: btoa;
|
||||
const escape = (x: string) => base64(encodeURIComponent(x)).replace(/=+$/, '');
|
||||
|
||||
@@ -24,7 +24,7 @@ export type SelectFieldProps = HTMLFieldProps<
|
||||
>;
|
||||
|
||||
function Select({
|
||||
allowedValues,
|
||||
allowedValues = [],
|
||||
checkboxes,
|
||||
disabled,
|
||||
fieldType,
|
||||
@@ -38,21 +38,19 @@ function Select({
|
||||
required,
|
||||
disableItem,
|
||||
transform,
|
||||
value,
|
||||
value = [],
|
||||
...props
|
||||
}: SelectFieldProps) {
|
||||
const multiple = fieldType === Array;
|
||||
return (
|
||||
<div className='autoform__select_field' {...filterDOMProps(props)}>
|
||||
<div className="autoform__select_field" {...filterDOMProps(props)}>
|
||||
<LabelField label={label} id={id} required={required} />
|
||||
|
||||
|
||||
{checkboxes ? (
|
||||
allowedValues!.map(item => (
|
||||
allowedValues.map((item) => (
|
||||
<div key={item}>
|
||||
<input
|
||||
checked={
|
||||
fieldType === Array ? value!.includes(item) : value === item
|
||||
}
|
||||
checked={fieldType === Array ? value.includes(item) : value === item}
|
||||
disabled={disableItem?.(item) ?? disabled}
|
||||
id={`${id}-${escape(item)}`}
|
||||
name={name}
|
||||
@@ -64,9 +62,7 @@ function Select({
|
||||
type="checkbox"
|
||||
/>
|
||||
|
||||
<label htmlFor={`${id}-${escape(item)}`}>
|
||||
{transform ? transform(item) : item}
|
||||
</label>
|
||||
<label htmlFor={`${id}-${escape(item)}`}>{transform ? transform(item) : item}</label>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
@@ -75,7 +71,7 @@ function Select({
|
||||
id={id}
|
||||
multiple={multiple}
|
||||
name={name}
|
||||
onChange={event => {
|
||||
onChange={(event) => {
|
||||
if (!readOnly) {
|
||||
const item = event.target.value;
|
||||
if (multiple) {
|
||||
@@ -88,7 +84,7 @@ function Select({
|
||||
}}
|
||||
ref={inputRef}
|
||||
value={value ?? ''}
|
||||
style={{ width: "100%", padding: "0.5rem" }}
|
||||
style={{ width: '100%', padding: '0.5rem' }}
|
||||
>
|
||||
{(!!placeholder || !required || value === undefined) && !multiple && (
|
||||
<option value="" disabled={required} hidden={required}>
|
||||
@@ -96,7 +92,7 @@ function Select({
|
||||
</option>
|
||||
)}
|
||||
|
||||
{allowedValues?.map(value => (
|
||||
{allowedValues?.map((value) => (
|
||||
<option disabled={disableItem?.(value)} key={value} value={value}>
|
||||
{transform ? transform(value) : value}
|
||||
</option>
|
||||
|
||||
@@ -23,7 +23,6 @@ function Text({
|
||||
value,
|
||||
...props
|
||||
}: TextFieldProps) {
|
||||
|
||||
return (
|
||||
<div {...filterDOMProps(props)}>
|
||||
<LabelField label={label} id={id} required={props.required} />
|
||||
@@ -33,7 +32,7 @@ function Text({
|
||||
disabled={disabled}
|
||||
id={id}
|
||||
name={name}
|
||||
onChange={event => onChange(event.target.value)}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
ref={inputRef}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ValidatedForm } from 'uniforms';
|
||||
|
||||
import BaseForm from './BaseForm';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function Validated(parent: any) {
|
||||
class _ extends ValidatedForm.Validated(parent) {
|
||||
static Validated = Validated;
|
||||
|
||||
@@ -3,46 +3,46 @@ import { ContentType } from './../models/PanelSettings';
|
||||
export const DEFAULT_CONTENT_TYPE_NAME = 'default';
|
||||
|
||||
export const DEFAULT_CONTENT_TYPE: ContentType = {
|
||||
"name": "default",
|
||||
"pageBundle": false,
|
||||
"previewPath": null,
|
||||
"fields": [
|
||||
name: 'default',
|
||||
pageBundle: false,
|
||||
previewPath: null,
|
||||
fields: [
|
||||
{
|
||||
"title": "Title",
|
||||
"name": "title",
|
||||
"type": "string"
|
||||
title: 'Title',
|
||||
name: 'title',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
"title": "Description",
|
||||
"name": "description",
|
||||
"type": "string"
|
||||
title: 'Description',
|
||||
name: 'description',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
"title": "Publishing date",
|
||||
"name": "date",
|
||||
"type": "datetime",
|
||||
"default": "{{now}}",
|
||||
"isPublishDate": true
|
||||
title: 'Publishing date',
|
||||
name: 'date',
|
||||
type: 'datetime',
|
||||
default: '{{now}}',
|
||||
isPublishDate: true
|
||||
},
|
||||
{
|
||||
"title": "Content preview",
|
||||
"name": "preview",
|
||||
"type": "image"
|
||||
title: 'Content preview',
|
||||
name: 'preview',
|
||||
type: 'image'
|
||||
},
|
||||
{
|
||||
"title": "Is in draft",
|
||||
"name": "draft",
|
||||
"type": "draft"
|
||||
title: 'Is in draft',
|
||||
name: 'draft',
|
||||
type: 'draft'
|
||||
},
|
||||
{
|
||||
"title": "Tags",
|
||||
"name": "tags",
|
||||
"type": "tags"
|
||||
title: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'tags'
|
||||
},
|
||||
{
|
||||
"title": "Categories",
|
||||
"name": "categories",
|
||||
"type": "categories"
|
||||
title: 'Categories',
|
||||
name: 'categories',
|
||||
type: 'categories'
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
3
src/constants/DefaultFieldValues.ts
Normal file
3
src/constants/DefaultFieldValues.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const DefaultFieldValues = {
|
||||
faultyCustomPlaceholder: '<failed to process>'
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
export const DefaultFields = {
|
||||
PublishingDate: `date`,
|
||||
LastModified: `lastmod`,
|
||||
Description: `description`,
|
||||
Title: `title`,
|
||||
Slug: `slug`
|
||||
};
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
|
||||
|
||||
export const DEFAULT_FILE_TYPES = [".md", ".markdown", ".mdx"];
|
||||
export const DEFAULT_FILE_TYPES = ['.md', '.markdown', '.mdx'];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const extensionName = "frontMatter";
|
||||
const extensionName = 'frontMatter';
|
||||
|
||||
export const EXTENSION_ID = 'eliostruyf.vscode-front-matter';
|
||||
export const EXTENSION_BETA_ID = 'eliostruyf.vscode-front-matter-beta';
|
||||
@@ -8,49 +8,71 @@ export const getCommandName = (command: string) => {
|
||||
};
|
||||
|
||||
export const COMMAND_NAME = {
|
||||
init: getCommandName("init"),
|
||||
insertTags: getCommandName("insertTags"),
|
||||
insertCategories: getCommandName("insertCategories"),
|
||||
createTag: getCommandName("createTag"),
|
||||
createCategory: getCommandName("createCategory"),
|
||||
exportTaxonomy: getCommandName("exportTaxonomy"),
|
||||
remap: getCommandName("remap"),
|
||||
setLastModifiedDate: getCommandName("setLastModifiedDate"),
|
||||
generateSlug: getCommandName("generateSlug"),
|
||||
createFromTemplate: getCommandName("createFromTemplate"),
|
||||
toggleDraft: getCommandName("toggleDraft"),
|
||||
registerFolder: getCommandName("registerFolder"),
|
||||
unregisterFolder: getCommandName("unregisterFolder"),
|
||||
createContent: getCommandName("createContent"),
|
||||
createByContentType: getCommandName("createByContentType"),
|
||||
createByTemplate: getCommandName("createByTemplate"),
|
||||
createTemplate: getCommandName("createTemplate"),
|
||||
collapseSections: getCommandName("collapseSections"),
|
||||
preview: getCommandName("preview"),
|
||||
dashboard: getCommandName("dashboard"),
|
||||
dashboardMedia: getCommandName("dashboard.media"),
|
||||
dashboardSnippets: getCommandName("dashboard.snippets"),
|
||||
dashboardData: getCommandName("dashboard.data"),
|
||||
dashboardClose: getCommandName("dashboard.close"),
|
||||
promote: getCommandName("promoteSettings"),
|
||||
createFolder: getCommandName("createFolder"),
|
||||
diagnostics: getCommandName("diagnostics"),
|
||||
modeSwitch: getCommandName("mode.switch"),
|
||||
init: getCommandName('init'),
|
||||
insertTags: getCommandName('insertTags'),
|
||||
insertCategories: getCommandName('insertCategories'),
|
||||
createTag: getCommandName('createTag'),
|
||||
createCategory: getCommandName('createCategory'),
|
||||
exportTaxonomy: getCommandName('exportTaxonomy'),
|
||||
remap: getCommandName('remap'),
|
||||
setLastModifiedDate: getCommandName('setLastModifiedDate'),
|
||||
generateSlug: getCommandName('generateSlug'),
|
||||
createFromTemplate: getCommandName('createFromTemplate'),
|
||||
toggleDraft: getCommandName('toggleDraft'),
|
||||
registerFolder: getCommandName('registerFolder'),
|
||||
unregisterFolder: getCommandName('unregisterFolder'),
|
||||
createContent: getCommandName('createContent'),
|
||||
createByContentType: getCommandName('createByContentType'),
|
||||
createByTemplate: getCommandName('createByTemplate'),
|
||||
createTemplate: getCommandName('createTemplate'),
|
||||
initTemplate: getCommandName('initTemplate'),
|
||||
collapseSections: getCommandName('collapseSections'),
|
||||
preview: getCommandName('preview'),
|
||||
dashboard: getCommandName('dashboard'),
|
||||
dashboardMedia: getCommandName('dashboard.media'),
|
||||
dashboardSnippets: getCommandName('dashboard.snippets'),
|
||||
dashboardData: getCommandName('dashboard.data'),
|
||||
dashboardTaxonomy: getCommandName('dashboard.taxonomy'),
|
||||
dashboardClose: getCommandName('dashboard.close'),
|
||||
promote: getCommandName('promoteSettings'),
|
||||
createFolder: getCommandName('createFolder'),
|
||||
diagnostics: getCommandName('diagnostics'),
|
||||
modeSwitch: getCommandName('mode.switch'),
|
||||
|
||||
showOutputChannel: getCommandName('showOutputChannel'),
|
||||
|
||||
// Insert dashboards
|
||||
insertImage: getCommandName("insertImage"),
|
||||
insertSnippet: getCommandName("insertSnippet"),
|
||||
insertMedia: getCommandName('insertMedia'),
|
||||
insertSnippet: getCommandName('insertSnippet'),
|
||||
|
||||
// WYSIWYG
|
||||
bold: getCommandName("markup.bold"),
|
||||
italic: getCommandName("markup.italic"),
|
||||
strikethrough: getCommandName("markup.strikethrough"),
|
||||
code: getCommandName("markup.code"),
|
||||
codeblock: getCommandName("markup.codeblock"),
|
||||
heading: getCommandName("markup.heading"),
|
||||
blockquote: getCommandName("markup.blockquote"),
|
||||
unorderedlist: getCommandName("markup.unorderedlist"),
|
||||
orderedlist: getCommandName("markup.orderedlist"),
|
||||
taskList: getCommandName("markup.tasklist"),
|
||||
options: getCommandName("markup.options"),
|
||||
};
|
||||
bold: getCommandName('markup.bold'),
|
||||
italic: getCommandName('markup.italic'),
|
||||
strikethrough: getCommandName('markup.strikethrough'),
|
||||
code: getCommandName('markup.code'),
|
||||
codeblock: getCommandName('markup.codeblock'),
|
||||
heading: getCommandName('markup.heading'),
|
||||
blockquote: getCommandName('markup.blockquote'),
|
||||
unorderedlist: getCommandName('markup.unorderedlist'),
|
||||
orderedlist: getCommandName('markup.orderedlist'),
|
||||
taskList: getCommandName('markup.tasklist'),
|
||||
hyperlink: getCommandName('markup.hyperlink'),
|
||||
options: getCommandName('markup.options'),
|
||||
|
||||
// Content types
|
||||
generateContentType: getCommandName('contenttype.generate'),
|
||||
addMissingFields: getCommandName('contenttype.addMissingFields'),
|
||||
setContentType: getCommandName('contenttype.setContentType'),
|
||||
|
||||
// Git
|
||||
gitSync: getCommandName('git.sync'),
|
||||
|
||||
// Authenticate
|
||||
authenticate: getCommandName('authenticate'),
|
||||
|
||||
// Config
|
||||
reloadConfig: getCommandName('config.reload'),
|
||||
|
||||
// Cache
|
||||
clearCache: getCommandName('cache.clear')
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
export const ExtensionState = {
|
||||
PagesView: `frontMatter:Pages:ViewType`,
|
||||
SelectedFolder: `frontMatter:SelectedFolder`,
|
||||
@@ -8,20 +7,24 @@ export const ExtensionState = {
|
||||
|
||||
Dashboard: {
|
||||
Contents: {
|
||||
Sorting: `frontMatter:Dashboard:Contents:Sorting`,
|
||||
Sorting: `frontMatter:Dashboard:Contents:Sorting`
|
||||
},
|
||||
Media: {
|
||||
Sorting: `frontMatter:Dashboard:Media:Sorting`,
|
||||
Sorting: `frontMatter:Dashboard:Media:Sorting`
|
||||
},
|
||||
Pages: {
|
||||
Cache: `frontMatter:Dashboard:Pages:Cache`,
|
||||
Index: `frontMatter:Dashboard:Pages:Index`,
|
||||
Index: `frontMatter:Dashboard:Pages:Index`
|
||||
}
|
||||
},
|
||||
|
||||
Settings: {
|
||||
Extends: `frontMatter:Settings:Extends`
|
||||
},
|
||||
|
||||
Updates: {
|
||||
v7_0_0: {
|
||||
dateFields: `frontMatter:Updates:v7.0.0:dateFields`
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
|
||||
|
||||
export const FEATURE_FLAG = {
|
||||
panel: {
|
||||
globalSettings: "panel.globalSettings",
|
||||
seo: "panel.seo",
|
||||
actions: "panel.actions",
|
||||
metadata: "panel.metadata",
|
||||
recentlyModified: "panel.recentlyModified",
|
||||
otherActions: "panel.otherActions",
|
||||
globalSettings: 'panel.globalSettings',
|
||||
seo: 'panel.seo',
|
||||
actions: 'panel.actions',
|
||||
metadata: 'panel.metadata',
|
||||
recentlyModified: 'panel.recentlyModified',
|
||||
otherActions: 'panel.otherActions',
|
||||
contentType: 'panel.contentType'
|
||||
},
|
||||
dashboard: {
|
||||
snippets: {
|
||||
view: "dashboard.snippets.view",
|
||||
manage: "dashboard.snippets.manage",
|
||||
view: 'dashboard.snippets.view',
|
||||
manage: 'dashboard.snippets.manage'
|
||||
},
|
||||
data: {
|
||||
view: "dashboard.data.view",
|
||||
view: 'dashboard.data.view'
|
||||
},
|
||||
taxonomy: {
|
||||
view: 'dashboard.taxonomy.view'
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,33 +1,102 @@
|
||||
export const FrameworkDetectors = [
|
||||
{
|
||||
"framework": {"name": "gatsby", "dist": "public", "static": "static", "build": "gatsby build"},
|
||||
"requiredFiles": ["gatsby-config.js"],
|
||||
"requiredDependencies": ["gatsby"],
|
||||
"commands": {
|
||||
"start": "npx gatsby develop"
|
||||
framework: {
|
||||
name: 'gatsby',
|
||||
dist: 'public',
|
||||
static: 'static',
|
||||
build: 'gatsby build'
|
||||
},
|
||||
requiredFiles: ['gatsby-config.js'],
|
||||
requiredDependencies: ['gatsby'],
|
||||
commands: {
|
||||
start: 'npx gatsby develop'
|
||||
}
|
||||
},
|
||||
{
|
||||
"framework": {"name": "hugo", "dist": "public", "static": "static", "build": "hugo"},
|
||||
"requiredFiles": ["config.toml", "config.yaml", "config.yml"],
|
||||
"commands": {
|
||||
"start": "hugo server -D"
|
||||
framework: {
|
||||
name: 'hugo',
|
||||
dist: 'public',
|
||||
static: 'static',
|
||||
build: 'hugo'
|
||||
},
|
||||
requiredFiles: ['config.toml', 'config.yaml', 'config.yml'],
|
||||
commands: {
|
||||
start: 'hugo server -D'
|
||||
}
|
||||
},
|
||||
{
|
||||
"framework": {"name": "next", "dist": ".next", "static": "public", "build": "next build"},
|
||||
"requiredFiles": ["next.config.js"],
|
||||
"requiredDependencies": ["next"],
|
||||
"commands": {
|
||||
"start": "npx next dev"
|
||||
framework: {
|
||||
name: 'next',
|
||||
dist: '.next',
|
||||
static: 'public',
|
||||
build: 'next build'
|
||||
},
|
||||
requiredFiles: ['next.config.js'],
|
||||
requiredDependencies: ['next'],
|
||||
commands: {
|
||||
start: 'npx next dev'
|
||||
}
|
||||
},
|
||||
{
|
||||
"framework": {"name": "nuxt", "dist": "dist", "static": "static", "build": "nuxt"},
|
||||
"requiredFiles": ["nuxt.config.js"],
|
||||
"requiredDependencies": ["nuxt"],
|
||||
"commands": {
|
||||
"start": "npx nuxt"
|
||||
framework: {
|
||||
name: 'nuxt',
|
||||
dist: 'dist',
|
||||
static: 'static',
|
||||
build: 'nuxt'
|
||||
},
|
||||
requiredFiles: ['nuxt.config.js'],
|
||||
requiredDependencies: ['nuxt'],
|
||||
commands: {
|
||||
start: 'npx nuxt'
|
||||
}
|
||||
},
|
||||
{
|
||||
framework: {
|
||||
name: 'jekyll',
|
||||
dist: '_site',
|
||||
static: 'assets',
|
||||
build: 'bundle exec jekyll build'
|
||||
},
|
||||
requiredFiles: ['Gemfile'],
|
||||
requiredDependencies: ['jekyll'],
|
||||
commands: {
|
||||
start: 'bundle exec jekyll serve --livereload'
|
||||
}
|
||||
},
|
||||
{
|
||||
framework: {
|
||||
name: 'docusaurus',
|
||||
dist: 'build',
|
||||
static: 'static',
|
||||
build: 'npx docusaurus build'
|
||||
},
|
||||
requiredFiles: ['docusaurus.config.js'],
|
||||
requiredDependencies: ['@docusaurus/core'],
|
||||
commands: {
|
||||
start: 'npx docusaurus start'
|
||||
}
|
||||
},
|
||||
{
|
||||
framework: {
|
||||
name: '11ty',
|
||||
dist: '_site',
|
||||
build: 'npx @11ty/eleventy'
|
||||
},
|
||||
requiredDependencies: ['@11ty/eleventy'],
|
||||
commands: {
|
||||
start: 'npx @11ty/eleventy --serve'
|
||||
}
|
||||
},
|
||||
{
|
||||
framework: {
|
||||
name: 'hexo',
|
||||
dist: 'public',
|
||||
build: 'npx hexo-cli generate'
|
||||
},
|
||||
requiredFiles: ['_config.js'],
|
||||
requiredDependencies: ['hexo'],
|
||||
commands: {
|
||||
start: 'npx hexo-cli server'
|
||||
}
|
||||
}
|
||||
];
|
||||
];
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
|
||||
|
||||
export enum GeneralCommands{
|
||||
setMode = "setMode"
|
||||
};
|
||||
export const GeneralCommands = {
|
||||
toWebview: {
|
||||
setMode: 'setMode',
|
||||
gitSyncingStart: 'gitSyncingStart',
|
||||
gitSyncingEnd: 'gitSyncingEnd'
|
||||
},
|
||||
toVSCode: {
|
||||
openLink: 'openLink',
|
||||
gitSync: 'gitSync'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
export const GITHUB_LINK = "https://github.com/estruyf/vscode-front-matter";
|
||||
export const ISSUE_LINK = "https://github.com/estruyf/vscode-front-matter/issues";
|
||||
export const SPONSOR_LINK = "https://github.com/sponsors/estruyf";
|
||||
export const REVIEW_LINK = "https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter&ssr=false#review-details";
|
||||
export const GITHUB_LINK = 'https://github.com/estruyf/vscode-front-matter';
|
||||
export const ISSUE_LINK = 'https://github.com/estruyf/vscode-front-matter/issues';
|
||||
export const SPONSOR_LINK = 'https://github.com/sponsors/estruyf';
|
||||
export const REVIEW_LINK =
|
||||
'https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter&ssr=false#review-details';
|
||||
export const DOCUMENTATION_LINK = 'https://frontmatter.codes/docs';
|
||||
export const DOCUMENTATION_SETTINGS_LINK = 'https://frontmatter.codes/docs/settings';
|
||||
|
||||
export const SENTRY_LINK = "https://1ac45704bbe74264a7b4674bdc2abf48@o1022172.ingest.sentry.io/5988293";
|
||||
export const SENTRY_LINK =
|
||||
'https://1ac45704bbe74264a7b4674bdc2abf48@o1022172.ingest.sentry.io/5988293';
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
|
||||
export const LocalStore = {
|
||||
rootFolder: ".frontmatter",
|
||||
contentFolder: "content",
|
||||
templatesFolder: "templates",
|
||||
mediaDatabaseFile: "mediaDb.json"
|
||||
}
|
||||
rootFolder: '.frontmatter',
|
||||
contentFolder: 'content',
|
||||
templatesFolder: 'templates',
|
||||
mediaDatabaseFile: 'mediaDb.json'
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const HOME_PAGE_NAVIGATION_ID = "FrontMatter:RootFolder";
|
||||
export const HOME_PAGE_NAVIGATION_ID = 'FrontMatter:RootFolder';
|
||||
|
||||
3
src/constants/NotificationType.ts
Normal file
3
src/constants/NotificationType.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const NOTIFICATION_TYPE = {
|
||||
requiredFieldValidation: 'requiredFieldValidation'
|
||||
};
|
||||
6
src/constants/PreviewCommands.ts
Normal file
6
src/constants/PreviewCommands.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const PreviewCommands = {
|
||||
toVSCode: {
|
||||
open: `preview.open`
|
||||
},
|
||||
fromVSCode: {}
|
||||
};
|
||||
6
src/constants/StaticFolderPlaceholder.ts
Normal file
6
src/constants/StaticFolderPlaceholder.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const STATIC_FOLDER_PLACEHOLDER = {
|
||||
hexo: {
|
||||
postsFolder: 'source/_posts',
|
||||
placeholder: 'hexo:post_asset_folder'
|
||||
}
|
||||
};
|
||||
@@ -10,6 +10,7 @@ export const TelemetryEvent = {
|
||||
openMediaDashboard: 'openMediaDashboard',
|
||||
openDataDashboard: 'openDataDashboard',
|
||||
openSnippetsDashboard: 'openSnippetsDashboard',
|
||||
openTaxonomyDashboard: 'openTaxonomyDashboard',
|
||||
closeDashboard: 'closeDashboard',
|
||||
|
||||
// Other actions
|
||||
@@ -21,10 +22,17 @@ export const TelemetryEvent = {
|
||||
uploadMedia: 'uploadMedia',
|
||||
refreshMedia: 'refreshMedia',
|
||||
deleteMedia: 'deleteMedia',
|
||||
insertContentSnippet: 'insertContentSnippet',
|
||||
insertMediaToContent: 'insertMediaToContent',
|
||||
insertFileToContent: 'insertFileToContent',
|
||||
updateMediaMetadata: 'updateMediaMetadata',
|
||||
openExplorerView: 'openExplorerView',
|
||||
|
||||
// Content types
|
||||
generateContentType: 'generateContentType',
|
||||
addMissingFields: 'addMissingFields',
|
||||
setContentType: 'setContentType',
|
||||
|
||||
// Custom scripts
|
||||
runCustomScript: 'runCustomScript',
|
||||
runMediaScript: 'runMediaScript',
|
||||
@@ -35,4 +43,8 @@ export const TelemetryEvent = {
|
||||
webviewDataView: 'webviewDataView',
|
||||
webviewContentsView: 'webviewContentsView',
|
||||
webviewSnippetsView: 'webviewSnippetsView',
|
||||
};
|
||||
webviewTaxonomyDashboard: 'webviewTaxonomyDashboard',
|
||||
|
||||
// Git
|
||||
gitSync: 'gitSync'
|
||||
};
|
||||
|
||||
@@ -1,439 +1,438 @@
|
||||
/**
|
||||
* An inlined enum containing useful character codes (to be used with String.charCodeAt).
|
||||
* Please leave the const keyword such that it gets inlined when compiled to JavaScript!
|
||||
*
|
||||
*
|
||||
* SOURCE: https://github.com/microsoft/vscode/blob/32b031eeefc4fd27a21659d35070967bfe965bcc/src/vs/base/common/charCode.ts
|
||||
*/
|
||||
export const enum CharCode {
|
||||
Null = 0,
|
||||
/**
|
||||
* The `\b` character.
|
||||
*/
|
||||
Backspace = 8,
|
||||
/**
|
||||
* The `\t` character.
|
||||
*/
|
||||
Tab = 9,
|
||||
/**
|
||||
* The `\n` character.
|
||||
*/
|
||||
LineFeed = 10,
|
||||
/**
|
||||
* The `\r` character.
|
||||
*/
|
||||
CarriageReturn = 13,
|
||||
Space = 32,
|
||||
/**
|
||||
* The `!` character.
|
||||
*/
|
||||
ExclamationMark = 33,
|
||||
/**
|
||||
* The `"` character.
|
||||
*/
|
||||
DoubleQuote = 34,
|
||||
/**
|
||||
* The `#` character.
|
||||
*/
|
||||
Hash = 35,
|
||||
/**
|
||||
* The `$` character.
|
||||
*/
|
||||
DollarSign = 36,
|
||||
/**
|
||||
* The `%` character.
|
||||
*/
|
||||
PercentSign = 37,
|
||||
/**
|
||||
* The `&` character.
|
||||
*/
|
||||
Ampersand = 38,
|
||||
/**
|
||||
* The `'` character.
|
||||
*/
|
||||
SingleQuote = 39,
|
||||
/**
|
||||
* The `(` character.
|
||||
*/
|
||||
OpenParen = 40,
|
||||
/**
|
||||
* The `)` character.
|
||||
*/
|
||||
CloseParen = 41,
|
||||
/**
|
||||
* The `*` character.
|
||||
*/
|
||||
Asterisk = 42,
|
||||
/**
|
||||
* The `+` character.
|
||||
*/
|
||||
Plus = 43,
|
||||
/**
|
||||
* The `,` character.
|
||||
*/
|
||||
Comma = 44,
|
||||
/**
|
||||
* The `-` character.
|
||||
*/
|
||||
Dash = 45,
|
||||
/**
|
||||
* The `.` character.
|
||||
*/
|
||||
Period = 46,
|
||||
/**
|
||||
* The `/` character.
|
||||
*/
|
||||
Slash = 47,
|
||||
export const enum CharCode {
|
||||
Null = 0,
|
||||
/**
|
||||
* The `\b` character.
|
||||
*/
|
||||
Backspace = 8,
|
||||
/**
|
||||
* The `\t` character.
|
||||
*/
|
||||
Tab = 9,
|
||||
/**
|
||||
* The `\n` character.
|
||||
*/
|
||||
LineFeed = 10,
|
||||
/**
|
||||
* The `\r` character.
|
||||
*/
|
||||
CarriageReturn = 13,
|
||||
Space = 32,
|
||||
/**
|
||||
* The `!` character.
|
||||
*/
|
||||
ExclamationMark = 33,
|
||||
/**
|
||||
* The `"` character.
|
||||
*/
|
||||
DoubleQuote = 34,
|
||||
/**
|
||||
* The `#` character.
|
||||
*/
|
||||
Hash = 35,
|
||||
/**
|
||||
* The `$` character.
|
||||
*/
|
||||
DollarSign = 36,
|
||||
/**
|
||||
* The `%` character.
|
||||
*/
|
||||
PercentSign = 37,
|
||||
/**
|
||||
* The `&` character.
|
||||
*/
|
||||
Ampersand = 38,
|
||||
/**
|
||||
* The `'` character.
|
||||
*/
|
||||
SingleQuote = 39,
|
||||
/**
|
||||
* The `(` character.
|
||||
*/
|
||||
OpenParen = 40,
|
||||
/**
|
||||
* The `)` character.
|
||||
*/
|
||||
CloseParen = 41,
|
||||
/**
|
||||
* The `*` character.
|
||||
*/
|
||||
Asterisk = 42,
|
||||
/**
|
||||
* The `+` character.
|
||||
*/
|
||||
Plus = 43,
|
||||
/**
|
||||
* The `,` character.
|
||||
*/
|
||||
Comma = 44,
|
||||
/**
|
||||
* The `-` character.
|
||||
*/
|
||||
Dash = 45,
|
||||
/**
|
||||
* The `.` character.
|
||||
*/
|
||||
Period = 46,
|
||||
/**
|
||||
* The `/` character.
|
||||
*/
|
||||
Slash = 47,
|
||||
|
||||
Digit0 = 48,
|
||||
Digit1 = 49,
|
||||
Digit2 = 50,
|
||||
Digit3 = 51,
|
||||
Digit4 = 52,
|
||||
Digit5 = 53,
|
||||
Digit6 = 54,
|
||||
Digit7 = 55,
|
||||
Digit8 = 56,
|
||||
Digit9 = 57,
|
||||
Digit0 = 48,
|
||||
Digit1 = 49,
|
||||
Digit2 = 50,
|
||||
Digit3 = 51,
|
||||
Digit4 = 52,
|
||||
Digit5 = 53,
|
||||
Digit6 = 54,
|
||||
Digit7 = 55,
|
||||
Digit8 = 56,
|
||||
Digit9 = 57,
|
||||
|
||||
/**
|
||||
* The `:` character.
|
||||
*/
|
||||
Colon = 58,
|
||||
/**
|
||||
* The `;` character.
|
||||
*/
|
||||
Semicolon = 59,
|
||||
/**
|
||||
* The `<` character.
|
||||
*/
|
||||
LessThan = 60,
|
||||
/**
|
||||
* The `=` character.
|
||||
*/
|
||||
Equals = 61,
|
||||
/**
|
||||
* The `>` character.
|
||||
*/
|
||||
GreaterThan = 62,
|
||||
/**
|
||||
* The `?` character.
|
||||
*/
|
||||
QuestionMark = 63,
|
||||
/**
|
||||
* The `@` character.
|
||||
*/
|
||||
AtSign = 64,
|
||||
/**
|
||||
* The `:` character.
|
||||
*/
|
||||
Colon = 58,
|
||||
/**
|
||||
* The `;` character.
|
||||
*/
|
||||
Semicolon = 59,
|
||||
/**
|
||||
* The `<` character.
|
||||
*/
|
||||
LessThan = 60,
|
||||
/**
|
||||
* The `=` character.
|
||||
*/
|
||||
Equals = 61,
|
||||
/**
|
||||
* The `>` character.
|
||||
*/
|
||||
GreaterThan = 62,
|
||||
/**
|
||||
* The `?` character.
|
||||
*/
|
||||
QuestionMark = 63,
|
||||
/**
|
||||
* The `@` character.
|
||||
*/
|
||||
AtSign = 64,
|
||||
|
||||
A = 65,
|
||||
B = 66,
|
||||
C = 67,
|
||||
D = 68,
|
||||
E = 69,
|
||||
F = 70,
|
||||
G = 71,
|
||||
H = 72,
|
||||
I = 73,
|
||||
J = 74,
|
||||
K = 75,
|
||||
L = 76,
|
||||
M = 77,
|
||||
N = 78,
|
||||
O = 79,
|
||||
P = 80,
|
||||
Q = 81,
|
||||
R = 82,
|
||||
S = 83,
|
||||
T = 84,
|
||||
U = 85,
|
||||
V = 86,
|
||||
W = 87,
|
||||
X = 88,
|
||||
Y = 89,
|
||||
Z = 90,
|
||||
A = 65,
|
||||
B = 66,
|
||||
C = 67,
|
||||
D = 68,
|
||||
E = 69,
|
||||
F = 70,
|
||||
G = 71,
|
||||
H = 72,
|
||||
I = 73,
|
||||
J = 74,
|
||||
K = 75,
|
||||
L = 76,
|
||||
M = 77,
|
||||
N = 78,
|
||||
O = 79,
|
||||
P = 80,
|
||||
Q = 81,
|
||||
R = 82,
|
||||
S = 83,
|
||||
T = 84,
|
||||
U = 85,
|
||||
V = 86,
|
||||
W = 87,
|
||||
X = 88,
|
||||
Y = 89,
|
||||
Z = 90,
|
||||
|
||||
/**
|
||||
* The `[` character.
|
||||
*/
|
||||
OpenSquareBracket = 91,
|
||||
/**
|
||||
* The `\` character.
|
||||
*/
|
||||
Backslash = 92,
|
||||
/**
|
||||
* The `]` character.
|
||||
*/
|
||||
CloseSquareBracket = 93,
|
||||
/**
|
||||
* The `^` character.
|
||||
*/
|
||||
Caret = 94,
|
||||
/**
|
||||
* The `_` character.
|
||||
*/
|
||||
Underline = 95,
|
||||
/**
|
||||
* The ``(`)`` character.
|
||||
*/
|
||||
BackTick = 96,
|
||||
/**
|
||||
* The `[` character.
|
||||
*/
|
||||
OpenSquareBracket = 91,
|
||||
/**
|
||||
* The `\` character.
|
||||
*/
|
||||
Backslash = 92,
|
||||
/**
|
||||
* The `]` character.
|
||||
*/
|
||||
CloseSquareBracket = 93,
|
||||
/**
|
||||
* The `^` character.
|
||||
*/
|
||||
Caret = 94,
|
||||
/**
|
||||
* The `_` character.
|
||||
*/
|
||||
Underline = 95,
|
||||
/**
|
||||
* The ``(`)`` character.
|
||||
*/
|
||||
BackTick = 96,
|
||||
|
||||
a = 97,
|
||||
b = 98,
|
||||
c = 99,
|
||||
d = 100,
|
||||
e = 101,
|
||||
f = 102,
|
||||
g = 103,
|
||||
h = 104,
|
||||
i = 105,
|
||||
j = 106,
|
||||
k = 107,
|
||||
l = 108,
|
||||
m = 109,
|
||||
n = 110,
|
||||
o = 111,
|
||||
p = 112,
|
||||
q = 113,
|
||||
r = 114,
|
||||
s = 115,
|
||||
t = 116,
|
||||
u = 117,
|
||||
v = 118,
|
||||
w = 119,
|
||||
x = 120,
|
||||
y = 121,
|
||||
z = 122,
|
||||
a = 97,
|
||||
b = 98,
|
||||
c = 99,
|
||||
d = 100,
|
||||
e = 101,
|
||||
f = 102,
|
||||
g = 103,
|
||||
h = 104,
|
||||
i = 105,
|
||||
j = 106,
|
||||
k = 107,
|
||||
l = 108,
|
||||
m = 109,
|
||||
n = 110,
|
||||
o = 111,
|
||||
p = 112,
|
||||
q = 113,
|
||||
r = 114,
|
||||
s = 115,
|
||||
t = 116,
|
||||
u = 117,
|
||||
v = 118,
|
||||
w = 119,
|
||||
x = 120,
|
||||
y = 121,
|
||||
z = 122,
|
||||
|
||||
/**
|
||||
* The `{` character.
|
||||
*/
|
||||
OpenCurlyBrace = 123,
|
||||
/**
|
||||
* The `|` character.
|
||||
*/
|
||||
Pipe = 124,
|
||||
/**
|
||||
* The `}` character.
|
||||
*/
|
||||
CloseCurlyBrace = 125,
|
||||
/**
|
||||
* The `~` character.
|
||||
*/
|
||||
Tilde = 126,
|
||||
/**
|
||||
* The `{` character.
|
||||
*/
|
||||
OpenCurlyBrace = 123,
|
||||
/**
|
||||
* The `|` character.
|
||||
*/
|
||||
Pipe = 124,
|
||||
/**
|
||||
* The `}` character.
|
||||
*/
|
||||
CloseCurlyBrace = 125,
|
||||
/**
|
||||
* The `~` character.
|
||||
*/
|
||||
Tilde = 126,
|
||||
|
||||
U_Combining_Grave_Accent = 0x0300, // U+0300 Combining Grave Accent
|
||||
U_Combining_Acute_Accent = 0x0301, // U+0301 Combining Acute Accent
|
||||
U_Combining_Circumflex_Accent = 0x0302, // U+0302 Combining Circumflex Accent
|
||||
U_Combining_Tilde = 0x0303, // U+0303 Combining Tilde
|
||||
U_Combining_Macron = 0x0304, // U+0304 Combining Macron
|
||||
U_Combining_Overline = 0x0305, // U+0305 Combining Overline
|
||||
U_Combining_Breve = 0x0306, // U+0306 Combining Breve
|
||||
U_Combining_Dot_Above = 0x0307, // U+0307 Combining Dot Above
|
||||
U_Combining_Diaeresis = 0x0308, // U+0308 Combining Diaeresis
|
||||
U_Combining_Hook_Above = 0x0309, // U+0309 Combining Hook Above
|
||||
U_Combining_Ring_Above = 0x030A, // U+030A Combining Ring Above
|
||||
U_Combining_Double_Acute_Accent = 0x030B, // U+030B Combining Double Acute Accent
|
||||
U_Combining_Caron = 0x030C, // U+030C Combining Caron
|
||||
U_Combining_Vertical_Line_Above = 0x030D, // U+030D Combining Vertical Line Above
|
||||
U_Combining_Double_Vertical_Line_Above = 0x030E, // U+030E Combining Double Vertical Line Above
|
||||
U_Combining_Double_Grave_Accent = 0x030F, // U+030F Combining Double Grave Accent
|
||||
U_Combining_Candrabindu = 0x0310, // U+0310 Combining Candrabindu
|
||||
U_Combining_Inverted_Breve = 0x0311, // U+0311 Combining Inverted Breve
|
||||
U_Combining_Turned_Comma_Above = 0x0312, // U+0312 Combining Turned Comma Above
|
||||
U_Combining_Comma_Above = 0x0313, // U+0313 Combining Comma Above
|
||||
U_Combining_Reversed_Comma_Above = 0x0314, // U+0314 Combining Reversed Comma Above
|
||||
U_Combining_Comma_Above_Right = 0x0315, // U+0315 Combining Comma Above Right
|
||||
U_Combining_Grave_Accent_Below = 0x0316, // U+0316 Combining Grave Accent Below
|
||||
U_Combining_Acute_Accent_Below = 0x0317, // U+0317 Combining Acute Accent Below
|
||||
U_Combining_Left_Tack_Below = 0x0318, // U+0318 Combining Left Tack Below
|
||||
U_Combining_Right_Tack_Below = 0x0319, // U+0319 Combining Right Tack Below
|
||||
U_Combining_Left_Angle_Above = 0x031A, // U+031A Combining Left Angle Above
|
||||
U_Combining_Horn = 0x031B, // U+031B Combining Horn
|
||||
U_Combining_Left_Half_Ring_Below = 0x031C, // U+031C Combining Left Half Ring Below
|
||||
U_Combining_Up_Tack_Below = 0x031D, // U+031D Combining Up Tack Below
|
||||
U_Combining_Down_Tack_Below = 0x031E, // U+031E Combining Down Tack Below
|
||||
U_Combining_Plus_Sign_Below = 0x031F, // U+031F Combining Plus Sign Below
|
||||
U_Combining_Minus_Sign_Below = 0x0320, // U+0320 Combining Minus Sign Below
|
||||
U_Combining_Palatalized_Hook_Below = 0x0321, // U+0321 Combining Palatalized Hook Below
|
||||
U_Combining_Retroflex_Hook_Below = 0x0322, // U+0322 Combining Retroflex Hook Below
|
||||
U_Combining_Dot_Below = 0x0323, // U+0323 Combining Dot Below
|
||||
U_Combining_Diaeresis_Below = 0x0324, // U+0324 Combining Diaeresis Below
|
||||
U_Combining_Ring_Below = 0x0325, // U+0325 Combining Ring Below
|
||||
U_Combining_Comma_Below = 0x0326, // U+0326 Combining Comma Below
|
||||
U_Combining_Cedilla = 0x0327, // U+0327 Combining Cedilla
|
||||
U_Combining_Ogonek = 0x0328, // U+0328 Combining Ogonek
|
||||
U_Combining_Vertical_Line_Below = 0x0329, // U+0329 Combining Vertical Line Below
|
||||
U_Combining_Bridge_Below = 0x032A, // U+032A Combining Bridge Below
|
||||
U_Combining_Inverted_Double_Arch_Below = 0x032B, // U+032B Combining Inverted Double Arch Below
|
||||
U_Combining_Caron_Below = 0x032C, // U+032C Combining Caron Below
|
||||
U_Combining_Circumflex_Accent_Below = 0x032D, // U+032D Combining Circumflex Accent Below
|
||||
U_Combining_Breve_Below = 0x032E, // U+032E Combining Breve Below
|
||||
U_Combining_Inverted_Breve_Below = 0x032F, // U+032F Combining Inverted Breve Below
|
||||
U_Combining_Tilde_Below = 0x0330, // U+0330 Combining Tilde Below
|
||||
U_Combining_Macron_Below = 0x0331, // U+0331 Combining Macron Below
|
||||
U_Combining_Low_Line = 0x0332, // U+0332 Combining Low Line
|
||||
U_Combining_Double_Low_Line = 0x0333, // U+0333 Combining Double Low Line
|
||||
U_Combining_Tilde_Overlay = 0x0334, // U+0334 Combining Tilde Overlay
|
||||
U_Combining_Short_Stroke_Overlay = 0x0335, // U+0335 Combining Short Stroke Overlay
|
||||
U_Combining_Long_Stroke_Overlay = 0x0336, // U+0336 Combining Long Stroke Overlay
|
||||
U_Combining_Short_Solidus_Overlay = 0x0337, // U+0337 Combining Short Solidus Overlay
|
||||
U_Combining_Long_Solidus_Overlay = 0x0338, // U+0338 Combining Long Solidus Overlay
|
||||
U_Combining_Right_Half_Ring_Below = 0x0339, // U+0339 Combining Right Half Ring Below
|
||||
U_Combining_Inverted_Bridge_Below = 0x033A, // U+033A Combining Inverted Bridge Below
|
||||
U_Combining_Square_Below = 0x033B, // U+033B Combining Square Below
|
||||
U_Combining_Seagull_Below = 0x033C, // U+033C Combining Seagull Below
|
||||
U_Combining_X_Above = 0x033D, // U+033D Combining X Above
|
||||
U_Combining_Vertical_Tilde = 0x033E, // U+033E Combining Vertical Tilde
|
||||
U_Combining_Double_Overline = 0x033F, // U+033F Combining Double Overline
|
||||
U_Combining_Grave_Tone_Mark = 0x0340, // U+0340 Combining Grave Tone Mark
|
||||
U_Combining_Acute_Tone_Mark = 0x0341, // U+0341 Combining Acute Tone Mark
|
||||
U_Combining_Greek_Perispomeni = 0x0342, // U+0342 Combining Greek Perispomeni
|
||||
U_Combining_Greek_Koronis = 0x0343, // U+0343 Combining Greek Koronis
|
||||
U_Combining_Greek_Dialytika_Tonos = 0x0344, // U+0344 Combining Greek Dialytika Tonos
|
||||
U_Combining_Greek_Ypogegrammeni = 0x0345, // U+0345 Combining Greek Ypogegrammeni
|
||||
U_Combining_Bridge_Above = 0x0346, // U+0346 Combining Bridge Above
|
||||
U_Combining_Equals_Sign_Below = 0x0347, // U+0347 Combining Equals Sign Below
|
||||
U_Combining_Double_Vertical_Line_Below = 0x0348, // U+0348 Combining Double Vertical Line Below
|
||||
U_Combining_Left_Angle_Below = 0x0349, // U+0349 Combining Left Angle Below
|
||||
U_Combining_Not_Tilde_Above = 0x034A, // U+034A Combining Not Tilde Above
|
||||
U_Combining_Homothetic_Above = 0x034B, // U+034B Combining Homothetic Above
|
||||
U_Combining_Almost_Equal_To_Above = 0x034C, // U+034C Combining Almost Equal To Above
|
||||
U_Combining_Left_Right_Arrow_Below = 0x034D, // U+034D Combining Left Right Arrow Below
|
||||
U_Combining_Upwards_Arrow_Below = 0x034E, // U+034E Combining Upwards Arrow Below
|
||||
U_Combining_Grapheme_Joiner = 0x034F, // U+034F Combining Grapheme Joiner
|
||||
U_Combining_Right_Arrowhead_Above = 0x0350, // U+0350 Combining Right Arrowhead Above
|
||||
U_Combining_Left_Half_Ring_Above = 0x0351, // U+0351 Combining Left Half Ring Above
|
||||
U_Combining_Fermata = 0x0352, // U+0352 Combining Fermata
|
||||
U_Combining_X_Below = 0x0353, // U+0353 Combining X Below
|
||||
U_Combining_Left_Arrowhead_Below = 0x0354, // U+0354 Combining Left Arrowhead Below
|
||||
U_Combining_Right_Arrowhead_Below = 0x0355, // U+0355 Combining Right Arrowhead Below
|
||||
U_Combining_Right_Arrowhead_And_Up_Arrowhead_Below = 0x0356, // U+0356 Combining Right Arrowhead And Up Arrowhead Below
|
||||
U_Combining_Right_Half_Ring_Above = 0x0357, // U+0357 Combining Right Half Ring Above
|
||||
U_Combining_Dot_Above_Right = 0x0358, // U+0358 Combining Dot Above Right
|
||||
U_Combining_Asterisk_Below = 0x0359, // U+0359 Combining Asterisk Below
|
||||
U_Combining_Double_Ring_Below = 0x035A, // U+035A Combining Double Ring Below
|
||||
U_Combining_Zigzag_Above = 0x035B, // U+035B Combining Zigzag Above
|
||||
U_Combining_Double_Breve_Below = 0x035C, // U+035C Combining Double Breve Below
|
||||
U_Combining_Double_Breve = 0x035D, // U+035D Combining Double Breve
|
||||
U_Combining_Double_Macron = 0x035E, // U+035E Combining Double Macron
|
||||
U_Combining_Double_Macron_Below = 0x035F, // U+035F Combining Double Macron Below
|
||||
U_Combining_Double_Tilde = 0x0360, // U+0360 Combining Double Tilde
|
||||
U_Combining_Double_Inverted_Breve = 0x0361, // U+0361 Combining Double Inverted Breve
|
||||
U_Combining_Double_Rightwards_Arrow_Below = 0x0362, // U+0362 Combining Double Rightwards Arrow Below
|
||||
U_Combining_Latin_Small_Letter_A = 0x0363, // U+0363 Combining Latin Small Letter A
|
||||
U_Combining_Latin_Small_Letter_E = 0x0364, // U+0364 Combining Latin Small Letter E
|
||||
U_Combining_Latin_Small_Letter_I = 0x0365, // U+0365 Combining Latin Small Letter I
|
||||
U_Combining_Latin_Small_Letter_O = 0x0366, // U+0366 Combining Latin Small Letter O
|
||||
U_Combining_Latin_Small_Letter_U = 0x0367, // U+0367 Combining Latin Small Letter U
|
||||
U_Combining_Latin_Small_Letter_C = 0x0368, // U+0368 Combining Latin Small Letter C
|
||||
U_Combining_Latin_Small_Letter_D = 0x0369, // U+0369 Combining Latin Small Letter D
|
||||
U_Combining_Latin_Small_Letter_H = 0x036A, // U+036A Combining Latin Small Letter H
|
||||
U_Combining_Latin_Small_Letter_M = 0x036B, // U+036B Combining Latin Small Letter M
|
||||
U_Combining_Latin_Small_Letter_R = 0x036C, // U+036C Combining Latin Small Letter R
|
||||
U_Combining_Latin_Small_Letter_T = 0x036D, // U+036D Combining Latin Small Letter T
|
||||
U_Combining_Latin_Small_Letter_V = 0x036E, // U+036E Combining Latin Small Letter V
|
||||
U_Combining_Latin_Small_Letter_X = 0x036F, // U+036F Combining Latin Small Letter X
|
||||
U_Combining_Grave_Accent = 0x0300, // U+0300 Combining Grave Accent
|
||||
U_Combining_Acute_Accent = 0x0301, // U+0301 Combining Acute Accent
|
||||
U_Combining_Circumflex_Accent = 0x0302, // U+0302 Combining Circumflex Accent
|
||||
U_Combining_Tilde = 0x0303, // U+0303 Combining Tilde
|
||||
U_Combining_Macron = 0x0304, // U+0304 Combining Macron
|
||||
U_Combining_Overline = 0x0305, // U+0305 Combining Overline
|
||||
U_Combining_Breve = 0x0306, // U+0306 Combining Breve
|
||||
U_Combining_Dot_Above = 0x0307, // U+0307 Combining Dot Above
|
||||
U_Combining_Diaeresis = 0x0308, // U+0308 Combining Diaeresis
|
||||
U_Combining_Hook_Above = 0x0309, // U+0309 Combining Hook Above
|
||||
U_Combining_Ring_Above = 0x030a, // U+030A Combining Ring Above
|
||||
U_Combining_Double_Acute_Accent = 0x030b, // U+030B Combining Double Acute Accent
|
||||
U_Combining_Caron = 0x030c, // U+030C Combining Caron
|
||||
U_Combining_Vertical_Line_Above = 0x030d, // U+030D Combining Vertical Line Above
|
||||
U_Combining_Double_Vertical_Line_Above = 0x030e, // U+030E Combining Double Vertical Line Above
|
||||
U_Combining_Double_Grave_Accent = 0x030f, // U+030F Combining Double Grave Accent
|
||||
U_Combining_Candrabindu = 0x0310, // U+0310 Combining Candrabindu
|
||||
U_Combining_Inverted_Breve = 0x0311, // U+0311 Combining Inverted Breve
|
||||
U_Combining_Turned_Comma_Above = 0x0312, // U+0312 Combining Turned Comma Above
|
||||
U_Combining_Comma_Above = 0x0313, // U+0313 Combining Comma Above
|
||||
U_Combining_Reversed_Comma_Above = 0x0314, // U+0314 Combining Reversed Comma Above
|
||||
U_Combining_Comma_Above_Right = 0x0315, // U+0315 Combining Comma Above Right
|
||||
U_Combining_Grave_Accent_Below = 0x0316, // U+0316 Combining Grave Accent Below
|
||||
U_Combining_Acute_Accent_Below = 0x0317, // U+0317 Combining Acute Accent Below
|
||||
U_Combining_Left_Tack_Below = 0x0318, // U+0318 Combining Left Tack Below
|
||||
U_Combining_Right_Tack_Below = 0x0319, // U+0319 Combining Right Tack Below
|
||||
U_Combining_Left_Angle_Above = 0x031a, // U+031A Combining Left Angle Above
|
||||
U_Combining_Horn = 0x031b, // U+031B Combining Horn
|
||||
U_Combining_Left_Half_Ring_Below = 0x031c, // U+031C Combining Left Half Ring Below
|
||||
U_Combining_Up_Tack_Below = 0x031d, // U+031D Combining Up Tack Below
|
||||
U_Combining_Down_Tack_Below = 0x031e, // U+031E Combining Down Tack Below
|
||||
U_Combining_Plus_Sign_Below = 0x031f, // U+031F Combining Plus Sign Below
|
||||
U_Combining_Minus_Sign_Below = 0x0320, // U+0320 Combining Minus Sign Below
|
||||
U_Combining_Palatalized_Hook_Below = 0x0321, // U+0321 Combining Palatalized Hook Below
|
||||
U_Combining_Retroflex_Hook_Below = 0x0322, // U+0322 Combining Retroflex Hook Below
|
||||
U_Combining_Dot_Below = 0x0323, // U+0323 Combining Dot Below
|
||||
U_Combining_Diaeresis_Below = 0x0324, // U+0324 Combining Diaeresis Below
|
||||
U_Combining_Ring_Below = 0x0325, // U+0325 Combining Ring Below
|
||||
U_Combining_Comma_Below = 0x0326, // U+0326 Combining Comma Below
|
||||
U_Combining_Cedilla = 0x0327, // U+0327 Combining Cedilla
|
||||
U_Combining_Ogonek = 0x0328, // U+0328 Combining Ogonek
|
||||
U_Combining_Vertical_Line_Below = 0x0329, // U+0329 Combining Vertical Line Below
|
||||
U_Combining_Bridge_Below = 0x032a, // U+032A Combining Bridge Below
|
||||
U_Combining_Inverted_Double_Arch_Below = 0x032b, // U+032B Combining Inverted Double Arch Below
|
||||
U_Combining_Caron_Below = 0x032c, // U+032C Combining Caron Below
|
||||
U_Combining_Circumflex_Accent_Below = 0x032d, // U+032D Combining Circumflex Accent Below
|
||||
U_Combining_Breve_Below = 0x032e, // U+032E Combining Breve Below
|
||||
U_Combining_Inverted_Breve_Below = 0x032f, // U+032F Combining Inverted Breve Below
|
||||
U_Combining_Tilde_Below = 0x0330, // U+0330 Combining Tilde Below
|
||||
U_Combining_Macron_Below = 0x0331, // U+0331 Combining Macron Below
|
||||
U_Combining_Low_Line = 0x0332, // U+0332 Combining Low Line
|
||||
U_Combining_Double_Low_Line = 0x0333, // U+0333 Combining Double Low Line
|
||||
U_Combining_Tilde_Overlay = 0x0334, // U+0334 Combining Tilde Overlay
|
||||
U_Combining_Short_Stroke_Overlay = 0x0335, // U+0335 Combining Short Stroke Overlay
|
||||
U_Combining_Long_Stroke_Overlay = 0x0336, // U+0336 Combining Long Stroke Overlay
|
||||
U_Combining_Short_Solidus_Overlay = 0x0337, // U+0337 Combining Short Solidus Overlay
|
||||
U_Combining_Long_Solidus_Overlay = 0x0338, // U+0338 Combining Long Solidus Overlay
|
||||
U_Combining_Right_Half_Ring_Below = 0x0339, // U+0339 Combining Right Half Ring Below
|
||||
U_Combining_Inverted_Bridge_Below = 0x033a, // U+033A Combining Inverted Bridge Below
|
||||
U_Combining_Square_Below = 0x033b, // U+033B Combining Square Below
|
||||
U_Combining_Seagull_Below = 0x033c, // U+033C Combining Seagull Below
|
||||
U_Combining_X_Above = 0x033d, // U+033D Combining X Above
|
||||
U_Combining_Vertical_Tilde = 0x033e, // U+033E Combining Vertical Tilde
|
||||
U_Combining_Double_Overline = 0x033f, // U+033F Combining Double Overline
|
||||
U_Combining_Grave_Tone_Mark = 0x0340, // U+0340 Combining Grave Tone Mark
|
||||
U_Combining_Acute_Tone_Mark = 0x0341, // U+0341 Combining Acute Tone Mark
|
||||
U_Combining_Greek_Perispomeni = 0x0342, // U+0342 Combining Greek Perispomeni
|
||||
U_Combining_Greek_Koronis = 0x0343, // U+0343 Combining Greek Koronis
|
||||
U_Combining_Greek_Dialytika_Tonos = 0x0344, // U+0344 Combining Greek Dialytika Tonos
|
||||
U_Combining_Greek_Ypogegrammeni = 0x0345, // U+0345 Combining Greek Ypogegrammeni
|
||||
U_Combining_Bridge_Above = 0x0346, // U+0346 Combining Bridge Above
|
||||
U_Combining_Equals_Sign_Below = 0x0347, // U+0347 Combining Equals Sign Below
|
||||
U_Combining_Double_Vertical_Line_Below = 0x0348, // U+0348 Combining Double Vertical Line Below
|
||||
U_Combining_Left_Angle_Below = 0x0349, // U+0349 Combining Left Angle Below
|
||||
U_Combining_Not_Tilde_Above = 0x034a, // U+034A Combining Not Tilde Above
|
||||
U_Combining_Homothetic_Above = 0x034b, // U+034B Combining Homothetic Above
|
||||
U_Combining_Almost_Equal_To_Above = 0x034c, // U+034C Combining Almost Equal To Above
|
||||
U_Combining_Left_Right_Arrow_Below = 0x034d, // U+034D Combining Left Right Arrow Below
|
||||
U_Combining_Upwards_Arrow_Below = 0x034e, // U+034E Combining Upwards Arrow Below
|
||||
U_Combining_Grapheme_Joiner = 0x034f, // U+034F Combining Grapheme Joiner
|
||||
U_Combining_Right_Arrowhead_Above = 0x0350, // U+0350 Combining Right Arrowhead Above
|
||||
U_Combining_Left_Half_Ring_Above = 0x0351, // U+0351 Combining Left Half Ring Above
|
||||
U_Combining_Fermata = 0x0352, // U+0352 Combining Fermata
|
||||
U_Combining_X_Below = 0x0353, // U+0353 Combining X Below
|
||||
U_Combining_Left_Arrowhead_Below = 0x0354, // U+0354 Combining Left Arrowhead Below
|
||||
U_Combining_Right_Arrowhead_Below = 0x0355, // U+0355 Combining Right Arrowhead Below
|
||||
U_Combining_Right_Arrowhead_And_Up_Arrowhead_Below = 0x0356, // U+0356 Combining Right Arrowhead And Up Arrowhead Below
|
||||
U_Combining_Right_Half_Ring_Above = 0x0357, // U+0357 Combining Right Half Ring Above
|
||||
U_Combining_Dot_Above_Right = 0x0358, // U+0358 Combining Dot Above Right
|
||||
U_Combining_Asterisk_Below = 0x0359, // U+0359 Combining Asterisk Below
|
||||
U_Combining_Double_Ring_Below = 0x035a, // U+035A Combining Double Ring Below
|
||||
U_Combining_Zigzag_Above = 0x035b, // U+035B Combining Zigzag Above
|
||||
U_Combining_Double_Breve_Below = 0x035c, // U+035C Combining Double Breve Below
|
||||
U_Combining_Double_Breve = 0x035d, // U+035D Combining Double Breve
|
||||
U_Combining_Double_Macron = 0x035e, // U+035E Combining Double Macron
|
||||
U_Combining_Double_Macron_Below = 0x035f, // U+035F Combining Double Macron Below
|
||||
U_Combining_Double_Tilde = 0x0360, // U+0360 Combining Double Tilde
|
||||
U_Combining_Double_Inverted_Breve = 0x0361, // U+0361 Combining Double Inverted Breve
|
||||
U_Combining_Double_Rightwards_Arrow_Below = 0x0362, // U+0362 Combining Double Rightwards Arrow Below
|
||||
U_Combining_Latin_Small_Letter_A = 0x0363, // U+0363 Combining Latin Small Letter A
|
||||
U_Combining_Latin_Small_Letter_E = 0x0364, // U+0364 Combining Latin Small Letter E
|
||||
U_Combining_Latin_Small_Letter_I = 0x0365, // U+0365 Combining Latin Small Letter I
|
||||
U_Combining_Latin_Small_Letter_O = 0x0366, // U+0366 Combining Latin Small Letter O
|
||||
U_Combining_Latin_Small_Letter_U = 0x0367, // U+0367 Combining Latin Small Letter U
|
||||
U_Combining_Latin_Small_Letter_C = 0x0368, // U+0368 Combining Latin Small Letter C
|
||||
U_Combining_Latin_Small_Letter_D = 0x0369, // U+0369 Combining Latin Small Letter D
|
||||
U_Combining_Latin_Small_Letter_H = 0x036a, // U+036A Combining Latin Small Letter H
|
||||
U_Combining_Latin_Small_Letter_M = 0x036b, // U+036B Combining Latin Small Letter M
|
||||
U_Combining_Latin_Small_Letter_R = 0x036c, // U+036C Combining Latin Small Letter R
|
||||
U_Combining_Latin_Small_Letter_T = 0x036d, // U+036D Combining Latin Small Letter T
|
||||
U_Combining_Latin_Small_Letter_V = 0x036e, // U+036E Combining Latin Small Letter V
|
||||
U_Combining_Latin_Small_Letter_X = 0x036f, // U+036F Combining Latin Small Letter X
|
||||
|
||||
/**
|
||||
* Unicode Character 'LINE SEPARATOR' (U+2028)
|
||||
* http://www.fileformat.info/info/unicode/char/2028/index.htm
|
||||
*/
|
||||
LINE_SEPARATOR = 0x2028,
|
||||
/**
|
||||
* Unicode Character 'PARAGRAPH SEPARATOR' (U+2029)
|
||||
* http://www.fileformat.info/info/unicode/char/2029/index.htm
|
||||
*/
|
||||
PARAGRAPH_SEPARATOR = 0x2029,
|
||||
/**
|
||||
* Unicode Character 'NEXT LINE' (U+0085)
|
||||
* http://www.fileformat.info/info/unicode/char/0085/index.htm
|
||||
*/
|
||||
NEXT_LINE = 0x0085,
|
||||
/**
|
||||
* Unicode Character 'LINE SEPARATOR' (U+2028)
|
||||
* http://www.fileformat.info/info/unicode/char/2028/index.htm
|
||||
*/
|
||||
LINE_SEPARATOR = 0x2028,
|
||||
/**
|
||||
* Unicode Character 'PARAGRAPH SEPARATOR' (U+2029)
|
||||
* http://www.fileformat.info/info/unicode/char/2029/index.htm
|
||||
*/
|
||||
PARAGRAPH_SEPARATOR = 0x2029,
|
||||
/**
|
||||
* Unicode Character 'NEXT LINE' (U+0085)
|
||||
* http://www.fileformat.info/info/unicode/char/0085/index.htm
|
||||
*/
|
||||
NEXT_LINE = 0x0085,
|
||||
|
||||
// http://www.fileformat.info/info/unicode/category/Sk/list.htm
|
||||
U_CIRCUMFLEX = 0x005E, // U+005E CIRCUMFLEX
|
||||
U_GRAVE_ACCENT = 0x0060, // U+0060 GRAVE ACCENT
|
||||
U_DIAERESIS = 0x00A8, // U+00A8 DIAERESIS
|
||||
U_MACRON = 0x00AF, // U+00AF MACRON
|
||||
U_ACUTE_ACCENT = 0x00B4, // U+00B4 ACUTE ACCENT
|
||||
U_CEDILLA = 0x00B8, // U+00B8 CEDILLA
|
||||
U_MODIFIER_LETTER_LEFT_ARROWHEAD = 0x02C2, // U+02C2 MODIFIER LETTER LEFT ARROWHEAD
|
||||
U_MODIFIER_LETTER_RIGHT_ARROWHEAD = 0x02C3, // U+02C3 MODIFIER LETTER RIGHT ARROWHEAD
|
||||
U_MODIFIER_LETTER_UP_ARROWHEAD = 0x02C4, // U+02C4 MODIFIER LETTER UP ARROWHEAD
|
||||
U_MODIFIER_LETTER_DOWN_ARROWHEAD = 0x02C5, // U+02C5 MODIFIER LETTER DOWN ARROWHEAD
|
||||
U_MODIFIER_LETTER_CENTRED_RIGHT_HALF_RING = 0x02D2, // U+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING
|
||||
U_MODIFIER_LETTER_CENTRED_LEFT_HALF_RING = 0x02D3, // U+02D3 MODIFIER LETTER CENTRED LEFT HALF RING
|
||||
U_MODIFIER_LETTER_UP_TACK = 0x02D4, // U+02D4 MODIFIER LETTER UP TACK
|
||||
U_MODIFIER_LETTER_DOWN_TACK = 0x02D5, // U+02D5 MODIFIER LETTER DOWN TACK
|
||||
U_MODIFIER_LETTER_PLUS_SIGN = 0x02D6, // U+02D6 MODIFIER LETTER PLUS SIGN
|
||||
U_MODIFIER_LETTER_MINUS_SIGN = 0x02D7, // U+02D7 MODIFIER LETTER MINUS SIGN
|
||||
U_BREVE = 0x02D8, // U+02D8 BREVE
|
||||
U_DOT_ABOVE = 0x02D9, // U+02D9 DOT ABOVE
|
||||
U_RING_ABOVE = 0x02DA, // U+02DA RING ABOVE
|
||||
U_OGONEK = 0x02DB, // U+02DB OGONEK
|
||||
U_SMALL_TILDE = 0x02DC, // U+02DC SMALL TILDE
|
||||
U_DOUBLE_ACUTE_ACCENT = 0x02DD, // U+02DD DOUBLE ACUTE ACCENT
|
||||
U_MODIFIER_LETTER_RHOTIC_HOOK = 0x02DE, // U+02DE MODIFIER LETTER RHOTIC HOOK
|
||||
U_MODIFIER_LETTER_CROSS_ACCENT = 0x02DF, // U+02DF MODIFIER LETTER CROSS ACCENT
|
||||
U_MODIFIER_LETTER_EXTRA_HIGH_TONE_BAR = 0x02E5, // U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR
|
||||
U_MODIFIER_LETTER_HIGH_TONE_BAR = 0x02E6, // U+02E6 MODIFIER LETTER HIGH TONE BAR
|
||||
U_MODIFIER_LETTER_MID_TONE_BAR = 0x02E7, // U+02E7 MODIFIER LETTER MID TONE BAR
|
||||
U_MODIFIER_LETTER_LOW_TONE_BAR = 0x02E8, // U+02E8 MODIFIER LETTER LOW TONE BAR
|
||||
U_MODIFIER_LETTER_EXTRA_LOW_TONE_BAR = 0x02E9, // U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR
|
||||
U_MODIFIER_LETTER_YIN_DEPARTING_TONE_MARK = 0x02EA, // U+02EA MODIFIER LETTER YIN DEPARTING TONE MARK
|
||||
U_MODIFIER_LETTER_YANG_DEPARTING_TONE_MARK = 0x02EB, // U+02EB MODIFIER LETTER YANG DEPARTING TONE MARK
|
||||
U_MODIFIER_LETTER_UNASPIRATED = 0x02ED, // U+02ED MODIFIER LETTER UNASPIRATED
|
||||
U_MODIFIER_LETTER_LOW_DOWN_ARROWHEAD = 0x02EF, // U+02EF MODIFIER LETTER LOW DOWN ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_UP_ARROWHEAD = 0x02F0, // U+02F0 MODIFIER LETTER LOW UP ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_LEFT_ARROWHEAD = 0x02F1, // U+02F1 MODIFIER LETTER LOW LEFT ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_RIGHT_ARROWHEAD = 0x02F2, // U+02F2 MODIFIER LETTER LOW RIGHT ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_RING = 0x02F3, // U+02F3 MODIFIER LETTER LOW RING
|
||||
U_MODIFIER_LETTER_MIDDLE_GRAVE_ACCENT = 0x02F4, // U+02F4 MODIFIER LETTER MIDDLE GRAVE ACCENT
|
||||
U_MODIFIER_LETTER_MIDDLE_DOUBLE_GRAVE_ACCENT = 0x02F5, // U+02F5 MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT
|
||||
U_MODIFIER_LETTER_MIDDLE_DOUBLE_ACUTE_ACCENT = 0x02F6, // U+02F6 MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT
|
||||
U_MODIFIER_LETTER_LOW_TILDE = 0x02F7, // U+02F7 MODIFIER LETTER LOW TILDE
|
||||
U_MODIFIER_LETTER_RAISED_COLON = 0x02F8, // U+02F8 MODIFIER LETTER RAISED COLON
|
||||
U_MODIFIER_LETTER_BEGIN_HIGH_TONE = 0x02F9, // U+02F9 MODIFIER LETTER BEGIN HIGH TONE
|
||||
U_MODIFIER_LETTER_END_HIGH_TONE = 0x02FA, // U+02FA MODIFIER LETTER END HIGH TONE
|
||||
U_MODIFIER_LETTER_BEGIN_LOW_TONE = 0x02FB, // U+02FB MODIFIER LETTER BEGIN LOW TONE
|
||||
U_MODIFIER_LETTER_END_LOW_TONE = 0x02FC, // U+02FC MODIFIER LETTER END LOW TONE
|
||||
U_MODIFIER_LETTER_SHELF = 0x02FD, // U+02FD MODIFIER LETTER SHELF
|
||||
U_MODIFIER_LETTER_OPEN_SHELF = 0x02FE, // U+02FE MODIFIER LETTER OPEN SHELF
|
||||
U_MODIFIER_LETTER_LOW_LEFT_ARROW = 0x02FF, // U+02FF MODIFIER LETTER LOW LEFT ARROW
|
||||
U_GREEK_LOWER_NUMERAL_SIGN = 0x0375, // U+0375 GREEK LOWER NUMERAL SIGN
|
||||
U_GREEK_TONOS = 0x0384, // U+0384 GREEK TONOS
|
||||
U_GREEK_DIALYTIKA_TONOS = 0x0385, // U+0385 GREEK DIALYTIKA TONOS
|
||||
U_GREEK_KORONIS = 0x1FBD, // U+1FBD GREEK KORONIS
|
||||
U_GREEK_PSILI = 0x1FBF, // U+1FBF GREEK PSILI
|
||||
U_GREEK_PERISPOMENI = 0x1FC0, // U+1FC0 GREEK PERISPOMENI
|
||||
U_GREEK_DIALYTIKA_AND_PERISPOMENI = 0x1FC1, // U+1FC1 GREEK DIALYTIKA AND PERISPOMENI
|
||||
U_GREEK_PSILI_AND_VARIA = 0x1FCD, // U+1FCD GREEK PSILI AND VARIA
|
||||
U_GREEK_PSILI_AND_OXIA = 0x1FCE, // U+1FCE GREEK PSILI AND OXIA
|
||||
U_GREEK_PSILI_AND_PERISPOMENI = 0x1FCF, // U+1FCF GREEK PSILI AND PERISPOMENI
|
||||
U_GREEK_DASIA_AND_VARIA = 0x1FDD, // U+1FDD GREEK DASIA AND VARIA
|
||||
U_GREEK_DASIA_AND_OXIA = 0x1FDE, // U+1FDE GREEK DASIA AND OXIA
|
||||
U_GREEK_DASIA_AND_PERISPOMENI = 0x1FDF, // U+1FDF GREEK DASIA AND PERISPOMENI
|
||||
U_GREEK_DIALYTIKA_AND_VARIA = 0x1FED, // U+1FED GREEK DIALYTIKA AND VARIA
|
||||
U_GREEK_DIALYTIKA_AND_OXIA = 0x1FEE, // U+1FEE GREEK DIALYTIKA AND OXIA
|
||||
U_GREEK_VARIA = 0x1FEF, // U+1FEF GREEK VARIA
|
||||
U_GREEK_OXIA = 0x1FFD, // U+1FFD GREEK OXIA
|
||||
U_GREEK_DASIA = 0x1FFE, // U+1FFE GREEK DASIA
|
||||
// http://www.fileformat.info/info/unicode/category/Sk/list.htm
|
||||
U_CIRCUMFLEX = 0x005e, // U+005E CIRCUMFLEX
|
||||
U_GRAVE_ACCENT = 0x0060, // U+0060 GRAVE ACCENT
|
||||
U_DIAERESIS = 0x00a8, // U+00A8 DIAERESIS
|
||||
U_MACRON = 0x00af, // U+00AF MACRON
|
||||
U_ACUTE_ACCENT = 0x00b4, // U+00B4 ACUTE ACCENT
|
||||
U_CEDILLA = 0x00b8, // U+00B8 CEDILLA
|
||||
U_MODIFIER_LETTER_LEFT_ARROWHEAD = 0x02c2, // U+02C2 MODIFIER LETTER LEFT ARROWHEAD
|
||||
U_MODIFIER_LETTER_RIGHT_ARROWHEAD = 0x02c3, // U+02C3 MODIFIER LETTER RIGHT ARROWHEAD
|
||||
U_MODIFIER_LETTER_UP_ARROWHEAD = 0x02c4, // U+02C4 MODIFIER LETTER UP ARROWHEAD
|
||||
U_MODIFIER_LETTER_DOWN_ARROWHEAD = 0x02c5, // U+02C5 MODIFIER LETTER DOWN ARROWHEAD
|
||||
U_MODIFIER_LETTER_CENTRED_RIGHT_HALF_RING = 0x02d2, // U+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING
|
||||
U_MODIFIER_LETTER_CENTRED_LEFT_HALF_RING = 0x02d3, // U+02D3 MODIFIER LETTER CENTRED LEFT HALF RING
|
||||
U_MODIFIER_LETTER_UP_TACK = 0x02d4, // U+02D4 MODIFIER LETTER UP TACK
|
||||
U_MODIFIER_LETTER_DOWN_TACK = 0x02d5, // U+02D5 MODIFIER LETTER DOWN TACK
|
||||
U_MODIFIER_LETTER_PLUS_SIGN = 0x02d6, // U+02D6 MODIFIER LETTER PLUS SIGN
|
||||
U_MODIFIER_LETTER_MINUS_SIGN = 0x02d7, // U+02D7 MODIFIER LETTER MINUS SIGN
|
||||
U_BREVE = 0x02d8, // U+02D8 BREVE
|
||||
U_DOT_ABOVE = 0x02d9, // U+02D9 DOT ABOVE
|
||||
U_RING_ABOVE = 0x02da, // U+02DA RING ABOVE
|
||||
U_OGONEK = 0x02db, // U+02DB OGONEK
|
||||
U_SMALL_TILDE = 0x02dc, // U+02DC SMALL TILDE
|
||||
U_DOUBLE_ACUTE_ACCENT = 0x02dd, // U+02DD DOUBLE ACUTE ACCENT
|
||||
U_MODIFIER_LETTER_RHOTIC_HOOK = 0x02de, // U+02DE MODIFIER LETTER RHOTIC HOOK
|
||||
U_MODIFIER_LETTER_CROSS_ACCENT = 0x02df, // U+02DF MODIFIER LETTER CROSS ACCENT
|
||||
U_MODIFIER_LETTER_EXTRA_HIGH_TONE_BAR = 0x02e5, // U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR
|
||||
U_MODIFIER_LETTER_HIGH_TONE_BAR = 0x02e6, // U+02E6 MODIFIER LETTER HIGH TONE BAR
|
||||
U_MODIFIER_LETTER_MID_TONE_BAR = 0x02e7, // U+02E7 MODIFIER LETTER MID TONE BAR
|
||||
U_MODIFIER_LETTER_LOW_TONE_BAR = 0x02e8, // U+02E8 MODIFIER LETTER LOW TONE BAR
|
||||
U_MODIFIER_LETTER_EXTRA_LOW_TONE_BAR = 0x02e9, // U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR
|
||||
U_MODIFIER_LETTER_YIN_DEPARTING_TONE_MARK = 0x02ea, // U+02EA MODIFIER LETTER YIN DEPARTING TONE MARK
|
||||
U_MODIFIER_LETTER_YANG_DEPARTING_TONE_MARK = 0x02eb, // U+02EB MODIFIER LETTER YANG DEPARTING TONE MARK
|
||||
U_MODIFIER_LETTER_UNASPIRATED = 0x02ed, // U+02ED MODIFIER LETTER UNASPIRATED
|
||||
U_MODIFIER_LETTER_LOW_DOWN_ARROWHEAD = 0x02ef, // U+02EF MODIFIER LETTER LOW DOWN ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_UP_ARROWHEAD = 0x02f0, // U+02F0 MODIFIER LETTER LOW UP ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_LEFT_ARROWHEAD = 0x02f1, // U+02F1 MODIFIER LETTER LOW LEFT ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_RIGHT_ARROWHEAD = 0x02f2, // U+02F2 MODIFIER LETTER LOW RIGHT ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_RING = 0x02f3, // U+02F3 MODIFIER LETTER LOW RING
|
||||
U_MODIFIER_LETTER_MIDDLE_GRAVE_ACCENT = 0x02f4, // U+02F4 MODIFIER LETTER MIDDLE GRAVE ACCENT
|
||||
U_MODIFIER_LETTER_MIDDLE_DOUBLE_GRAVE_ACCENT = 0x02f5, // U+02F5 MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT
|
||||
U_MODIFIER_LETTER_MIDDLE_DOUBLE_ACUTE_ACCENT = 0x02f6, // U+02F6 MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT
|
||||
U_MODIFIER_LETTER_LOW_TILDE = 0x02f7, // U+02F7 MODIFIER LETTER LOW TILDE
|
||||
U_MODIFIER_LETTER_RAISED_COLON = 0x02f8, // U+02F8 MODIFIER LETTER RAISED COLON
|
||||
U_MODIFIER_LETTER_BEGIN_HIGH_TONE = 0x02f9, // U+02F9 MODIFIER LETTER BEGIN HIGH TONE
|
||||
U_MODIFIER_LETTER_END_HIGH_TONE = 0x02fa, // U+02FA MODIFIER LETTER END HIGH TONE
|
||||
U_MODIFIER_LETTER_BEGIN_LOW_TONE = 0x02fb, // U+02FB MODIFIER LETTER BEGIN LOW TONE
|
||||
U_MODIFIER_LETTER_END_LOW_TONE = 0x02fc, // U+02FC MODIFIER LETTER END LOW TONE
|
||||
U_MODIFIER_LETTER_SHELF = 0x02fd, // U+02FD MODIFIER LETTER SHELF
|
||||
U_MODIFIER_LETTER_OPEN_SHELF = 0x02fe, // U+02FE MODIFIER LETTER OPEN SHELF
|
||||
U_MODIFIER_LETTER_LOW_LEFT_ARROW = 0x02ff, // U+02FF MODIFIER LETTER LOW LEFT ARROW
|
||||
U_GREEK_LOWER_NUMERAL_SIGN = 0x0375, // U+0375 GREEK LOWER NUMERAL SIGN
|
||||
U_GREEK_TONOS = 0x0384, // U+0384 GREEK TONOS
|
||||
U_GREEK_DIALYTIKA_TONOS = 0x0385, // U+0385 GREEK DIALYTIKA TONOS
|
||||
U_GREEK_KORONIS = 0x1fbd, // U+1FBD GREEK KORONIS
|
||||
U_GREEK_PSILI = 0x1fbf, // U+1FBF GREEK PSILI
|
||||
U_GREEK_PERISPOMENI = 0x1fc0, // U+1FC0 GREEK PERISPOMENI
|
||||
U_GREEK_DIALYTIKA_AND_PERISPOMENI = 0x1fc1, // U+1FC1 GREEK DIALYTIKA AND PERISPOMENI
|
||||
U_GREEK_PSILI_AND_VARIA = 0x1fcd, // U+1FCD GREEK PSILI AND VARIA
|
||||
U_GREEK_PSILI_AND_OXIA = 0x1fce, // U+1FCE GREEK PSILI AND OXIA
|
||||
U_GREEK_PSILI_AND_PERISPOMENI = 0x1fcf, // U+1FCF GREEK PSILI AND PERISPOMENI
|
||||
U_GREEK_DASIA_AND_VARIA = 0x1fdd, // U+1FDD GREEK DASIA AND VARIA
|
||||
U_GREEK_DASIA_AND_OXIA = 0x1fde, // U+1FDE GREEK DASIA AND OXIA
|
||||
U_GREEK_DASIA_AND_PERISPOMENI = 0x1fdf, // U+1FDF GREEK DASIA AND PERISPOMENI
|
||||
U_GREEK_DIALYTIKA_AND_VARIA = 0x1fed, // U+1FED GREEK DIALYTIKA AND VARIA
|
||||
U_GREEK_DIALYTIKA_AND_OXIA = 0x1fee, // U+1FEE GREEK DIALYTIKA AND OXIA
|
||||
U_GREEK_VARIA = 0x1fef, // U+1FEF GREEK VARIA
|
||||
U_GREEK_OXIA = 0x1ffd, // U+1FFD GREEK OXIA
|
||||
U_GREEK_DASIA = 0x1ffe, // U+1FFE GREEK DASIA
|
||||
|
||||
U_IDEOGRAPHIC_FULL_STOP = 0x3002, // U+3002 IDEOGRAPHIC FULL STOP
|
||||
U_LEFT_CORNER_BRACKET = 0x300C, // U+300C LEFT CORNER BRACKET
|
||||
U_RIGHT_CORNER_BRACKET = 0x300D, // U+300D RIGHT CORNER BRACKET
|
||||
U_LEFT_BLACK_LENTICULAR_BRACKET = 0x3010, // U+3010 LEFT BLACK LENTICULAR BRACKET
|
||||
U_RIGHT_BLACK_LENTICULAR_BRACKET = 0x3011, // U+3011 RIGHT BLACK LENTICULAR BRACKET
|
||||
U_IDEOGRAPHIC_FULL_STOP = 0x3002, // U+3002 IDEOGRAPHIC FULL STOP
|
||||
U_LEFT_CORNER_BRACKET = 0x300c, // U+300C LEFT CORNER BRACKET
|
||||
U_RIGHT_CORNER_BRACKET = 0x300d, // U+300D RIGHT CORNER BRACKET
|
||||
U_LEFT_BLACK_LENTICULAR_BRACKET = 0x3010, // U+3010 LEFT BLACK LENTICULAR BRACKET
|
||||
U_RIGHT_BLACK_LENTICULAR_BRACKET = 0x3011, // U+3011 RIGHT BLACK LENTICULAR BRACKET
|
||||
|
||||
U_OVERLINE = 0x203e, // Unicode Character 'OVERLINE'
|
||||
|
||||
U_OVERLINE = 0x203E, // Unicode Character 'OVERLINE'
|
||||
/**
|
||||
* UTF-8 BOM
|
||||
* Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF)
|
||||
* http://www.fileformat.info/info/unicode/char/feff/index.htm
|
||||
*/
|
||||
UTF8_BOM = 65279,
|
||||
|
||||
/**
|
||||
* UTF-8 BOM
|
||||
* Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF)
|
||||
* http://www.fileformat.info/info/unicode/char/feff/index.htm
|
||||
*/
|
||||
UTF8_BOM = 65279,
|
||||
|
||||
U_FULLWIDTH_SEMICOLON = 0xFF1B, // U+FF1B FULLWIDTH SEMICOLON
|
||||
U_FULLWIDTH_COMMA = 0xFF0C, // U+FF0C FULLWIDTH COMMA
|
||||
}
|
||||
U_FULLWIDTH_SEMICOLON = 0xff1b, // U+FF1B FULLWIDTH SEMICOLON
|
||||
U_FULLWIDTH_COMMA = 0xff0c // U+FF0C FULLWIDTH COMMA
|
||||
}
|
||||
|
||||
@@ -1,276 +1,276 @@
|
||||
export const charMap: { [character: string]: string } = {
|
||||
// latin
|
||||
"À": "A",
|
||||
"Á": "A",
|
||||
"Â": "A",
|
||||
"Ã": "A",
|
||||
"Ä": "A",
|
||||
"Å": "A",
|
||||
"Æ": "AE",
|
||||
"Ç": "C",
|
||||
"È": "E",
|
||||
"É": "E",
|
||||
"Ê": "E",
|
||||
"Ë": "E",
|
||||
"Ì": "I",
|
||||
"Í": "I",
|
||||
"Î": "I",
|
||||
"Ï": "I",
|
||||
"Ð": "D",
|
||||
"Ñ": "N",
|
||||
"Ò": "O",
|
||||
"Ó": "O",
|
||||
"Ô": "O",
|
||||
"Õ": "O",
|
||||
"Ö": "O",
|
||||
"Ő": "O",
|
||||
"Ø": "O",
|
||||
"Ù": "U",
|
||||
"Ú": "U",
|
||||
"Û": "U",
|
||||
"Ü": "U",
|
||||
"Ű": "U",
|
||||
"Ý": "Y",
|
||||
"Þ": "TH",
|
||||
"ß": "ss",
|
||||
"à": "a",
|
||||
"á": "a",
|
||||
"â": "a",
|
||||
"ã": "a",
|
||||
"ä": "a",
|
||||
"å": "a",
|
||||
"æ": "ae",
|
||||
"ç": "c",
|
||||
"è": "e",
|
||||
"é": "e",
|
||||
"ê": "e",
|
||||
"ë": "e",
|
||||
"ì": "i",
|
||||
"í": "i",
|
||||
"î": "i",
|
||||
"ï": "i",
|
||||
"ð": "d",
|
||||
"ñ": "n",
|
||||
"ò": "o",
|
||||
"ó": "o",
|
||||
"ô": "o",
|
||||
"õ": "o",
|
||||
"ö": "o",
|
||||
"ő": "o",
|
||||
"ø": "o",
|
||||
"ù": "u",
|
||||
"ú": "u",
|
||||
"û": "u",
|
||||
"ü": "u",
|
||||
"ű": "u",
|
||||
"ý": "y",
|
||||
"þ": "th",
|
||||
"ÿ": "y",
|
||||
"ẞ": "SS",
|
||||
À: 'A',
|
||||
Á: 'A',
|
||||
Â: 'A',
|
||||
Ã: 'A',
|
||||
Ä: 'A',
|
||||
Å: 'A',
|
||||
Æ: 'AE',
|
||||
Ç: 'C',
|
||||
È: 'E',
|
||||
É: 'E',
|
||||
Ê: 'E',
|
||||
Ë: 'E',
|
||||
Ì: 'I',
|
||||
Í: 'I',
|
||||
Î: 'I',
|
||||
Ï: 'I',
|
||||
Ð: 'D',
|
||||
Ñ: 'N',
|
||||
Ò: 'O',
|
||||
Ó: 'O',
|
||||
Ô: 'O',
|
||||
Õ: 'O',
|
||||
Ö: 'O',
|
||||
Ő: 'O',
|
||||
Ø: 'O',
|
||||
Ù: 'U',
|
||||
Ú: 'U',
|
||||
Û: 'U',
|
||||
Ü: 'U',
|
||||
Ű: 'U',
|
||||
Ý: 'Y',
|
||||
Þ: 'TH',
|
||||
ß: 'ss',
|
||||
à: 'a',
|
||||
á: 'a',
|
||||
â: 'a',
|
||||
ã: 'a',
|
||||
ä: 'a',
|
||||
å: 'a',
|
||||
æ: 'ae',
|
||||
ç: 'c',
|
||||
è: 'e',
|
||||
é: 'e',
|
||||
ê: 'e',
|
||||
ë: 'e',
|
||||
ì: 'i',
|
||||
í: 'i',
|
||||
î: 'i',
|
||||
ï: 'i',
|
||||
ð: 'd',
|
||||
ñ: 'n',
|
||||
ò: 'o',
|
||||
ó: 'o',
|
||||
ô: 'o',
|
||||
õ: 'o',
|
||||
ö: 'o',
|
||||
ő: 'o',
|
||||
ø: 'o',
|
||||
ù: 'u',
|
||||
ú: 'u',
|
||||
û: 'u',
|
||||
ü: 'u',
|
||||
ű: 'u',
|
||||
ý: 'y',
|
||||
þ: 'th',
|
||||
ÿ: 'y',
|
||||
ẞ: 'SS',
|
||||
// greek
|
||||
"α": "a",
|
||||
"β": "b",
|
||||
"γ": "g",
|
||||
"δ": "d",
|
||||
"ε": "e",
|
||||
"ζ": "z",
|
||||
"η": "h",
|
||||
"θ": "8",
|
||||
"ι": "i",
|
||||
"κ": "k",
|
||||
"λ": "l",
|
||||
"μ": "m",
|
||||
"ν": "n",
|
||||
"ξ": "3",
|
||||
"ο": "o",
|
||||
"π": "p",
|
||||
"ρ": "r",
|
||||
"σ": "s",
|
||||
"τ": "t",
|
||||
"υ": "y",
|
||||
"φ": "f",
|
||||
"χ": "x",
|
||||
"ψ": "ps",
|
||||
"ω": "w",
|
||||
"ά": "a",
|
||||
"έ": "e",
|
||||
"ί": "i",
|
||||
"ό": "o",
|
||||
"ύ": "y",
|
||||
"ή": "h",
|
||||
"ώ": "w",
|
||||
"ς": "s",
|
||||
"ϊ": "i",
|
||||
"ΰ": "y",
|
||||
"ϋ": "y",
|
||||
"ΐ": "i",
|
||||
"Α": "A",
|
||||
"Β": "B",
|
||||
"Γ": "G",
|
||||
"Δ": "D",
|
||||
"Ε": "E",
|
||||
"Ζ": "Z",
|
||||
"Η": "H",
|
||||
"Θ": "8",
|
||||
"Ι": "I",
|
||||
"Κ": "K",
|
||||
"Λ": "L",
|
||||
"Μ": "M",
|
||||
"Ν": "N",
|
||||
"Ξ": "3",
|
||||
"Ο": "O",
|
||||
"Π": "P",
|
||||
"Ρ": "R",
|
||||
"Σ": "S",
|
||||
"Τ": "T",
|
||||
"Υ": "Y",
|
||||
"Φ": "F",
|
||||
"Χ": "X",
|
||||
"Ψ": "PS",
|
||||
"Ω": "W",
|
||||
"Ά": "A",
|
||||
"Έ": "E",
|
||||
"Ί": "I",
|
||||
"Ό": "O",
|
||||
"Ύ": "Y",
|
||||
"Ή": "H",
|
||||
"Ώ": "W",
|
||||
"Ϊ": "I",
|
||||
"Ϋ": "Y",
|
||||
α: 'a',
|
||||
β: 'b',
|
||||
γ: 'g',
|
||||
δ: 'd',
|
||||
ε: 'e',
|
||||
ζ: 'z',
|
||||
η: 'h',
|
||||
θ: '8',
|
||||
ι: 'i',
|
||||
κ: 'k',
|
||||
λ: 'l',
|
||||
μ: 'm',
|
||||
ν: 'n',
|
||||
ξ: '3',
|
||||
ο: 'o',
|
||||
π: 'p',
|
||||
ρ: 'r',
|
||||
σ: 's',
|
||||
τ: 't',
|
||||
υ: 'y',
|
||||
φ: 'f',
|
||||
χ: 'x',
|
||||
ψ: 'ps',
|
||||
ω: 'w',
|
||||
ά: 'a',
|
||||
έ: 'e',
|
||||
ί: 'i',
|
||||
ό: 'o',
|
||||
ύ: 'y',
|
||||
ή: 'h',
|
||||
ώ: 'w',
|
||||
ς: 's',
|
||||
ϊ: 'i',
|
||||
ΰ: 'y',
|
||||
ϋ: 'y',
|
||||
ΐ: 'i',
|
||||
Α: 'A',
|
||||
Β: 'B',
|
||||
Γ: 'G',
|
||||
Δ: 'D',
|
||||
Ε: 'E',
|
||||
Ζ: 'Z',
|
||||
Η: 'H',
|
||||
Θ: '8',
|
||||
Ι: 'I',
|
||||
Κ: 'K',
|
||||
Λ: 'L',
|
||||
Μ: 'M',
|
||||
Ν: 'N',
|
||||
Ξ: '3',
|
||||
Ο: 'O',
|
||||
Π: 'P',
|
||||
Ρ: 'R',
|
||||
Σ: 'S',
|
||||
Τ: 'T',
|
||||
Υ: 'Y',
|
||||
Φ: 'F',
|
||||
Χ: 'X',
|
||||
Ψ: 'PS',
|
||||
Ω: 'W',
|
||||
Ά: 'A',
|
||||
Έ: 'E',
|
||||
Ί: 'I',
|
||||
Ό: 'O',
|
||||
Ύ: 'Y',
|
||||
Ή: 'H',
|
||||
Ώ: 'W',
|
||||
Ϊ: 'I',
|
||||
Ϋ: 'Y',
|
||||
// turkish
|
||||
"ş": "s",
|
||||
"Ş": "S",
|
||||
"ı": "i",
|
||||
"İ": "I",
|
||||
"ğ": "g",
|
||||
"Ğ": "G",
|
||||
ş: 's',
|
||||
Ş: 'S',
|
||||
ı: 'i',
|
||||
İ: 'I',
|
||||
ğ: 'g',
|
||||
Ğ: 'G',
|
||||
// russian
|
||||
"а": "a",
|
||||
"б": "b",
|
||||
"в": "v",
|
||||
"г": "g",
|
||||
"д": "d",
|
||||
"е": "e",
|
||||
"ё": "yo",
|
||||
"ж": "zh",
|
||||
"з": "z",
|
||||
"и": "i",
|
||||
"й": "j",
|
||||
"к": "k",
|
||||
"л": "l",
|
||||
"м": "m",
|
||||
"н": "n",
|
||||
"о": "o",
|
||||
"п": "p",
|
||||
"р": "r",
|
||||
"с": "s",
|
||||
"т": "t",
|
||||
"у": "u",
|
||||
"ф": "f",
|
||||
"х": "h",
|
||||
"ц": "c",
|
||||
"ч": "ch",
|
||||
"ш": "sh",
|
||||
"щ": "sh",
|
||||
"ъ": "u",
|
||||
"ы": "y",
|
||||
"ь": "",
|
||||
"э": "e",
|
||||
"ю": "yu",
|
||||
"я": "ya",
|
||||
"А": "A",
|
||||
"Б": "B",
|
||||
"В": "V",
|
||||
"Г": "G",
|
||||
"Д": "D",
|
||||
"Е": "E",
|
||||
"Ё": "Yo",
|
||||
"Ж": "Zh",
|
||||
"З": "Z",
|
||||
"И": "I",
|
||||
"Й": "J",
|
||||
"К": "K",
|
||||
"Л": "L",
|
||||
"М": "M",
|
||||
"Н": "N",
|
||||
"О": "O",
|
||||
"П": "P",
|
||||
"Р": "R",
|
||||
"С": "S",
|
||||
"Т": "T",
|
||||
"У": "U",
|
||||
"Ф": "F",
|
||||
"Х": "H",
|
||||
"Ц": "C",
|
||||
"Ч": "Ch",
|
||||
"Ш": "Sh",
|
||||
"Щ": "Sh",
|
||||
"Ъ": "U",
|
||||
"Ы": "Y",
|
||||
"Ь": "",
|
||||
"Э": "E",
|
||||
"Ю": "Yu",
|
||||
"Я": "Ya",
|
||||
а: 'a',
|
||||
б: 'b',
|
||||
в: 'v',
|
||||
г: 'g',
|
||||
д: 'd',
|
||||
е: 'e',
|
||||
ё: 'yo',
|
||||
ж: 'zh',
|
||||
з: 'z',
|
||||
и: 'i',
|
||||
й: 'j',
|
||||
к: 'k',
|
||||
л: 'l',
|
||||
м: 'm',
|
||||
н: 'n',
|
||||
о: 'o',
|
||||
п: 'p',
|
||||
р: 'r',
|
||||
с: 's',
|
||||
т: 't',
|
||||
у: 'u',
|
||||
ф: 'f',
|
||||
х: 'h',
|
||||
ц: 'c',
|
||||
ч: 'ch',
|
||||
ш: 'sh',
|
||||
щ: 'sh',
|
||||
ъ: 'u',
|
||||
ы: 'y',
|
||||
ь: '',
|
||||
э: 'e',
|
||||
ю: 'yu',
|
||||
я: 'ya',
|
||||
А: 'A',
|
||||
Б: 'B',
|
||||
В: 'V',
|
||||
Г: 'G',
|
||||
Д: 'D',
|
||||
Е: 'E',
|
||||
Ё: 'Yo',
|
||||
Ж: 'Zh',
|
||||
З: 'Z',
|
||||
И: 'I',
|
||||
Й: 'J',
|
||||
К: 'K',
|
||||
Л: 'L',
|
||||
М: 'M',
|
||||
Н: 'N',
|
||||
О: 'O',
|
||||
П: 'P',
|
||||
Р: 'R',
|
||||
С: 'S',
|
||||
Т: 'T',
|
||||
У: 'U',
|
||||
Ф: 'F',
|
||||
Х: 'H',
|
||||
Ц: 'C',
|
||||
Ч: 'Ch',
|
||||
Ш: 'Sh',
|
||||
Щ: 'Sh',
|
||||
Ъ: 'U',
|
||||
Ы: 'Y',
|
||||
Ь: '',
|
||||
Э: 'E',
|
||||
Ю: 'Yu',
|
||||
Я: 'Ya',
|
||||
// ukranian
|
||||
"Є": "Ye",
|
||||
"І": "I",
|
||||
"Ї": "Yi",
|
||||
"Ґ": "G",
|
||||
"є": "ye",
|
||||
"і": "i",
|
||||
"ї": "yi",
|
||||
"ґ": "g",
|
||||
Є: 'Ye',
|
||||
І: 'I',
|
||||
Ї: 'Yi',
|
||||
Ґ: 'G',
|
||||
є: 'ye',
|
||||
і: 'i',
|
||||
ї: 'yi',
|
||||
ґ: 'g',
|
||||
// czech
|
||||
"č": "c",
|
||||
"ď": "d",
|
||||
"ě": "e",
|
||||
"ň": "n",
|
||||
"ř": "r",
|
||||
"š": "s",
|
||||
"ť": "t",
|
||||
"ů": "u",
|
||||
"ž": "z",
|
||||
"Č": "C",
|
||||
"Ď": "D",
|
||||
"Ě": "E",
|
||||
"Ň": "N",
|
||||
"Ř": "R",
|
||||
"Š": "S",
|
||||
"Ť": "T",
|
||||
"Ů": "U",
|
||||
"Ž": "Z",
|
||||
č: 'c',
|
||||
ď: 'd',
|
||||
ě: 'e',
|
||||
ň: 'n',
|
||||
ř: 'r',
|
||||
š: 's',
|
||||
ť: 't',
|
||||
ů: 'u',
|
||||
ž: 'z',
|
||||
Č: 'C',
|
||||
Ď: 'D',
|
||||
Ě: 'E',
|
||||
Ň: 'N',
|
||||
Ř: 'R',
|
||||
Š: 'S',
|
||||
Ť: 'T',
|
||||
Ů: 'U',
|
||||
Ž: 'Z',
|
||||
// polish
|
||||
"ą": "a",
|
||||
"ć": "c",
|
||||
"ę": "e",
|
||||
"ł": "l",
|
||||
"ń": "n",
|
||||
"ś": "s",
|
||||
"ź": "z",
|
||||
"ż": "z",
|
||||
"Ą": "A",
|
||||
"Ć": "C",
|
||||
"Ę": "e",
|
||||
"Ł": "L",
|
||||
"Ń": "N",
|
||||
"Ś": "S",
|
||||
"Ź": "Z",
|
||||
"Ż": "Z",
|
||||
ą: 'a',
|
||||
ć: 'c',
|
||||
ę: 'e',
|
||||
ł: 'l',
|
||||
ń: 'n',
|
||||
ś: 's',
|
||||
ź: 'z',
|
||||
ż: 'z',
|
||||
Ą: 'A',
|
||||
Ć: 'C',
|
||||
Ę: 'e',
|
||||
Ł: 'L',
|
||||
Ń: 'N',
|
||||
Ś: 'S',
|
||||
Ź: 'Z',
|
||||
Ż: 'Z',
|
||||
// latvian
|
||||
"ā": "a",
|
||||
"ē": "e",
|
||||
"ģ": "g",
|
||||
"ī": "i",
|
||||
"ķ": "k",
|
||||
"ļ": "l",
|
||||
"ņ": "n",
|
||||
"ū": "u",
|
||||
"Ā": "A",
|
||||
"Ē": "E",
|
||||
"Ģ": "G",
|
||||
"Ī": "i",
|
||||
"Ķ": "k",
|
||||
"Ļ": "L",
|
||||
"Ņ": "N",
|
||||
"Ū": "u"
|
||||
};
|
||||
ā: 'a',
|
||||
ē: 'e',
|
||||
ģ: 'g',
|
||||
ī: 'i',
|
||||
ķ: 'k',
|
||||
ļ: 'l',
|
||||
ņ: 'n',
|
||||
ū: 'u',
|
||||
Ā: 'A',
|
||||
Ē: 'E',
|
||||
Ģ: 'G',
|
||||
Ī: 'i',
|
||||
Ķ: 'k',
|
||||
Ļ: 'L',
|
||||
Ņ: 'N',
|
||||
Ū: 'u'
|
||||
};
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
export const CONTEXT = {
|
||||
canInit: "frontMatter:CanInit",
|
||||
initialized: "frontMatter:Initialized",
|
||||
canOpenPreview: "frontMatter:CanOpenPreview",
|
||||
canOpenDashboard: "frontMatter:CanOpenDashboard",
|
||||
isEnabled: "frontMatter:enabled",
|
||||
isDashboardOpen: "frontMatter:dashboard:open",
|
||||
wysiwyg: "frontMatter:markdown:wysiwyg",
|
||||
backer: "frontMatter:backers:supporter",
|
||||
isValidFile: "frontMatter:file:isValid",
|
||||
canOpenPreview: 'frontMatter:CanOpenPreview',
|
||||
canOpenDashboard: 'frontMatter:CanOpenDashboard',
|
||||
isEnabled: 'frontMatter:enabled',
|
||||
isDashboardOpen: 'frontMatter:dashboard:open',
|
||||
wysiwyg: 'frontMatter:markdown:wysiwyg',
|
||||
backer: 'frontMatter:backers:supporter',
|
||||
isValidFile: 'frontMatter:file:isValid',
|
||||
|
||||
isSnippetsDashboardEnabled: "frontMatter:dashboard:snippets:enabled",
|
||||
isDataDashboardEnabled: "frontMatter:dashboard:data:enabled",
|
||||
};
|
||||
hasViewModes: 'frontMatter:has:modes',
|
||||
|
||||
isSnippetsDashboardEnabled: 'frontMatter:dashboard:snippets:enabled',
|
||||
isDataDashboardEnabled: 'frontMatter:dashboard:data:enabled',
|
||||
|
||||
isGitEnabled: 'frontMatter:git:enabled'
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user