Compare commits

...

359 Commits

Author SHA1 Message Date
Elio Struyf
e695bad1c6 Merge pull request #347 from estruyf/dev 2022-06-01 12:01:18 +02:00
Elio Struyf
fe31081907 7.3.2 2022-06-01 12:00:45 +02:00
Elio Struyf
248ccb3718 Update changelog 2022-06-01 12:00:36 +02:00
Elio Struyf
2260174ec2 Merge branch 'main' into dev 2022-06-01 11:59:30 +02:00
Elio Struyf
cd3a867422 #346 - Fix media refresh 2022-06-01 11:59:02 +02:00
Elio Struyf
05a63dd110 Create PULL_REQUEST_TEMPLATE.md 2022-05-30 13:32:48 +02:00
Elio Struyf
cfc0c3d5a1 Create CONTRIBUTING.md 2022-05-30 13:29:48 +02:00
Elio Struyf
d6dbca25ce Create CODE_OF_CONDUCT.md 2022-05-30 13:16:10 +02:00
Elio Struyf
d21ad14e89 Merge pull request #344 from estruyf/dev 2022-05-26 18:58:30 +02:00
Elio Struyf
8d00726322 Update changelog 2022-05-26 18:57:22 +02:00
Elio Struyf
af11c304d3 7.3.1 2022-05-26 18:53:35 +02:00
Elio Struyf
223276f6af #343 - Fix in schema for frontMatter.taxonomy.fieldGroups setting 2022-05-26 18:53:27 +02:00
Elio Struyf
a6fdfe0dfa Merge pull request #342 from estruyf/dev 2022-05-25 13:13:50 +02:00
Elio Struyf
6154164b1c Updated changelog 2022-05-25 13:09:16 +02:00
Elio Struyf
1cdb6c56a5 #336 - Fix for updating status field 2022-05-25 13:08:39 +02:00
Elio Struyf
c63310a2db Initialize template folder 2022-05-25 12:51:39 +02:00
Elio Struyf
9f681a7459 Remove template creation 2022-05-25 11:46:18 +02:00
Elio Struyf
2610032a38 Update for the dataFile field 2022-05-25 10:12:05 +02:00
Elio Struyf
d11e8112e0 Fix for data view 2022-05-25 10:09:21 +02:00
Elio Struyf
df5e346cf1 Changelog update 2022-05-24 12:03:30 +02:00
Elio Struyf
9892d14a62 default labels for issues 2022-05-20 16:55:51 +02:00
Elio Struyf
8c61f79885 #340 - Show notification for not existing content folders 2022-05-20 16:46:39 +02:00
Elio Struyf
ffa6638d3d #339 - Fix for content folders without a title 2022-05-20 16:25:08 +02:00
Elio Struyf
f9ef12bd3a #338 - Disable templates setting 2022-05-20 16:22:46 +02:00
Elio Struyf
b79216f2b5 Added project label flow 2022-05-18 16:52:43 +02:00
Elio Struyf
2597a63718 Updated workflow 2022-05-18 14:13:07 +02:00
Elio Struyf
126a21a6b5 Added github action info 2022-05-18 13:58:50 +02:00
Elio Struyf
3abfbd5302 Message handler updates 2022-05-18 13:20:06 +02:00
Elio Struyf
efdbce2d08 #332 - Adding the new fileData field 2022-05-18 13:19:55 +02:00
Elio Struyf
09eea16d60 Remove logging 2022-05-18 10:29:23 +02:00
Elio Struyf
71697a09b6 Update dependency version 2022-05-17 16:23:23 +02:00
Elio Struyf
3583a2b962 #337 - Add support for other fm types 2022-05-17 16:19:40 +02:00
Elio Struyf
2825d5ddd8 #336 - support for draft field invert 2022-05-13 09:01:30 +02:00
Elio Struyf
2e66174c4a Setting focus for questions 2022-05-13 08:26:30 +02:00
Elio Struyf
e78069ad17 #333 - collection and published field support 2022-05-13 08:18:42 +02:00
Elio Struyf
4c97993c5f #333 - better support for Jekyll 2022-05-12 20:53:47 +02:00
Elio Struyf
a452173d9a Added icons to snippets 2022-05-12 17:59:17 +02:00
Elio Struyf
60a38be923 #335 - Merge media snippets to content snippets 2022-05-12 15:51:50 +02:00
Elio Struyf
6c3d286282 #331 - Added functionality to run other type of scripts 2022-05-10 16:26:59 +02:00
Elio Struyf
32c7bbd3f9 #334 - Fix for locked content folders retrieval 2022-05-09 09:00:36 +02:00
Elio Struyf
426dbc2e46 Update beta script 2022-05-08 20:02:35 +02:00
Elio Struyf
9882dea960 Update beta release script 2022-05-08 19:52:31 +02:00
Elio Struyf
eb9a05e90c update beta release script 2022-05-08 18:18:14 +02:00
Elio Struyf
4e59e736ed Parse windows path 2022-05-08 18:09:19 +02:00
Elio Struyf
9f91ebf289 7.3.0 2022-05-05 17:41:32 +02:00
Elio Struyf
b80de402bd #330 - Update front matter from script 2022-05-05 17:41:25 +02:00
Elio Struyf
e3c535276c Merge pull request #328 from estruyf/dev 2022-05-02 20:33:02 +02:00
Elio Struyf
add22b0bd0 updated changelog 2022-05-02 20:24:29 +02:00
Elio Struyf
48f855144e Limit the snippet pre height 2022-04-28 16:00:01 +02:00
Elio Struyf
67291f0cbe style fixes in date picker 2022-04-27 16:31:54 +02:00
Elio Struyf
45b302c698 Status radius change 2022-04-26 16:40:13 +02:00
Elio Struyf
f897edab5f Enhanced tags 2022-04-26 16:35:18 +02:00
Elio Struyf
dffb9f3dd8 #326 - New content type actions 2022-04-26 12:08:37 +02:00
Elio Struyf
573e1966ae Merge branch 'poc/generate-ct' into dev 2022-04-26 12:05:28 +02:00
Elio Struyf
d161aa98a0 Updates for button colors 2022-04-26 12:05:08 +02:00
Elio Struyf
f10d93c22e Add new mode for the content type actions 2022-04-25 20:47:44 +02:00
Elio Struyf
17a98fba68 Add content type create, update, setting 2022-04-25 14:57:59 +02:00
Elio Struyf
dee28397cb Override default content type 2022-04-22 11:18:42 +02:00
Elio Struyf
c4055eb37c Content type generation 2022-04-21 21:18:24 +02:00
Elio Struyf
91049bebd9 #325 - Better welcome experience 2022-04-21 17:11:07 +02:00
Elio Struyf
9f6c35b9ec Automatically set the recognized framework 2022-04-21 12:49:56 +02:00
Elio Struyf
f0ed7c0b39 #323 - Added additional SSGs 2022-04-21 12:42:57 +02:00
Elio Struyf
e64c4fc0f8 #324 - Fix for the framework selection 2022-04-21 12:27:45 +02:00
Elio Struyf
cd19cec4f7 #308 - Updates to media insertion + title metadata 2022-04-21 09:01:30 +02:00
Elio Struyf
070fc53685 Media dashboard fixes + improvements 2022-04-20 20:58:03 +02:00
Elio Struyf
b232c55843 Fix for mode switch 2022-04-20 11:19:23 +02:00
Elio Struyf
55a14b3fbe #308 - Implementation of the file field 2022-04-20 11:02:32 +02:00
Elio Struyf
60fde1711e Merge branch 'release/v7.2.0' into dev 2022-04-12 17:07:46 +02:00
Elio Struyf
31ca9d4e8b #322 - Show folder name for index page 2022-04-12 17:07:28 +02:00
Elio Struyf
bd47a09d1e Small fix for index files in the list 2022-04-12 15:34:46 +02:00
Elio Struyf
744322a398 #263 - WYSIWYG string field 2022-04-12 15:12:14 +02:00
Elio Struyf
70de0e3ebd Merge branch 'poc/preview' into release/v7.2.0 2022-04-11 14:10:11 +02:00
Elio Struyf
935ef83c4f #316 - Surpress disposed webview notifications 2022-04-11 13:22:20 +02:00
Elio Struyf
93370095e9 Merge branch 'dev' into v7.2.0 2022-04-11 13:13:15 +02:00
Elio Struyf
e8e9a5a5d3 Updated tag 2022-04-11 13:09:47 +02:00
Elio Struyf
a5fbf6991c Merge pull request #318 from estruyf/dev 2022-04-11 13:07:16 +02:00
Elio Struyf
a5f8017ab7 7.1.2 2022-04-11 13:05:56 +02:00
Elio Struyf
201fa4d564 #316 - Fix draft tab navigation 2022-04-11 13:05:48 +02:00
Elio Struyf
5e23d4446b 7.2.0 2022-04-11 10:42:01 +02:00
Elio Struyf
ef4e3fe28e Added sponsor image 2022-04-11 09:55:44 +02:00
Elio Struyf
6d6d86692a Merge pull request #313 from estruyf/dev 2022-04-08 10:03:42 +02:00
Elio Struyf
ada9724e54 update changelog 2022-04-08 10:03:13 +02:00
Elio Struyf
6347b728e4 Merge branch 'dev' 2022-04-08 10:01:09 +02:00
Elio Struyf
5079812745 7.1.1 2022-04-08 10:00:53 +02:00
Elio Struyf
c2ed9b2577 Fix for stopPropagation 2022-04-08 10:00:50 +02:00
Elio Struyf
20a5178326 Merge pull request #312 from estruyf/dev 2022-04-07 16:34:10 +02:00
Elio Struyf
81ad61f89d Update changelog for 7.1.0 release 2022-04-07 16:26:13 +02:00
Elio Struyf
5fc030b4dc Update attributes 2022-04-07 16:24:52 +02:00
Elio Struyf
6ef1ba5b57 Updated preview 2022-04-07 16:24:31 +02:00
Elio Struyf
bea6b181db Update changelog 2022-04-07 12:37:12 +02:00
Elio Struyf
e17819f458 #311 - Fix for updating snippets 2022-04-07 12:36:42 +02:00
Elio Struyf
db52e9c29a Style fix for tagpicker 2022-04-07 10:09:30 +02:00
Elio Struyf
e06fcb8ced Update settings + commends + changelog 2022-04-06 17:27:07 +02:00
Elio Struyf
51f43e8bfa #310 - Update changelog 2022-04-06 16:19:35 +02:00
Elio Struyf
0f66935385 #303 - updated card tags setting 2022-04-06 12:03:28 +02:00
Elio Struyf
29a6b121bb #308 - image check and if unknown, show file icon 2022-04-05 15:46:23 +02:00
Elio Struyf
6ed37f9ac2 Updated logo 2022-04-05 15:19:53 +02:00
Elio Struyf
f7c53b9afb updated changelog 2022-04-04 17:25:23 +02:00
Elio Struyf
e6e5c5c881 #308 - Supported mime types for media dashboard 2022-04-04 17:24:55 +02:00
Elio Struyf
f059b89fa5 #306 - Default value fix 2022-04-04 08:35:18 +02:00
Elio Struyf
8d5a678bb8 #240 - fix snippet action 2022-04-04 08:17:39 +02:00
Elio Struyf
8d901105bf Updated readme 2022-04-02 19:42:24 +02:00
Elio Struyf
637394156f #305 - fix for taxonomy picker styling 2022-04-02 10:08:31 +02:00
Elio Struyf
a79a987f5e Fix for onenter with selection 2022-04-02 09:34:28 +02:00
Elio Struyf
b22335d38e Updated changelog 2022-04-01 17:00:00 +02:00
Elio Struyf
757ccbddcf Fix duplicate snippets reference 2022-04-01 15:54:32 +02:00
Elio Struyf
39a30b320d #304 - Fix yaml stringify 2022-04-01 15:42:59 +02:00
Elio Struyf
912e436ca8 Fix for delete alert dialog 2022-04-01 15:41:57 +02:00
Elio Struyf
1b0853e23d #240 - Add the ability to define display modes 2022-03-31 17:05:04 +02:00
Elio Struyf
07c4e69319 Update media menu 2022-03-31 10:15:47 +02:00
Elio Struyf
4b3808a9ec #303 - new menu position 2022-03-30 20:42:51 +02:00
Elio Struyf
bd09a10fd8 #303 - Content card actions 2022-03-30 11:47:25 +02:00
Elio Struyf
9dbdd092f6 update changelog 2022-03-30 10:00:43 +02:00
Elio Struyf
ce331f12fb #302 - Spinner fix 2022-03-30 09:59:49 +02:00
Elio Struyf
cb93370f59 #301 - Visualize tags on content cards 2022-03-30 09:53:30 +02:00
Elio Struyf
7c77dca821 SEO Keywords key fix 2022-03-29 18:18:58 +02:00
Elio Struyf
17ffed418f #246 - Support to add multiple tags/keywords/taxonomy via comma separated values 2022-03-29 18:18:48 +02:00
Elio Struyf
7abb97e681 #293 - enhancement for preview images in block fields 2022-03-28 17:48:07 +02:00
Elio Struyf
33b1acddd0 7.1.0 2022-03-23 10:17:45 +01:00
Elio Struyf
e73803f927 #294 - Allow full text search 2022-03-23 10:17:32 +01:00
Elio Struyf
bbd257e650 Layout snippet fix 2022-03-23 10:17:07 +01:00
Elio Struyf
491b32baaa #296 - State caching for content dashboard 2022-03-23 08:49:43 +01:00
Elio Struyf
70d8bfe273 Small padding fixes 2022-03-22 16:46:26 +01:00
Elio Struyf
e69c8bbad8 Merge pull request #295 from estruyf/dev 2022-03-21 13:54:45 +01:00
Elio Struyf
12aba4e900 Remove logging 2022-03-21 13:47:08 +01:00
Elio Struyf
9d70521ccf #292 - Lower fuzzy search threshold 2022-03-21 12:58:20 +01:00
Elio Struyf
1d7ff4fbf7 update changelog 2022-03-21 12:48:32 +01:00
Elio Struyf
1eaf04d907 Update wf trigger 2022-03-17 17:03:59 +01:00
Elio Struyf
9839013465 Fix #257 2022-03-17 16:13:32 +01:00
Elio Struyf
65be619d51 Showing data nav by default + empty message update 2022-03-17 16:07:11 +01:00
Elio Struyf
c4331cb140 Update content folder settings 2022-03-16 19:55:43 +01:00
Elio Struyf
c09831e832 #286 - Fix for content types not containing fields 2022-03-16 19:33:39 +01:00
Elio Struyf
2a48e6adf1 Merge branch 'dev' of github.com:estruyf/vscode-front-matter into dev 2022-03-16 09:57:47 +01:00
Elio Struyf
8579d29890 #286 - Refresh button for content page 2022-03-16 09:57:39 +01:00
Elio
4fe9794b10 Additional logging 2022-03-16 08:41:32 +01:00
Elio Struyf
9413a6f878 #290 - Fix for onDidChangeTextEditorSelection listener sending metadata updates 2022-03-15 14:17:09 +01:00
Elio Struyf
e77672dfc7 Added new placeholders 2022-03-14 16:46:57 +01:00
Elio Struyf
bb9795952d Updated changelog + smaller command enhancements 2022-03-14 16:07:20 +01:00
Elio Struyf
36b3efafd4 Moved assets to docs site 2022-03-14 11:46:46 +01:00
Elio Struyf
b9ba9768ea Allow variable encoding in snippets 2022-03-14 10:18:55 +01:00
Elio Struyf
09c2c44c0a Hide the deprecation message 2022-03-14 10:18:44 +01:00
Elio Struyf
99ebbab100 Custom scripts 2022-03-14 09:06:29 +01:00
Elio Struyf
6ab6dda1da #175 - Simplified snippets 2022-03-11 13:53:33 +01:00
Elio Struyf
f77dce3566 Updated readme's 2022-03-11 12:24:46 +01:00
Elio Struyf
67c4355dff #287 - Show folder name on index.md files 2022-03-11 12:05:20 +01:00
Elio Struyf
1038d51e5d updateMetadata logic change 2022-03-10 09:33:19 +01:00
Elio Struyf
eaa61c1ea1 Updated vscodeignore 2022-03-10 08:54:35 +01:00
Elio Struyf
50695b6866 Error boundary for keyword 2022-03-09 20:47:24 +01:00
Elio Struyf
bf9011e23f Fix script 2022-03-09 11:29:22 +01:00
Elio Struyf
ac8a429ac2 Hide devtools webpack 2022-03-09 11:27:04 +01:00
Elio Struyf
f0cf59a1ac Fix for validating team value 2022-03-09 10:31:05 +01:00
Elio Struyf
145abfb026 Updated snippets 2022-03-08 17:11:26 +01:00
Elio Struyf
438160d08f #284 - Set the WYSIWYG on all supported files 2022-03-08 15:40:55 +01:00
Elio Struyf
b867f72fe2 Added collapse and dashboard buttons 2022-03-08 15:23:53 +01:00
Elio Struyf
cad6a2d5b4 #282 - Update relative paths for sub-leafs/bundles 2022-03-08 13:53:52 +01:00
Elio Struyf
3ea28e673f #282 - relative image paths in front matter 2022-03-08 13:06:41 +01:00
Elio Struyf
ea11a3646f #283 - Published date sorting 2022-03-08 08:58:03 +01:00
Elio Struyf
c8e79e75ba #281 - Do not automatically set dates to fm + remove date {{now}} field 2022-03-08 08:24:14 +01:00
Elio Struyf
9340568653 Sponsor updates 2022-03-08 08:23:27 +01:00
Elio Struyf
0d7b55c52f #270 #282 - Enhancements for page bundles and related folders + files 2022-03-07 20:52:21 +01:00
Elio Struyf
5644c0c381 #281 - Introduce new date fields and deprecate settings 2022-03-07 11:39:57 +01:00
Elio Struyf
04390b461f #280 - Fix for date fields 2022-03-07 09:27:38 +01:00
Elio Struyf
3ca6f32628 #279 - Fix for content dashboard updates 2022-03-07 09:20:24 +01:00
Elio Struyf
9fbf962e9f Fix for date parsing 2022-03-07 09:08:16 +01:00
Elio Struyf
b0d3aceecd Updated changelog + new features 2022-03-04 15:38:03 +01:00
Elio Struyf
94d88987ea Merge branch 'issue/175' into dev 2022-03-04 15:05:31 +01:00
Elio Struyf
aaf7a40969 7.0.0 2022-03-04 15:05:17 +01:00
Elio Struyf
4065019525 Snippet variables 2022-03-04 09:08:25 +01:00
Elio Struyf
eeb1fc9cb4 Added schema + array and string type 2022-03-03 21:05:41 +01:00
Elio Struyf
f35d8c8332 Merge branch 'issue/175' of github.com:estruyf/vscode-front-matter into issue/175 2022-03-03 19:57:15 +01:00
Elio Struyf
c8cd435142 Added snippet schema 2022-03-03 19:57:10 +01:00
Elio Struyf
0e42e1ea00 Code snippets changes: add, update, delete, and more 2022-03-03 16:26:36 +01:00
Elio Struyf
a6bdfc3421 Snippet dialog 2022-03-02 22:00:45 +01:00
Elio Struyf
47003754f6 Merge branch 'main' into dev 2022-03-02 18:18:00 +01:00
Elio Struyf
71072d9520 #275 - Invalid markdown syntax tree fix 2022-03-02 18:15:41 +01:00
Elio Struyf
b64dd8f88a Update changelog 2022-03-02 18:13:35 +01:00
Elio Struyf
173c89d86f 6.1.1 2022-03-02 18:12:24 +01:00
Elio Struyf
b1013829d8 #275 - Fix for incorrect markdown syntax 2022-03-02 18:10:44 +01:00
Elio Struyf
48ac869e40 Insert snippet into the content 2022-03-02 17:03:29 +01:00
Elio Struyf
00e590bc67 Snippet parser implementation 2022-03-02 16:03:07 +01:00
Elio Struyf
55053acd38 Remove unnecessary activation events 2022-03-02 13:27:16 +01:00
Elio Struyf
576ee9ca9d First steps to create the snippet dashboard 2022-03-02 08:40:30 +01:00
Elio Struyf
b99c61a0ee #272 - Media details panel 2022-03-01 15:14:29 +01:00
Elio Struyf
8d3b5619cd Sponsor badge 2022-03-01 13:19:57 +01:00
Elio Struyf
fdc7b8e68f 6.2.0 2022-03-01 12:15:16 +01:00
Elio Struyf
f5f558d5bc Merge pull request #274 from estruyf/dev 2022-02-28 17:40:50 +01:00
Elio Struyf
c9c38ef10b Replace fix 2022-02-28 17:34:53 +01:00
Elio Struyf
c30f401c4f Updated changelog for v6.1.0 release 2022-02-28 17:27:36 +01:00
Elio Struyf
9b92050af8 Undo version 2022-02-28 16:31:12 +01:00
Elio Struyf
31a41e2a66 Added version 2022-02-28 15:56:13 +01:00
Elio Struyf
baa56bc246 Updated activation events 2022-02-28 15:29:10 +01:00
Elio Struyf
f53e81e0cb Added release notes 2022-02-28 13:45:52 +01:00
Elio Struyf
f454266846 Updated changelog 2022-02-25 18:21:07 +01:00
Elio Struyf
0ba3c22795 #271 - Added image size placeholders for media snippets 2022-02-25 10:39:52 +01:00
Elio Struyf
ff38cf361c #241 - Enhanced the taxonomy field render 2022-02-25 08:43:36 +01:00
Elio Struyf
57e93b91c5 #268 - preserve casing of filename on creation 2022-02-24 18:04:09 +01:00
Elio Struyf
c1161b95ed #268 - Fix for panel not showing up after renaming 2022-02-24 17:12:42 +01:00
Elio Struyf
32dc63b62a Fix for keywords 2022-02-24 11:45:02 +00:00
Elio Struyf
0c1198c802 #264 - Fix for windows paths on content folder registration 2022-02-24 10:27:37 +00:00
Elio Struyf
ed4b78cfdc #262 - Fix related to YAML comments 2022-02-21 18:06:41 +01:00
Elio Struyf
65f77baf2b #261 - Update tags and categories 2022-02-19 17:32:32 +01:00
Elio Struyf
eabdf00d3d #257 - Allow preview images to be used in multi-dimensional fields 2022-02-18 11:27:31 -08:00
Elio Struyf
c084a15e08 updated changelog 2022-02-17 19:22:19 -08:00
Elio Struyf
e577ba591e #176 - Fix for tax fields 2022-02-17 19:21:29 -08:00
Elio Struyf
b17c7f888a #241 - Add taxonomy limit to limit the number of selections 2022-02-17 19:21:16 -08:00
Elio Struyf
0ed41b7d7e #176 - Extra setting updates 2022-02-17 19:12:05 -08:00
Elio Struyf
2e1faaa34f Sort all settings 2022-02-17 19:01:58 -08:00
Elio Struyf
63f02f4f0e Updated link 2022-02-17 18:59:34 -08:00
Elio Struyf
489fc5ec9e #176 - fieldGroups setting added to schema 2022-02-17 18:57:59 -08:00
Elio Struyf
4c8ecdb344 #255 - Implemented placeholder logic for WV to backend communication 2022-02-17 18:43:49 -08:00
Elio Struyf
8d705ff6c5 #176 #255 - Default block fields value 2022-02-17 11:32:34 -08:00
Elio Struyf
cfe68e65e8 Fix indent 2022-02-17 10:59:02 -08:00
Elio Struyf
0e179f5fd7 update changelog 2022-02-16 17:36:21 -08:00
Elio Struyf
6cabd6283b #242 - Keep comments at front matter root 2022-02-16 17:35:49 -08:00
Elio Struyf
6135e38fce Added now placeholder 2022-02-16 09:39:55 -08:00
Elio Struyf
935b2230af Merge pull request #249 from estruyf/dependabot/npm_and_yarn/follow-redirects-1.14.8 2022-02-15 15:50:57 -08:00
Elio Struyf
6dcd89e9cd #176 - label field support added to block fields 2022-02-15 11:13:46 -08:00
Elio Struyf
2775b2051f #176 - Save + cancel button and fixes in data storage 2022-02-15 07:41:52 -08:00
dependabot[bot]
5ebb2d7370 Bump follow-redirects from 1.14.6 to 1.14.8
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.6 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.6...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-15 03:35:22 +00:00
Elio Struyf
c9488e6661 #176 - Fix image webview paths 2022-02-14 16:54:54 -08:00
Elio Struyf
442261e655 #176 - Taxonomy field support added to block field 2022-02-14 16:07:59 -08:00
Elio Struyf
1aa2d41c95 #176 - Image field support added for block field 2022-02-14 15:45:16 -08:00
Elio Struyf
e5a2194c23 #176 - Fields field support 2022-02-14 12:42:45 -08:00
Elio Struyf
cf6f051ee8 Fix background color + labels 2022-02-14 11:38:13 -08:00
Elio Struyf
bebde4de68 #176 - Block field updated to support default fields 2022-02-14 09:18:44 -08:00
Elio Struyf
174c4b7734 #176 - Block to JSON field type 2022-02-13 18:11:51 -08:00
Elio Struyf
1f7519ee60 Dependency updates 2022-02-13 09:38:53 -08:00
Elio Struyf
b6482546a5 #248 - Highlighting support for other files added 2022-02-13 09:38:46 -08:00
Elio Struyf
0decd84f7f #247 - Fix front matter highlighting 2022-02-13 09:38:06 -08:00
Elio Struyf
a1dbda0b23 #176 - update dropdown style 2022-02-13 08:55:08 -08:00
Elio Struyf
427245f211 #176 - Select the first block type if single 2022-02-13 08:37:17 -08:00
Elio Struyf
4678189eab Update changelog 2022-02-13 08:26:01 -08:00
Elio Struyf
15d89e34cf Fix checkbox 2022-02-12 18:00:26 +01:00
Elio Struyf
cbb0d8f72b Refactoring explorer view to listeners 2022-02-12 17:58:59 +01:00
Elio Struyf
131150f5a6 #176 - Sorting + multi-block type support 2022-02-12 16:39:33 +01:00
Elio Struyf
a31bca73e7 Keep collapsible state 2022-02-12 10:03:40 +01:00
Elio Struyf
1d5f940c94 Remove logging 2022-02-11 11:30:30 +01:00
Elio Struyf
70ea6a5a16 Updated changelog 2022-02-11 11:25:45 +01:00
Elio Struyf
849af69ce2 #176 - updated styles for the autoform fields 2022-02-11 11:24:27 +01:00
Elio Struyf
754570a9ec #176 - Optimize styling of fields 2022-02-10 22:04:47 +01:00
Elio Struyf
f7f6f26997 #176 - New collection field + uniform custom components 2022-02-10 20:18:13 +01:00
Elio Struyf
946d84a7a9 Data click optimization 2022-02-10 12:00:23 +01:00
Elio Struyf
781ab6ac40 #243 - Refactoring front matter parsing 2022-02-08 13:17:56 +01:00
Elio Struyf
df86d02e8b Update activity bar icon 2022-02-02 12:03:41 +01:00
Elio Struyf
19e468c908 Fix reference 2022-02-01 14:31:57 +01:00
Elio Struyf
5a81ea19b8 Add telemetry property 2022-01-31 22:15:18 +01:00
Elio Struyf
64a38e56b9 Update activation events 2022-01-31 20:33:05 +01:00
Elio Struyf
fca0528a7e application insight fixes 2022-01-30 19:56:13 +01:00
Elio Struyf
936916acf8 6.1.0 2022-01-30 17:33:30 +01:00
Elio Struyf
61e9fc0308 start preping 6.1.0 2022-01-30 17:33:25 +01:00
Elio Struyf
2356623d7a Merge branch 'dev' 2022-01-25 17:52:20 +01:00
Elio Struyf
ee70acebb6 update changelog 2022-01-25 17:52:03 +01:00
Elio Struyf
09c48db957 Merge pull request #238 from estruyf/dev 2022-01-25 17:44:14 +01:00
Elio Struyf
d7658852b0 Reveal media file 2022-01-24 22:27:55 +01:00
Elio Struyf
0a0efba37b Updated changelog 2022-01-24 18:34:58 +01:00
Elio Struyf
a16c0c6355 #235 - Fix for reselecting the previously removed value 2022-01-24 18:34:24 +01:00
Elio Struyf
8dcbe67152 updated changelog 2022-01-22 19:11:25 +01:00
Elio Struyf
2c20621071 #234 - Fix for multi-word keywords 2022-01-22 19:10:42 +01:00
Elio Struyf
48c4c0b8e4 Updated supporters 2022-01-22 16:15:17 +01:00
Elio Struyf
2900777ffb updated changelog 2022-01-22 10:37:21 +01:00
Elio Struyf
0ccd428852 updating the docs 2022-01-22 10:35:57 +01:00
Elio Struyf
368ade6b44 Updated changelog 2022-01-21 17:03:03 +01:00
Elio Struyf
5f6b6e3b4a Fix for multi-dimensional fields + authentication improvement 2022-01-21 16:22:30 +01:00
Elio Struyf
43554a4303 #226 - Update the local server message 2022-01-21 14:00:29 +01:00
Elio Struyf
2b0007c21a Update changelog 2022-01-21 13:55:28 +01:00
Elio Struyf
5ab0bdaa69 #233 - Partial dashboard update on file change 2022-01-21 13:53:24 +01:00
Elio Struyf
1c74df0266 #225 - removed slug validation in button for dependent placeholders 2022-01-20 17:02:32 +01:00
Elio Struyf
469a1aaaf8 updated readme 2022-01-19 19:35:09 +01:00
Elio Struyf
c5523f7aaf Update overflow on data view 2022-01-19 14:08:17 +01:00
Elio Struyf
61b46bc5ac Update comments 2022-01-19 14:00:05 +01:00
Elio Struyf
d7a0f71552 #225 - Optimize slug will now process all fields with {{slug}} 2022-01-19 13:53:19 +01:00
Elio Struyf
7d6d60039e Optimized styling for data dashboard 2022-01-19 12:59:25 +01:00
Elio Struyf
42cc53cefc #226 - Allow to start the local server for the framework or SSG 2022-01-19 10:15:58 +01:00
Elio Struyf
e68daa8ac2 Styling updates 2022-01-18 18:57:06 +01:00
Elio Struyf
333cc1f9df Update FUNDING.yml 2022-01-18 13:24:12 +01:00
Elio Struyf
00bb8c6385 #227 - File type updates 2022-01-18 11:02:05 +01:00
Elio Struyf
1deb969c20 #227 - Added new supported file types setting 2022-01-17 14:48:46 +01:00
Elio Struyf
928afceca7 #231 - Backer support added 2022-01-17 14:11:04 +01:00
Elio Struyf
179b31f67c #230 - front matter json support added 2022-01-16 19:49:18 +01:00
Elio Struyf
7d4fe9ca0f Updated changelog 2022-01-15 20:35:31 +01:00
Elio Struyf
3e33383eb1 #225 - Placeholder support for front matter field values (template and content type) 2022-01-15 20:35:06 +01:00
Elio Struyf
66324fd292 #193 - support added for data folders 2022-01-15 19:31:15 +01:00
Elio Struyf
8b1fbcabaa Fix keys 2022-01-14 20:35:48 +01:00
Elio Struyf
90519488c1 #228 - Added action icon 2022-01-14 20:31:04 +01:00
Elio Struyf
1012e10ddc #228 - Add bulk actions 2022-01-14 20:23:28 +01:00
Elio Struyf
2dd129d9bd Remove unused references 2022-01-14 17:52:06 +01:00
Elio Struyf
6af5458082 #193 - YAML support for data files added 2022-01-14 15:22:51 +01:00
Elio Struyf
9744cf0117 #193 - Added data type support 2022-01-14 13:00:27 +01:00
Elio Struyf
01921c799c #193 - Support for list/array fields 2022-01-14 11:26:30 +01:00
Elio Struyf
b1674b4b84 #193 - Data file dashboard added 2022-01-13 20:18:32 +01:00
Elio Struyf
9f7f803e25 #198 - Additional media sort options 2022-01-12 14:44:45 +01:00
Elio Struyf
b83c565e29 HMR support for panel development 2022-01-12 14:09:59 +01:00
Elio Struyf
dee30923ff #197 - Update fields type + support for taxonomy and images 2022-01-12 11:25:44 +01:00
Elio Struyf
9a91be8025 #197 - Support for multi-dimensional content type fields 2022-01-11 12:23:46 +01:00
Elio Struyf
46a9d6e602 6.0.0 2022-01-11 08:55:06 +01:00
Elio Struyf
511fd48081 Merge pull request #224 from estruyf/dev 2022-01-10 13:01:03 +01:00
Elio Struyf
0039fc1555 Release date added 2022-01-10 13:00:32 +01:00
Elio Struyf
98044187cd Update changelog 2022-01-07 13:03:26 +01:00
Elio Struyf
a6dcc1ea79 Merge pull request #222 from farmerau/onWillSaveTextDocument 2022-01-07 12:55:34 +01:00
Elio Struyf
32a686227e #221 - Logic to remove new line by gray matter 2022-01-07 12:54:39 +01:00
Austin Farmer
faa74132e5 Adjust Automatic Date Updates to Run on Save
Prefers `onWillSaveTextDocument` over `onDidChangeTextDocument` for the triggering event.
2022-01-06 15:44:36 -05:00
Elio Struyf
3a847f7e42 Merge branch 'dev' of github.com:estruyf/vscode-front-matter into dev 2022-01-05 18:49:40 +01:00
Elio Struyf
66c978891e updated changelog 2022-01-05 18:49:18 +01:00
Elio Struyf
2f31230e07 Merge pull request #220 from farmerau/markdown-file-heuristics-mdx 2022-01-05 18:40:01 +01:00
Austin Farmer
c4225c0011 Support detection by file extension 2022-01-05 11:38:32 -05:00
Elio Struyf
4edc7a0280 Updated filetype 2022-01-05 10:17:34 +01:00
Elio Struyf
a60fe5204b Updated config 2022-01-04 11:57:16 +01:00
Elio Struyf
bb980b4afe #218 - Added MDX support for template and content creation 2022-01-04 11:51:11 +01:00
Elio Struyf
504658d87a 5.10.0 2022-01-04 11:24:40 +01:00
Elio Struyf
feff69d969 Merge pull request #217 from estruyf/dev 2022-01-01 20:21:23 +01:00
Elio Struyf
a34d77242a Updated entry 2022-01-01 20:20:57 +01:00
Elio Struyf
1b24c1277d Merge pull request #216 from estruyf/dev 2022-01-01 20:15:04 +01:00
Elio Struyf
e6750205be 🎇 New Year release 🎆 2022-01-01 20:14:15 +01:00
Elio Struyf
1da8bf3f8b To lowercase links 2021-12-29 19:14:10 +01:00
Elio Struyf
90c60b6a40 Merge branch 'LuiseFreese-main' into dev 2021-12-29 19:12:35 +01:00
Luise Freese
ee79f89c7f fixes casing issues that led to links that only referred to settings site but not to the specific heading 2021-12-29 11:17:11 +01:00
Elio Struyf
0668d48fd5 updated changelog 2021-12-28 21:20:16 +01:00
Elio Struyf
d046f73d16 #214 - Open file after creation fix 2021-12-28 20:52:42 +01:00
Elio Struyf
f144d713d1 added edit quick action 2021-12-28 10:45:33 +01:00
Elio Struyf
d31c403bdc Update icon 2021-12-28 10:43:36 +01:00
Elio Struyf
35a0327387 Added quick actions + some styling fixes 2021-12-28 10:35:46 +01:00
Elio Struyf
9b39649bde Update description 2021-12-27 16:29:37 +01:00
Elio Struyf
3d857463f0 Updated extension description 2021-12-27 16:25:55 +01:00
Elio Struyf
0428642a2f Update changelog 2021-12-27 16:22:26 +01:00
Elio Struyf
5182a9ae1a Fix spinner overlapping the global navigation 2021-12-27 16:22:01 +01:00
Elio Struyf
ab3686b3b5 #199 - Search media files 2021-12-27 15:56:12 +01:00
Elio Struyf
c5b7b7845d #212 - Added deleted folder watcher 2021-12-26 20:29:44 +01:00
Elio Struyf
2f13c335ed #212 - Added folder watchers 2021-12-26 20:24:23 +01:00
Elio Struyf
f219ac721f Updated navigation header 2021-12-26 19:13:42 +01:00
Elio Struyf
0149885289 Item borders 2021-12-26 18:56:24 +01:00
Elio Struyf
cb80a10de2 #213 - Media folder design 2021-12-26 17:19:31 +01:00
Elio Struyf
092eb0fd2a #211 - Replace text selection on media insert 2021-12-26 12:11:38 +01:00
Elio Struyf
24f79d9d3f #210 - Media file extension fix 2021-12-26 11:52:45 +01:00
Elio Struyf
d667b19716 5.9.0 2021-12-26 11:40:28 +01:00
Elio Struyf
4d38a0881a Merge pull request #209 from estruyf/dev 2021-12-21 15:45:06 +01:00
Elio Struyf
1478d0bd53 🎄 release 🎄 2021-12-21 15:39:43 +01:00
Elio Struyf
00a9e59bc2 #208 - Fix collapse section issue 2021-12-21 15:25:27 +01:00
Elio Struyf
2b2843234e Updated changelog 2021-12-21 11:13:46 +01:00
Elio Struyf
71449aa5cc Merge branch 'dev' of github.com:estruyf/vscode-front-matter into dev 2021-12-21 11:13:34 +01:00
Elio Struyf
87f293a3f6 added charset 2021-12-21 11:13:30 +01:00
Elio Struyf
6da3ddb5dd #206 - Removal of the front matter parsing error notification 2021-12-20 20:38:56 +01:00
Elio Struyf
87e80ccfe9 Update readme 2021-12-18 21:15:57 +01:00
Elio Struyf
af9865d91b Refresh the pages on content creation 2021-12-17 19:21:59 +01:00
Elio Struyf
e576b6e8a4 #207 - fix quick picks 2021-12-17 19:21:41 +01:00
Elio Struyf
c9f4c8f94e #206 - Added front matter diagnostic parsing 2021-12-17 19:04:41 +01:00
Elio Struyf
6ef63da973 Add sentry ignore rule 2021-12-16 14:02:57 +01:00
Elio Struyf
2d85b0a554 Updates for Webpack 5 support + HMR during dev 2021-12-16 13:31:30 +01:00
Elio Struyf
41cbcc4c46 Retain context on dashboard when hidden 2021-12-15 15:37:27 +01:00
Elio Struyf
6c94880497 Make output bundles smaller by smarter importing icons 2021-12-15 14:47:49 +01:00
Elio Struyf
1d75c6b6b8 Updated vs code engine 2021-12-15 14:22:47 +01:00
Elio Struyf
338bc022f9 Updated node version 2021-12-15 14:18:56 +01:00
Elio Struyf
2451730311 Updated workflow 2021-12-15 14:16:07 +01:00
Elio Struyf
22cdaabe28 Update changelog 2021-12-15 14:12:26 +01:00
Elio Struyf
5a69240178 #205 - Define a logging level setting 2021-12-15 14:10:58 +01:00
Elio Struyf
b81ef077f6 Merge branch 'dev-refactor' into dev 2021-12-15 13:51:01 +01:00
Elio Struyf
cb72b53653 Refactoring to message listeners 2021-12-15 13:50:40 +01:00
Elio Struyf
050a513b48 Refactoring 2021-12-15 11:16:39 +01:00
Elio Struyf
481d1f56e4 5.8.0 2021-12-15 08:29:41 +01:00
Elio Struyf
229238703a Updated vscode types 2021-12-15 08:29:35 +01:00
360 changed files with 22128 additions and 10302 deletions

View File

@@ -0,0 +1 @@
{"assets":{"v7.0.0":{"snippets-dashboard.png":{"caption":"Snippets dashboard","alt":"Snippets dashboard"}}}}

View File

1
.github/FUNDING.yml vendored
View File

@@ -1,4 +1,5 @@
# These are supported funding model platforms
github: [estruyf]
open_collective: frontmatter
custom: ["https://www.buymeacoffee.com/zMeFRy9"]

View File

@@ -2,7 +2,7 @@
name: Bug report
about: Create a report to help us improve
title: 'Issue: '
labels: ''
labels: 'bug'
assignees: ''
---

View File

@@ -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
View 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)

27
.github/workflows/project-labelling.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Project labelling
on:
project_card:
types: [created, moved, deleted]
jobs:
automate-issues-labels:
runs-on: ubuntu-latest
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
- 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 }}"

View File

@@ -3,6 +3,7 @@ on:
push:
branches:
- dev
workflow_dispatch:
jobs:
build:
@@ -11,9 +12,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: 14
node-version: 16
registry-url: https://registry.npmjs.org/
- name: Install the dependencies

View File

@@ -12,9 +12,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: 14
node-version: 16
registry-url: https://registry.npmjs.org/
- name: Install the dependencies

View File

@@ -2,6 +2,7 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"ms-vscode.vscode-typescript-tslint-plugin"
"ms-vscode.vscode-typescript-tslint-plugin",
"eliostruyf.vscode-typescript-exportallmodules"
]
}

View File

@@ -22,3 +22,8 @@ assets/v2.*
assets/v3.*
assets/v4.*
assets/sponsors
dist/*.html
frontmatter.json
.frontmatter
webpack
README.beta.md

View File

@@ -1,5 +1,238 @@
# Change Log
## [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
- [#294](https://github.com/estruyf/vscode-front-matter/issues/294): Full-text search allows you to search through all your page content
- [#297](https://github.com/estruyf/vscode-front-matter/issues/297): SEO Keywords input got moved to the SEO section
- [#301](https://github.com/estruyf/vscode-front-matter/issues/301): Show tags on the content cards
- [#303](https://github.com/estruyf/vscode-front-matter/issues/303): Content card actions to quickly view, delete, or run custom scripts
- [#310](https://github.com/estruyf/vscode-front-matter/issues/310): Supported mime types for media dashboard
### ⚡️ Optimizations
- [#296](https://github.com/estruyf/vscode-front-matter/issues/296): Loading optimization of the content dashboard
### 🐞 Fixes
- [#302](https://github.com/estruyf/vscode-front-matter/issues/302): Fix for spinner when navigating between tabs
- [#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
## [7.0.0] - 2022-03-21 - [Release notes](https://beta.frontmatter.codes/updates/v7.0.0)
### ✨ New Features
- [#175](https://github.com/estruyf/vscode-front-matter/issues/175): New snippet support + dashboard
- [#281](https://github.com/estruyf/vscode-front-matter/issues/281): New `isPublishDate` and `isModifiedDate` datetime field properties
### 🎨 Enhancements
- Light color theme enhancements to media cards
- Light color theme enhancements to folder cards
- Added collapse and dashboard button to the view title of the FM Panel
- Show content commands only when a supported file type is active
- Added `{{year}}`, `{{month}}`, and `{{day}}` placeholders for fields
- [#272](https://github.com/estruyf/vscode-front-matter/issues/272): New slide over panel for showing details of media files
- [#276](https://github.com/estruyf/vscode-front-matter/issues/276): Add a Front Matter walkthrough for VS Code
- [#270](https://github.com/estruyf/vscode-front-matter/issues/270): Only show media files from public folder if `pageBundle` is not enabled on any of the content types
- [#282](https://github.com/estruyf/vscode-front-matter/issues/282): Insert relative paths for media files located in a page bundle (also sub-folders)
- [#283](https://github.com/estruyf/vscode-front-matter/issues/283): Added published date sorting options for the content dashboard
- [#286](https://github.com/estruyf/vscode-front-matter/issues/286): Refresh button added for the content page
- [#287](https://github.com/estruyf/vscode-front-matter/issues/287): Show folder name on `index.md` files for recently modified files
- [#292](https://github.com/estruyf/vscode-front-matter/issues/292): Lower fuzzy search threshold for the content dashboard
### 🐞 Fixes
- [#279](https://github.com/estruyf/vscode-front-matter/issues/279): Fix for content dashboard updates for all registered types
- [#280](https://github.com/estruyf/vscode-front-matter/issues/280): Fix to not automatically set dates on new files that do not contain front matter
- [#284](https://github.com/estruyf/vscode-front-matter/issues/284): Show the WYSIWYG controls on all supported file types
- [#290](https://github.com/estruyf/vscode-front-matter/issues/290): Fix for onDidChangeTextEditorSelection listener sending metadata updates
## [6.1.1] - 2022-03-02
### 🐞 Fixes
- [#275](https://github.com/estruyf/vscode-front-matter/issues/275): Fix for rendering the panel when content contains an invalid markdown syntax tree
## [6.1.0] - 2022-02-28 - [Release notes](https://beta.frontmatter.codes/updates/v6.1.0)
### ✨ New features
- [#176](https://github.com/estruyf/vscode-front-matter/issues/176): New `block` field type that allows you to you to define a group of fields which can be used to create a list of data
### 🎨 Enhancements
- Updated the activity bar icon for better visibility
- Storing the panel collapse section states
- [#241](https://github.com/estruyf/vscode-front-matter/issues/241): Added taxonomy limit field property which allows you to limit the number of selections
- [#242](https://github.com/estruyf/vscode-front-matter/issues/242): Keep comments at the root of the front matter
- [#248](https://github.com/estruyf/vscode-front-matter/issues/248): Added support for front matter highlighting to all file types specified in `frontMatter.content.supportedFileTypes`
- [#255](https://github.com/estruyf/vscode-front-matter/issues/255): Added support for default values on block fields / data creation
- [#257](https://github.com/estruyf/vscode-front-matter/issues/257): Allow preview images to be used in multi-dimensional fields
- [#271](https://github.com/estruyf/vscode-front-matter/issues/271): Added image size placeholders for media snippets
### ⚡️ Optimizations
- Show the data item its details when clicking on the record
- Refactoring of the explorer view panel listeners
- Added `{{now}}` placeholder to the publishing date for content creation
- [#243](https://github.com/estruyf/vscode-front-matter/issues/243): Refactoring front matter parsing
### 🐞 Fixes
- [#247](https://github.com/estruyf/vscode-front-matter/issues/247): Fix the front matter highlighting in markdown documents
- [#261](https://github.com/estruyf/vscode-front-matter/issues/261): Fix to allow that tag and category fields can be renamed
- [#264](https://github.com/estruyf/vscode-front-matter/issues/264): Fix for Windows paths on content folder registration
- [#268](https://github.com/estruyf/vscode-front-matter/issues/268): Fix for panel which only shows loading indicator
## [6.0.0] - 2022-01-25 - [Release Notes](https://beta.frontmatter.codes/updates/v6.0.0)
### ✨ New features
- [#193](https://github.com/estruyf/vscode-front-matter/issues/193): Support added for editing data files.
- [#197](https://github.com/estruyf/vscode-front-matter/issues/197): Support for multi-dimensional content type fields on content creation and editing.
- [#225](https://github.com/estruyf/vscode-front-matter/issues/225): Placeholder support for front matter field values (template and content type).
- [#226](https://github.com/estruyf/vscode-front-matter/issues/226): Ability to specify the local server start command and trigger it from the UI.
- [#227](https://github.com/estruyf/vscode-front-matter/issues/227): Specify the file types to support with the new `frontMatter.content.supportedFileTypes` setting.
- [#228](https://github.com/estruyf/vscode-front-matter/issues/228): Show bulk button actions in panel and dashboard view.
- [#231](https://github.com/estruyf/vscode-front-matter/issues/231): Once you authenticate via GitHub as a supporter, the support links will be hidden from the UI.
### 🎨 Enhancements
- Added default field value for content type fields
- HMR support for panel webview development
- Added reveal media file action
- [#187](https://github.com/estruyf/vscode-front-matter/issues/187): Svelte support with the [#227](https://github.com/estruyf/vscode-front-matter/issues/227) features has been added.
- [#198](https://github.com/estruyf/vscode-front-matter/issues/198): Additional media sort options (alt, caption, and size).
- [#230](https://github.com/estruyf/vscode-front-matter/issues/230): JSON front matter support added.
- [#233](https://github.com/estruyf/vscode-front-matter/issues/233): Partial update when a page is updated.
### 🐞 Fixes
- [#234](https://github.com/estruyf/vscode-front-matter/issues/234): Fix for multi-word keywords
- [#235](https://github.com/estruyf/vscode-front-matter/issues/235): Fix for reselecting the previously removed value from a choice field
## [5.10.0] - 2022-01-10
### 🎨 Enhancements
- [#218](https://github.com/estruyf/vscode-front-matter/issues/218): Add support for creating `mdx` files from templates and content types. This introduced a new setting: `frontMatter.content.defaultFileType`.
- [#220](https://github.com/estruyf/vscode-front-matter/issues/220): Add support DateTime updates in `mdx` files when the `mdx extension` is not installed.
### 🐞 Fixes
- [#221](https://github.com/estruyf/vscode-front-matter/issues/221): Automatic DateTime switch from on text change to on save to prevent multiple updates.
## [5.9.0] - 2022-01-01 - 🎇🎆
### 🎨 Enhancements
- Fixing the spinner which overlaps the global navigation bar
- Quick actions added for media files (edit, delete, insert markdown, insert snippet)
- [#199](https://github.com/estruyf/vscode-front-matter/issues/199): Search media files in the currently selected folder
- [#211](https://github.com/estruyf/vscode-front-matter/issues/211): Replace text selection on media inserts
- [#212](https://github.com/estruyf/vscode-front-matter/issues/212): Create folder watchers for content folders. When new content gets created, the dashboard updates.
- [#213](https://github.com/estruyf/vscode-front-matter/issues/213): New media folder overview design
### 🐞 Fixes
- [#210](https://github.com/estruyf/vscode-front-matter/issues/210): Fix for adding media files with uppercase file extensions
- [#214](https://github.com/estruyf/vscode-front-matter/issues/214): Fix for opening markdown file after creating it for the specified content type
## [5.8.0] - 2021-12-21 - 🎄
### 🎨 Enhancements
- Refactoring of the WebView logic to new message handlers
- Optimized the `getMedia` call from the webview
- Keep the dashboard its context when switching tabs
- [#205](https://github.com/estruyf/vscode-front-matter/issues/205): Define a logging level setting
- [#206](https://github.com/estruyf/vscode-front-matter/issues/206): Add front matter issues to the diagnostic tab
### 🐞 Fixes
- [#207](https://github.com/estruyf/vscode-front-matter/issues/207): Fix the quick picks for content creation
- [#208](https://github.com/estruyf/vscode-front-matter/issues/208): Fix for the collapse sections action so that it is not available everywhere, but only on the Front Matter panel
## [5.7.0] - 2021-12-07 - [Release Notes](https://beta.frontmatter.codes/updates/v5.7.0)
### 🎨 Enhancements

128
CODE_OF_CONDUCT.md Normal file
View 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
View 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 `npm i`;
- Open the project in VS Code;
- To start developing, run `npm run 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.

View File

@@ -17,8 +17,8 @@
<img src="https://vsmarketplacebadge.apphb.com/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
<a href="https://www.buymeacoffee.com/zMeFRy9" title="Buy me a coffee" style="margin-left:10px">
<img src="https://img.shields.io/badge/Buy%20me%20a%20coffee-€%203-blue?logo=buy-me-a-coffee&style=flat" alt="Buy me a coffee" style="display: inline-block" />
<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" />
</a>
</p>
@@ -28,30 +28,56 @@
</a>
</h2>
## What is Front Matter?
## What is Front Matter?
Front Matter BETA is an essential Visual Studio Code extension that simplifies working and managing your markdown articles. We created the extension to support many static-site generators like Hugo, Jekyll, Hexo, NextJs, Gatsby, and more.
Front Matter is a CMS that runs within Visual Studio Code. It gives you the power and control of a full-blown CMS while also providing you the flexibility and speed of the static site generator of your choice. Jump right into editing and creating content with Front Matter and be able to preview it straight in VS Code.
The extension brings Content Management System (CMS) capabilities straight within Visual Studio Code. For example, you can keep a list of the used tags, categories, create content, and so much more.
The extension supports various static-site generators and frameworks like Hugo, Jekyll, Hexo, NextJs, Gatsby, and more.
Our main extension features are:
A couple of our extension highlights that hopefully get you interested in giving Front Matter a try:
- Page dashboard where you can get an overview of all your markdown pages. You can use it to search, filter, sort your contents.
- Site preview within Visual Studio Code
- Content, data, and media management
- Search, filter, sort, etc. all your content
- Create new content
- Supporting tools to edit content and media
- Preview your site/content straight in Visual Studio Code
- SEO checks for title, description, and keywords
- Support for custom actions/scripts
- and many more
- Extensibility
- As we know, we cannot support all use cases. We provide a way to extend the functionality of the extension to your needs
- and many more features ...
> Missing something? Let us know by opening an issue on the [GitHub repository](https://github.com/estruyf/vscode-front-matter/issues/new/choose)
<p align="center">
<img src="./assets/v4.0.0/preview.png" alt="Site preview" style="display: inline-block" />
<img src="https://frontmatter.codes/assets/marketplace/v6.0.0/content-preview.png" alt="Site preview" style="display: inline-block" />
</p>
> If you see something missing in your article creation flow, please feel free to reach out.
**Version 7**
Snippets support for Front Matter has been added!
![Snippets dashboard](https://frontmatter.codes/assets/marketplace/v7.0.0/snippets-dashboard.png)
**Version 6**
In this version, we introduced the new data files/folders dashboard. You can find more information about the release in our [v6.0.0 release notes](https://frontmatter.codes/updates/v6.0.0).
<p align="center">
<img src="https://frontmatter.codes/assets/marketplace/v6.0.0/data-dashboard.png" alt="Data dashboard" style="display: inline-block" />
</p>
> Data files/folders are pieces of content that do not belong to any markdown content, but live on their own. Most of the time, these data files are used to store additional information about your project/blog/website that will be used to render the content.
**Version 5**
The new media dashboard redesign got introduced + support for setting metadata on media files [v5.0.0 release notes](https://frontmatter.codes/updates/v5.0.0).
<p align="center">
<img src="https://frontmatter.codes/assets/marketplace/v5.9.0/media-dashboard.png" alt="Data dashboard" style="display: inline-block" />
</p>
**Version 4**
Support for Team level settings, content-types, and image support. Get to know more at: [v4.0.0 release notes](https://frontmatter.codes/updates/v4_0_0).
@@ -70,7 +96,7 @@ In version v2 we released the re-designed sidebar panel with improved SEO suppor
</a>
</p>
## Installation
## ⚙️ Installation
You can get the extension via:
@@ -80,23 +106,54 @@ You can get the extension via:
> **Info**: The docs can be found on [frontmatter.codes](https://frontmatter.codes).
### Beta version
### 🧪 Beta version
If you have the courage to test out the beta features, we made available a beta version as well. You can install this via:
- The 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>
- Uninstall the main Front Matter 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>
> **Info**: The BETA docs can be found on [beta.frontmatter.codes](https://beta.frontmatter.codes).
## Documentation
## 📖 Documentation
<h2 align="center">
<a href="https://beta.frontmatter.codes" title="Documentation @ beta.frontmatter.codes">
Check out the extension documentation at beta.frontmatter.codes
</a>
</h2>
All documentation can be found on [frontmatter.codes](https://frontmatter.codes).
Documentation repository: [GitHub - Front Matter DOCs](https://github.com/FrontMatter/web-documentation-nextjs)
## 💪 Contributing
Pull requests are welcome. Please open an issue first to discuss what you would like to change, or which problem you would like to fix. This makes it easier for us to follow-up and plan for future releases.
You can always help us improve the extension in varous ways like:
- 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)
## 👀 Show the work you are using Front Matter
Are you using Front Matter and are you interested in showing for which websites you use it? You can show your work by opening a [showcase issue](https://github.com/estruyf/vscode-front-matter/issues/new?assignees=&labels=&template=showcase.md&title=Showcase%3A+).
You can open showcase issues for the following things:
- Show the website for which you use Front Matter;
- Share an article/video/webcast/... that explains how you use Front Matter;
- Got something else to share? Open an issue and we can see where it fits on our website.
## 👉 Contributors 🤘
@@ -106,33 +163,28 @@ If you have the courage to test out the beta features, we made available a beta
</a>
</p>
## 🖤 Sponsors 👇 🤘
## 🖤 Backers & Sponsors 👇 🤘
<p align="center">
<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/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>
<img src="https://frontmatter.codes/api/img-sponsors" />
</p>
<br />
<p align="center">
<a href="https://vercel.com/?utm_source=vscode-frontmatter&utm_campaign=oss">
<img src="assets/sponsors/powered-by-vercel.png" />
</a>
<img src="https://frontmatter.codes/assets/sponsors/powered-by-vercel.png" />
</a>
</p>
## 🔑 License
[MIT](./LICENSE)
<br />
<br />
<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://estruyf-github.azurewebsites.net/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" height="25px" />
</a>
</p>

123
README.md
View File

@@ -15,8 +15,8 @@
<img src="https://vsmarketplacebadge.apphb.com/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
<a href="https://www.buymeacoffee.com/zMeFRy9" title="Buy me a coffee" style="margin-left:10px">
<img src="https://img.shields.io/badge/Buy%20me%20a%20coffee-€%203-blue?logo=buy-me-a-coffee&style=flat" alt="Buy me a coffee" style="display: inline-block" />
<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" />
</a>
</p>
@@ -26,30 +26,56 @@
</a>
</h2>
## What is Front Matter?
## What is Front Matter?
Front Matter is an essential Visual Studio Code extension that simplifies working and managing your markdown articles. We created the extension to support many static-site generators like Hugo, Jekyll, Hexo, NextJs, Gatsby, and more.
Front Matter is a CMS that runs within Visual Studio Code. It gives you the power and control of a full-blown CMS while also providing you the flexibility and speed of the static site generator of your choice. Jump right into editing and creating content with Front Matter and be able to preview it straight in VS Code.
The extension brings Content Management System (CMS) capabilities straight within Visual Studio Code. For example, you can keep a list of the used tags, categories, create content, and so much more.
The extension supports various static-site generators and frameworks like Hugo, Jekyll, Hexo, NextJs, Gatsby, and more.
Our main extension features are:
A couple of our extension highlights that hopefully get you interested in giving Front Matter a try:
- Page dashboard where you can get an overview of all your markdown pages. You can use it to search, filter, sort your contents.
- Site preview within Visual Studio Code
- Content, data, and media management
- Search, filter, sort, etc. all your content
- Create new content
- Supporting tools to edit content and media
- Preview your site/content straight in Visual Studio Code
- SEO checks for title, description, and keywords
- Support for custom actions/scripts
- and many more
- Extensibility
- As we know, we cannot support all use cases. We provide a way to extend the functionality of the extension to your needs
- and many more features ...
> Missing something? Let us know by opening an issue on the [GitHub repository](https://github.com/estruyf/vscode-front-matter/issues/new/choose)
<p align="center">
<img src="./assets/v4.0.0/preview.png" alt="Site preview" style="display: inline-block" />
<img src="https://frontmatter.codes/assets/marketplace/v6.0.0/content-preview.png" alt="Site preview" style="display: inline-block" />
</p>
> If you see something missing in your article creation flow, please feel free to reach out.
**Version 7**
Snippets support for Front Matter has been added!
![Snippets dashboard](https://frontmatter.codes/assets/marketplace/v7.0.0/snippets-dashboard.png)
**Version 6**
In this version, we introduced the new data files/folders dashboard. You can find more information about the release in our [v6.0.0 release notes](https://frontmatter.codes/updates/v6.0.0).
<p align="center">
<img src="https://frontmatter.codes/assets/marketplace/v6.0.0/data-dashboard.png" alt="Data dashboard" style="display: inline-block" />
</p>
> Data files/folders are pieces of content that do not belong to any markdown content, but live on their own. Most of the time, these data files are used to store additional information about your project/blog/website that will be used to render the content.
**Version 5**
The new media dashboard redesign got introduced + support for setting metadata on media files [v5.0.0 release notes](https://frontmatter.codes/updates/v5.0.0).
<p align="center">
<img src="https://frontmatter.codes/assets/marketplace/v5.9.0/media-dashboard.png" alt="Data dashboard" style="display: inline-block" />
</p>
**Version 4**
Support for Team level settings, content-types, and image support. Get to know more at: [v4.0.0 release notes](https://frontmatter.codes/updates/v4_0_0).
@@ -68,7 +94,7 @@ In version v2 we released the re-designed sidebar panel with improved SEO suppor
</a>
</p>
## Installation
## ⚙️ Installation
You can get the extension via:
@@ -78,23 +104,54 @@ You can get the extension via:
> **Info**: The docs can be found on [frontmatter.codes](https://frontmatter.codes).
### Beta version
### 🧪 Beta version
If you have the courage to test out the beta features, we made available a beta version as well. You can install this via:
- The 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>
- Uninstall the main Front Matter 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>
> **Info**: The BETA docs can be found on [beta.frontmatter.codes](https://beta.frontmatter.codes).
## Documentation
## 📖 Documentation
<h2 align="center">
<a href="https://frontmatter.codes" title="Documentation @ frontmatter.codes">
Check out the extension documentation at frontmatter.codes
</a>
</h2>
All documentation can be found on [frontmatter.codes](https://frontmatter.codes).
Documentation repository: [GitHub - Front Matter DOCs](https://github.com/FrontMatter/web-documentation-nextjs)
## 💪 Contributing
Pull requests are welcome. Please open an issue first to discuss what you would like to change, or which problem you would like to fix. This makes it easier for us to follow-up and plan for future releases.
You can always help us improve the extension in varous ways like:
- 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)
## 👀 Show the work you are using Front Matter
Are you using Front Matter and are you interested in showing for which websites you use it? You can show your work by opening a [showcase issue](https://github.com/estruyf/vscode-front-matter/issues/new?assignees=&labels=&template=showcase.md&title=Showcase%3A+).
You can open showcase issues for the following things:
- Show the website for which you use Front Matter;
- Share an article/video/webcast/... that explains how you use Front Matter;
- Got something else to share? Open an issue and we can see where it fits on our website.
## 👉 Contributors 🤘
@@ -104,33 +161,29 @@ If you have the courage to test out the beta features, we made available a beta
</a>
</p>
## 🖤 Sponsors 👇 🤘
## 🖤 Backers & Sponsors 👇 🤘
<p align="center">
<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/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>
<img src="https://frontmatter.codes/api/img-sponsors" />
</p>
<br />
<p align="center">
<a href="https://vercel.com/?utm_source=vscode-frontmatter&utm_campaign=oss">
<img src="assets/sponsors/powered-by-vercel.png" />
<img src="https://frontmatter.codes/assets/sponsors/powered-by-vercel.png" />
</a>
</p>
## 🔑 License
[MIT](./LICENSE)
<br />
<br />
<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://estruyf-github.azurewebsites.net/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" height="25px" />
</a>
</p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

2
assets/empty.svg Normal file
View File

@@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1">
</svg>

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -1 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1249.98 1249.98"><rect x="25" y="25" width="1199.98" height="1199.98" style="fill:none;stroke:#AD0670;stroke-miterlimit:10;stroke-width:50px"/><path d="M171.89,489.56H95.38V127.21H230.6V212.4H171.89v52.8h54.68v81.91H171.89Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M461.79,489.56H379l-37.8-129.08c-.37-2.18-1-5.08-1.93-8.68s-2.05-7.9-3.39-12.91l.55,23.94V489.56H260.33V127.21h78.34q51.75,0,77.43,26.05,32.65,33.32,32.66,94.81,0,65.71-43.85,90.82ZM336.84,295H342q13.21,0,22-12.91t8.81-32.86q0-40.59-33.21-40.6h-2.75Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M691.68,309.56q0,82.85-29.54,134.71-29.35,51.63-76.51,51.63-41.82,0-71.74-39.66Q476.29,406,476.28,305.57q0-96.23,39.26-147.15,29.18-37.78,69.18-37.79,49,0,78,51.17T691.68,309.56Zm-79.44.7q0-98.32-27.16-98.33-13.58,0-21.65,25.81-7.89,23.94-7.89,70.41,0,45.77,7.43,71t20.65,25.23q13.57,0,20.91-24.88Q612.24,354.62,612.24,310.26Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M724.34,489.56V127.21h73l38.35,127.2q3.1,11.27,7.06,25.81t8.72,33.56l7.88,31.92Q855.17,298.52,853,265t-2.2-56.33V127.21h73V489.56h-73l-38.53-133.3q-6.06-21.35-10.92-40t-8.53-35.56q2.38,38.26,3.49,66.65t1.1,49.76v92.46Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M1062.31,489.56H985.8V214H943.6V127.21h162.56V214h-43.85Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M122.7,730.59h35.82l27.36,133.72q5,25.05,9.16,50.2t7.55,52.74q.39-3.6.6-5.62a25.33,25.33,0,0,1,.4-2.87l5.84-37.56,5.23-35.66L219.29,862l24.35-131.39h36.22l28.57,327.72h-40l-7-111.22q-.41-8.49-.71-14.64c-.2-4.11-.3-7.5-.3-10.19l-1.81-43.94-1-40.33c0-.28,0-.88-.1-1.8s-.17-2.16-.3-3.72l-1,6.58q-1.61,11.69-2.91,20.38t-2.32,14.65L245.65,904l-2,11.25-26.16,143.06H189.3L164.75,934.78q-5-24.4-8.95-49.56t-7.14-52.75l-12.08,225.84H97.14Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M395.56,730.59h32.6l66.6,327.72H453.31l-11.67-63.89H380.06l-11.87,63.89H327.94Zm40,229.66L426.35,908q-9.27-53.28-15.1-113.77Q408.43,823.78,404,854t-10.46,64.2l-7.65,42Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M496.17,730.59H632.4v38.63H585.51v289.09h-41V769.22H496.17Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M639,730.59H775.26v38.63H728.38v289.09h-41V769.22H639Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M806.65,730.59H917.93V768H848.5V871.74h61.58V909.1H848.5V1021h69.43v37.35H806.65Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M964.61,730.59h55.13q34.21,0,50.91,17.19,21.13,22.29,21.13,68.14,0,35.24-11.16,56.56t-31.9,26.43l57.15,159.4h-42.46l-57-160.46v160.46H964.61Zm41.85,145.18q24.35,0,34.41-11.88t10.06-40.12a138.46,138.46,0,0,0-2.11-26.11q-2.11-10.81-6.64-17.61a27.08,27.08,0,0,0-11.67-10,41.58,41.58,0,0,0-17-3.18h-7Z" transform="translate(24 24)" style="fill:#AD0670"/></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -1 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1249.98 1249.98"><rect x="25" y="25" width="1199.98" height="1199.98" style="fill:none;stroke:#AD0670;stroke-miterlimit:10;stroke-width:50px"/><path d="M171.89,489.56H95.38V127.21H230.6V212.4H171.89v52.8h54.68v81.91H171.89Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M461.79,489.56H379l-37.8-129.08c-.37-2.18-1-5.08-1.93-8.68s-2.05-7.9-3.39-12.91l.55,23.94V489.56H260.33V127.21h78.34q51.75,0,77.43,26.05,32.65,33.32,32.66,94.81,0,65.71-43.85,90.82ZM336.84,295H342q13.21,0,22-12.91t8.81-32.86q0-40.59-33.21-40.6h-2.75Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M691.68,309.56q0,82.85-29.54,134.71-29.35,51.63-76.51,51.63-41.82,0-71.74-39.66Q476.29,406,476.28,305.57q0-96.23,39.26-147.15,29.18-37.78,69.18-37.79,49,0,78,51.17T691.68,309.56Zm-79.44.7q0-98.32-27.16-98.33-13.58,0-21.65,25.81-7.89,23.94-7.89,70.41,0,45.77,7.43,71t20.65,25.23q13.57,0,20.91-24.88Q612.24,354.62,612.24,310.26Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M724.34,489.56V127.21h73l38.35,127.2q3.1,11.27,7.06,25.81t8.72,33.56l7.88,31.92Q855.17,298.52,853,265t-2.2-56.33V127.21h73V489.56h-73l-38.53-133.3q-6.06-21.35-10.92-40t-8.53-35.56q2.38,38.26,3.49,66.65t1.1,49.76v92.46Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M1062.31,489.56H985.8V214H943.6V127.21h162.56V214h-43.85Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M122.7,730.59h35.82l27.36,133.72q5,25.05,9.16,50.2t7.55,52.74q.39-3.6.6-5.62a25.33,25.33,0,0,1,.4-2.87l5.84-37.56,5.23-35.66L219.29,862l24.35-131.39h36.22l28.57,327.72h-40l-7-111.22q-.41-8.49-.71-14.64c-.2-4.11-.3-7.5-.3-10.19l-1.81-43.94-1-40.33c0-.28,0-.88-.1-1.8s-.17-2.16-.3-3.72l-1,6.58q-1.61,11.69-2.91,20.38t-2.32,14.65L245.65,904l-2,11.25-26.16,143.06H189.3L164.75,934.78q-5-24.4-8.95-49.56t-7.14-52.75l-12.08,225.84H97.14Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M395.56,730.59h32.6l66.6,327.72H453.31l-11.67-63.89H380.06l-11.87,63.89H327.94Zm40,229.66L426.35,908q-9.27-53.28-15.1-113.77Q408.43,823.78,404,854t-10.46,64.2l-7.65,42Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M496.17,730.59H632.4v38.63H585.51v289.09h-41V769.22H496.17Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M639,730.59H775.26v38.63H728.38v289.09h-41V769.22H639Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M806.65,730.59H917.93V768H848.5V871.74h61.58V909.1H848.5V1021h69.43v37.35H806.65Z" transform="translate(24 24)" style="fill:#AD0670"/><path d="M964.61,730.59h55.13q34.21,0,50.91,17.19,21.13,22.29,21.13,68.14,0,35.24-11.16,56.56t-31.9,26.43l57.15,159.4h-42.46l-57-160.46v160.46H964.61Zm41.85,145.18q24.35,0,34.41-11.88t10.06-40.12a138.46,138.46,0,0,0-2.11-26.11q-2.11-10.81-6.64-17.61a27.08,27.08,0,0,0-11.67-10,41.58,41.58,0,0,0-17-3.18h-7Z" transform="translate(24 24)" style="fill:#AD0670"/></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -1,16 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 26.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1250 1250" style="enable-background:new 0 0 1250 1250;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#02AEB7;stroke-width:50;stroke-miterlimit:10;}
.st1{fill:#02AEB7;}
</style>
<rect x="25" y="25" class="st0" width="1200" height="1200"/>
<path class="st1" d="M316,1082.3H119.4V151.2h347.5v218.9H316v135.7h140.5v210.5H316V1082.3z"/>
<path class="st1" d="M602.2,151.2H704l77.7,379.9c9.5,47.4,18.1,95,26,142.6c7.9,47.6,15,97.6,21.4,149.8c0.7-6.8,1.3-12.1,1.7-16
<path fill="#C5C5C5" d="M316,1082.3H119.4V151.2h347.5v218.9H316v135.7h140.5v210.5H316V1082.3z"/>
<path fill="#C5C5C5" d="M602.2,151.2H704l77.7,379.9c9.5,47.4,18.1,95,26,142.6s15,97.6,21.4,149.8c0.7-6.8,1.3-12.1,1.7-16
c0.2-2.7,0.6-5.5,1.1-8.2l16.6-106.7l14.9-101.3l13.2-66.9l69.2-373.3h102.9l81.2,931.1h-113.6l-19.9-316c-0.8-16.1-1.4-29.9-2-41.6
c-0.6-11.7-0.9-21.3-0.9-29L988.3,571l-2.8-114.6c0-0.8,0-2.5-0.3-5.1s-0.5-6.1-0.9-10.6l-2.8,18.7c-3,22.1-5.8,41.4-8.3,57.9
c-2.5,16.5-4.7,30.3-6.6,41.6l-15.1,84.9l-5.7,32l-74.3,406.4h-80.1l-69.7-351c-9.5-46.2-17.9-93.1-25.4-140.8
c-7.5-47.7-14.2-97.6-20.3-149.9l-34.3,641.6H529.6L602.2,151.2z"/>
s-4.7,30.3-6.6,41.6l-15.1,84.9l-5.7,32l-74.3,406.4h-80.1l-69.7-351c-9.5-46.2-17.9-93.1-25.4-140.8s-14.2-97.6-20.3-149.9
l-34.3,641.6H529.6L602.2,151.2z"/>
<rect x="119.4" y="0.1" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="395.7" y="0.1" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="675.3" y="0.1" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="119.4" y="1184.7" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="395.7" y="1184.7" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="675.3" y="1184.7" fill="#C5C5C5" width="184" height="64.7"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -1 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1249.98 1249.98"><rect x="25" y="25" width="1199.98" height="1199.98" style="fill:none;stroke:#02aeb7;stroke-miterlimit:10;stroke-width:50px"/><path d="M171.89,489.56H95.38V127.21H230.6V212.4H171.89v52.8h54.68v81.91H171.89Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M461.79,489.56H379l-37.8-129.08c-.37-2.18-1-5.08-1.93-8.68s-2.05-7.9-3.39-12.91l.55,23.94V489.56H260.33V127.21h78.34q51.75,0,77.43,26.05,32.65,33.32,32.66,94.81,0,65.71-43.85,90.82ZM336.84,295H342q13.21,0,22-12.91t8.81-32.86q0-40.59-33.21-40.6h-2.75Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M691.68,309.56q0,82.85-29.54,134.71-29.35,51.63-76.51,51.63-41.82,0-71.74-39.66Q476.29,406,476.28,305.57q0-96.23,39.26-147.15,29.18-37.78,69.18-37.79,49,0,78,51.17T691.68,309.56Zm-79.44.7q0-98.32-27.16-98.33-13.58,0-21.65,25.81-7.89,23.94-7.89,70.41,0,45.77,7.43,71t20.65,25.23q13.57,0,20.91-24.88Q612.24,354.62,612.24,310.26Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M724.34,489.56V127.21h73l38.35,127.2q3.1,11.27,7.06,25.81t8.72,33.56l7.88,31.92Q855.17,298.52,853,265t-2.2-56.33V127.21h73V489.56h-73l-38.53-133.3q-6.06-21.35-10.92-40t-8.53-35.56q2.38,38.26,3.49,66.65t1.1,49.76v92.46Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M1062.31,489.56H985.8V214H943.6V127.21h162.56V214h-43.85Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M122.7,730.59h35.82l27.36,133.72q5,25.05,9.16,50.2t7.55,52.74q.39-3.6.6-5.62a25.33,25.33,0,0,1,.4-2.87l5.84-37.56,5.23-35.66L219.29,862l24.35-131.39h36.22l28.57,327.72h-40l-7-111.22q-.41-8.49-.71-14.64c-.2-4.11-.3-7.5-.3-10.19l-1.81-43.94-1-40.33c0-.28,0-.88-.1-1.8s-.17-2.16-.3-3.72l-1,6.58q-1.61,11.69-2.91,20.38t-2.32,14.65L245.65,904l-2,11.25-26.16,143.06H189.3L164.75,934.78q-5-24.4-8.95-49.56t-7.14-52.75l-12.08,225.84H97.14Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M395.56,730.59h32.6l66.6,327.72H453.31l-11.67-63.89H380.06l-11.87,63.89H327.94Zm40,229.66L426.35,908q-9.27-53.28-15.1-113.77Q408.43,823.78,404,854t-10.46,64.2l-7.65,42Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M496.17,730.59H632.4v38.63H585.51v289.09h-41V769.22H496.17Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M639,730.59H775.26v38.63H728.38v289.09h-41V769.22H639Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M806.65,730.59H917.93V768H848.5V871.74h61.58V909.1H848.5V1021h69.43v37.35H806.65Z" transform="translate(24 24)" style="fill:#02aeb7"/><path d="M964.61,730.59h55.13q34.21,0,50.91,17.19,21.13,22.29,21.13,68.14,0,35.24-11.16,56.56t-31.9,26.43l57.15,159.4h-42.46l-57-160.46v160.46H964.61Zm41.85,145.18q24.35,0,34.41-11.88t10.06-40.12a138.46,138.46,0,0,0-2.11-26.11q-2.11-10.81-6.64-17.61a27.08,27.08,0,0,0-11.67-10,41.58,41.58,0,0,0-17-3.18h-7Z" transform="translate(24 24)" style="fill:#02aeb7"/></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1249.98 1249.98"><rect x="25" y="25" width="1199.98" height="1199.98" style="fill:none;stroke:#000000;stroke-miterlimit:10;stroke-width:50px"/><path d="M171.89,489.56H95.38V127.21H230.6V212.4H171.89v52.8h54.68v81.91H171.89Z" transform="translate(24 24)" style="fill:#000000"/><path d="M461.79,489.56H379l-37.8-129.08c-.37-2.18-1-5.08-1.93-8.68s-2.05-7.9-3.39-12.91l.55,23.94V489.56H260.33V127.21h78.34q51.75,0,77.43,26.05,32.65,33.32,32.66,94.81,0,65.71-43.85,90.82ZM336.84,295H342q13.21,0,22-12.91t8.81-32.86q0-40.59-33.21-40.6h-2.75Z" transform="translate(24 24)" style="fill:#000000"/><path d="M691.68,309.56q0,82.85-29.54,134.71-29.35,51.63-76.51,51.63-41.82,0-71.74-39.66Q476.29,406,476.28,305.57q0-96.23,39.26-147.15,29.18-37.78,69.18-37.79,49,0,78,51.17T691.68,309.56Zm-79.44.7q0-98.32-27.16-98.33-13.58,0-21.65,25.81-7.89,23.94-7.89,70.41,0,45.77,7.43,71t20.65,25.23q13.57,0,20.91-24.88Q612.24,354.62,612.24,310.26Z" transform="translate(24 24)" style="fill:#000000"/><path d="M724.34,489.56V127.21h73l38.35,127.2q3.1,11.27,7.06,25.81t8.72,33.56l7.88,31.92Q855.17,298.52,853,265t-2.2-56.33V127.21h73V489.56h-73l-38.53-133.3q-6.06-21.35-10.92-40t-8.53-35.56q2.38,38.26,3.49,66.65t1.1,49.76v92.46Z" transform="translate(24 24)" style="fill:#000000"/><path d="M1062.31,489.56H985.8V214H943.6V127.21h162.56V214h-43.85Z" transform="translate(24 24)" style="fill:#000000"/><path d="M122.7,730.59h35.82l27.36,133.72q5,25.05,9.16,50.2t7.55,52.74q.39-3.6.6-5.62a25.33,25.33,0,0,1,.4-2.87l5.84-37.56,5.23-35.66L219.29,862l24.35-131.39h36.22l28.57,327.72h-40l-7-111.22q-.41-8.49-.71-14.64c-.2-4.11-.3-7.5-.3-10.19l-1.81-43.94-1-40.33c0-.28,0-.88-.1-1.8s-.17-2.16-.3-3.72l-1,6.58q-1.61,11.69-2.91,20.38t-2.32,14.65L245.65,904l-2,11.25-26.16,143.06H189.3L164.75,934.78q-5-24.4-8.95-49.56t-7.14-52.75l-12.08,225.84H97.14Z" transform="translate(24 24)" style="fill:#000000"/><path d="M395.56,730.59h32.6l66.6,327.72H453.31l-11.67-63.89H380.06l-11.87,63.89H327.94Zm40,229.66L426.35,908q-9.27-53.28-15.1-113.77Q408.43,823.78,404,854t-10.46,64.2l-7.65,42Z" transform="translate(24 24)" style="fill:#000000"/><path d="M496.17,730.59H632.4v38.63H585.51v289.09h-41V769.22H496.17Z" transform="translate(24 24)" style="fill:#000000"/><path d="M639,730.59H775.26v38.63H728.38v289.09h-41V769.22H639Z" transform="translate(24 24)" style="fill:#000000"/><path d="M806.65,730.59H917.93V768H848.5V871.74h61.58V909.1H848.5V1021h69.43v37.35H806.65Z" transform="translate(24 24)" style="fill:#000000"/><path d="M964.61,730.59h55.13q34.21,0,50.91,17.19,21.13,22.29,21.13,68.14,0,35.24-11.16,56.56t-31.9,26.43l57.15,159.4h-42.46l-57-160.46v160.46H964.61Zm41.85,145.18q24.35,0,34.41-11.88t10.06-40.12a138.46,138.46,0,0,0-2.11-26.11q-2.11-10.81-6.64-17.61a27.08,27.08,0,0,0-11.67-10,41.58,41.58,0,0,0-17-3.18h-7Z" transform="translate(24 24)" style="fill:#000000"/></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><path d="M4,11.4H2.2V2.9H5.4v2H4V6.1H5.3V8H4Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M10.9,11.4H9l-.9-3V8.2C8,8.1,8,8,7.9,7.8v3.6H6.1V2.9H8a2.88,2.88,0,0,1,1.9.6,3.11,3.11,0,0,1,.8,2.2A2.25,2.25,0,0,1,9.6,7.8ZM8,6.8h.1a.55.55,0,0,0,.5-.3,1.88,1.88,0,0,0,.2-.8c0-.6-.3-1-.8-1H8Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M16.5,7.2a6.08,6.08,0,0,1-.7,3.2A2.14,2.14,0,0,1,14,11.6a2.09,2.09,0,0,1-1.7-.9,5.84,5.84,0,0,1-.9-3.5,5.84,5.84,0,0,1,.9-3.5A2.09,2.09,0,0,1,14,2.8,2.16,2.16,0,0,1,15.9,4,8.24,8.24,0,0,1,16.5,7.2Zm-1.9,0c0-1.5-.2-2.3-.7-2.3-.2,0-.4.2-.5.6a6.53,6.53,0,0,0-.2,1.7,7.18,7.18,0,0,0,.2,1.7c.1.4.3.6.5.6s.4-.2.5-.6A7.93,7.93,0,0,0,14.6,7.2Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M17.2,11.4V2.9H19l.9,3c.1.1.1.3.2.6s.1.5.2.8l.2.7c-.1-.7-.1-1.4-.2-1.9a6.64,6.64,0,0,1-.1-1.3V2.9H22v8.5H20.3l-.9-3.1-.3-.9c-.1-.3-.1-.6-.2-.8,0,.6.1,1.1.1,1.6v3.4H17.2Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M25.3,11.4H23.5V4.9h-1v-2h3.9v2H25.3Z" transform="translate(1 1)" fill="#C5C5C5"/><rect x="1" y="1" width="28" height="28" fill="none" stroke="#C5C5C5" stroke-miterlimit="10" stroke-width="2"/><path d="M2.9,17h.9l.6,3a5,5,0,0,1,.2,1.2c.1.4.1.8.2,1.2v-.2l.2-.9.1-.8.1-.5.6-3h.9l.7,7.5h-1l-.2-2.6V19.5h0v.1a.9.9,0,0,1-.1.5c-.1.2,0,.2-.1.3l-.1.7v.3l-.6,3.3H4.5l-.6-2.8a5.16,5.16,0,0,1-.2-1.1c-.1-.4-.1-.8-.2-1.2l-.3,5.2h-1Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M9.3,17h.8l1.6,7.5h-1L10.4,23H8.9l-.3,1.5h-1Zm1,5.2L10,21c-.1-.8-.3-1.7-.4-2.6a6.75,6.75,0,0,1-.2,1.4l-.3,1.5-.2,1h1.4Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M11.5,17h3.3v.9H13.7v6.7h-1V17.9H11.5Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M14.8,17h3.3v.9H17v6.7H16V17.9H14.8Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M18.7,17h2.7v.9H19.7v2.4h1.5v.9H19.7v2.6h1.7v.9H18.7Z" transform="translate(1 1)" fill="#C5C5C5"/><path d="M22.3,17h1.3c.6,0,1,.1,1.2.4a2.35,2.35,0,0,1,.5,1.6,2.5,2.5,0,0,1-.3,1.3,1.24,1.24,0,0,1-.8.6l1.4,3.7h-1l-1.4-3.7v3.7h-1V17Zm1,3.3c.4,0,.7-.1.8-.3s.2-.5.2-.9a1.27,1.27,0,0,0-.1-.6c-.1-.2-.1-.3-.2-.4s-.2-.2-.3-.2-.3-.1-.4-.1h-.2v2.5Z" transform="translate(1 1)" fill="#C5C5C5"/></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><path d="M4,11.4H2.2V2.9H5.4v2H4V6.1H5.3V8H4Z" transform="translate(1 1)" fill="#424242"/><path d="M10.9,11.4H9l-.9-3V8.2C8,8.1,8,8,7.9,7.8v3.6H6.1V2.9H8a2.88,2.88,0,0,1,1.9.6,3.11,3.11,0,0,1,.8,2.2A2.25,2.25,0,0,1,9.6,7.8ZM8,6.8h.1a.55.55,0,0,0,.5-.3,1.88,1.88,0,0,0,.2-.8c0-.6-.3-1-.8-1H8Z" transform="translate(1 1)" fill="#424242"/><path d="M16.5,7.2a6.08,6.08,0,0,1-.7,3.2A2.14,2.14,0,0,1,14,11.6a2.09,2.09,0,0,1-1.7-.9,5.84,5.84,0,0,1-.9-3.5,5.84,5.84,0,0,1,.9-3.5A2.09,2.09,0,0,1,14,2.8,2.16,2.16,0,0,1,15.9,4,8.24,8.24,0,0,1,16.5,7.2Zm-1.9,0c0-1.5-.2-2.3-.7-2.3-.2,0-.4.2-.5.6a6.53,6.53,0,0,0-.2,1.7,7.18,7.18,0,0,0,.2,1.7c.1.4.3.6.5.6s.4-.2.5-.6A7.93,7.93,0,0,0,14.6,7.2Z" transform="translate(1 1)" fill="#424242"/><path d="M17.2,11.4V2.9H19l.9,3c.1.1.1.3.2.6s.1.5.2.8l.2.7c-.1-.7-.1-1.4-.2-1.9a6.64,6.64,0,0,1-.1-1.3V2.9H22v8.5H20.3l-.9-3.1-.3-.9c-.1-.3-.1-.6-.2-.8,0,.6.1,1.1.1,1.6v3.4H17.2Z" transform="translate(1 1)" fill="#424242"/><path d="M25.3,11.4H23.5V4.9h-1v-2h3.9v2H25.3Z" transform="translate(1 1)" fill="#424242"/><rect x="1" y="1" width="28" height="28" fill="none" stroke="#424242" stroke-miterlimit="10" stroke-width="2"/><path d="M2.9,17h.9l.6,3a5,5,0,0,1,.2,1.2c.1.4.1.8.2,1.2v-.2l.2-.9.1-.8.1-.5.6-3h.9l.7,7.5h-1l-.2-2.6V19.5h0v.1a.9.9,0,0,1-.1.5c-.1.2,0,.2-.1.3l-.1.7v.3l-.6,3.3H4.5l-.6-2.8a5.16,5.16,0,0,1-.2-1.1c-.1-.4-.1-.8-.2-1.2l-.3,5.2h-1Z" transform="translate(1 1)" fill="#424242"/><path d="M9.3,17h.8l1.6,7.5h-1L10.4,23H8.9l-.3,1.5h-1Zm1,5.2L10,21c-.1-.8-.3-1.7-.4-2.6a6.75,6.75,0,0,1-.2,1.4l-.3,1.5-.2,1h1.4Z" transform="translate(1 1)" fill="#424242"/><path d="M11.5,17h3.3v.9H13.7v6.7h-1V17.9H11.5Z" transform="translate(1 1)" fill="#424242"/><path d="M14.8,17h3.3v.9H17v6.7H16V17.9H14.8Z" transform="translate(1 1)" fill="#424242"/><path d="M18.7,17h2.7v.9H19.7v2.4h1.5v.9H19.7v2.6h1.7v.9H18.7Z" transform="translate(1 1)" fill="#424242"/><path d="M22.3,17h1.3c.6,0,1,.1,1.2.4a2.35,2.35,0,0,1,.5,1.6,2.5,2.5,0,0,1-.3,1.3,1.24,1.24,0,0,1-.8.6l1.4,3.7h-1l-1.4-3.7v3.7h-1V17Zm1,3.3c.4,0,.7-.1.8-.3s.2-.5.2-.9a1.27,1.27,0,0,0-.1-.6c-.1-.2-.1-.3-.2-.4s-.2-.2-.3-.2-.3-.1-.4-.1h-.2v2.5Z" transform="translate(1 1)" fill="#424242"/></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,12 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 26.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1250 1250" style="enable-background:new 0 0 1250 1250;" xml:space="preserve">
<rect x="25" y="25" fill="none" stroke="#ffffff" stroke-width="50" stroke-miterlimit="10" width="1200" height="1200"/>
<path fill="#ffffff" d="M316,1082.3H119.4V151.2h347.5v218.9H316v135.7h140.5v210.5H316V1082.3z"/>
<path fill="#ffffff" d="M602.2,151.2H704l77.7,379.9c9.5,47.4,18.1,95,26,142.6c7.9,47.6,15,97.6,21.4,149.8c0.7-6.8,1.3-12.1,1.7-16
<path fill="#C5C5C5" d="M316,1082.3H119.4V151.2h347.5v218.9H316v135.7h140.5v210.5H316V1082.3z"/>
<path fill="#C5C5C5" d="M602.2,151.2H704l77.7,379.9c9.5,47.4,18.1,95,26,142.6s15,97.6,21.4,149.8c0.7-6.8,1.3-12.1,1.7-16
c0.2-2.7,0.6-5.5,1.1-8.2l16.6-106.7l14.9-101.3l13.2-66.9l69.2-373.3h102.9l81.2,931.1h-113.6l-19.9-316c-0.8-16.1-1.4-29.9-2-41.6
c-0.6-11.7-0.9-21.3-0.9-29L988.3,571l-2.8-114.6c0-0.8,0-2.5-0.3-5.1s-0.5-6.1-0.9-10.6l-2.8,18.7c-3,22.1-5.8,41.4-8.3,57.9
c-2.5,16.5-4.7,30.3-6.6,41.6l-15.1,84.9l-5.7,32l-74.3,406.4h-80.1l-69.7-351c-9.5-46.2-17.9-93.1-25.4-140.8
c-7.5-47.7-14.2-97.6-20.3-149.9l-34.3,641.6H529.6L602.2,151.2z"/>
s-4.7,30.3-6.6,41.6l-15.1,84.9l-5.7,32l-74.3,406.4h-80.1l-69.7-351c-9.5-46.2-17.9-93.1-25.4-140.8s-14.2-97.6-20.3-149.9
l-34.3,641.6H529.6L602.2,151.2z"/>
<rect x="119.4" y="0.1" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="395.7" y="0.1" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="675.3" y="0.1" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="119.4" y="1184.7" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="395.7" y="1184.7" fill="#C5C5C5" width="184" height="64.7"/>
<rect x="675.3" y="1184.7" fill="#C5C5C5" width="184" height="64.7"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,12 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 26.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1250 1250" style="enable-background:new 0 0 1250 1250;" xml:space="preserve">
<rect x="25" y="25" fill="none" stroke="#424242" stroke-width="50" stroke-miterlimit="10" width="1200" height="1200"/>
<path fill="#424242" d="M316,1082.3H119.4V151.2h347.5v218.9H316v135.7h140.5v210.5H316V1082.3z"/>
<path fill="#424242" d="M602.2,151.2H704l77.7,379.9c9.5,47.4,18.1,95,26,142.6c7.9,47.6,15,97.6,21.4,149.8c0.7-6.8,1.3-12.1,1.7-16
<path fill="#424242" d="M602.2,151.2H704l77.7,379.9c9.5,47.4,18.1,95,26,142.6s15,97.6,21.4,149.8c0.7-6.8,1.3-12.1,1.7-16
c0.2-2.7,0.6-5.5,1.1-8.2l16.6-106.7l14.9-101.3l13.2-66.9l69.2-373.3h102.9l81.2,931.1h-113.6l-19.9-316c-0.8-16.1-1.4-29.9-2-41.6
c-0.6-11.7-0.9-21.3-0.9-29L988.3,571l-2.8-114.6c0-0.8,0-2.5-0.3-5.1s-0.5-6.1-0.9-10.6l-2.8,18.7c-3,22.1-5.8,41.4-8.3,57.9
c-2.5,16.5-4.7,30.3-6.6,41.6l-15.1,84.9l-5.7,32l-74.3,406.4h-80.1l-69.7-351c-9.5-46.2-17.9-93.1-25.4-140.8
c-7.5-47.7-14.2-97.6-20.3-149.9l-34.3,641.6H529.6L602.2,151.2z"/>
s-4.7,30.3-6.6,41.6l-15.1,84.9l-5.7,32l-74.3,406.4h-80.1l-69.7-351c-9.5-46.2-17.9-93.1-25.4-140.8s-14.2-97.6-20.3-149.9
l-34.3,641.6H529.6L602.2,151.2z"/>
<rect x="119.4" y="0.1" fill="#424242" width="184" height="64.7"/>
<rect x="395.7" y="0.1" fill="#424242" width="184" height="64.7"/>
<rect x="675.3" y="0.1" fill="#424242" width="184" height="64.7"/>
<rect x="119.4" y="1184.7" fill="#424242" width="184" height="64.7"/>
<rect x="395.7" y="1184.7" fill="#424242" width="184" height="64.7"/>
<rect x="675.3" y="1184.7" fill="#424242" width="184" height="64.7"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -8,4 +8,4 @@
c-0.6-11.7-0.9-21.3-0.9-29L988.3,571l-2.8-114.6c0-0.8,0-2.5-0.3-5.1s-0.5-6.1-0.9-10.6l-2.8,18.7c-3,22.1-5.8,41.4-8.3,57.9
c-2.5,16.5-4.7,30.3-6.6,41.6l-15.1,84.9l-5.7,32l-74.3,406.4h-80.1l-69.7-351c-9.5-46.2-17.9-93.1-25.4-140.8
c-7.5-47.7-14.2-97.6-20.3-149.9l-34.3,641.6H529.6L602.2,151.2z"/>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="#C5C5C5" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M14.121 14.121L19 19m-7-7l7-7m-7 7l-2.879 2.879M12 12L9.121 9.121m0 5.758a3 3 0 10-4.243 4.243 3 3 0 004.243-4.243zm0-5.758a3 3 0 10-4.243-4.243 3 3 0 004.243 4.243z" />
</svg>

After

Width:  |  Height:  |  Size: 357 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="#424242" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M14.121 14.121L19 19m-7-7l7-7m-7 7l-2.879 2.879M12 12L9.121 9.121m0 5.758a3 3 0 10-4.243 4.243 3 3 0 004.243-4.243zm0-5.758a3 3 0 10-4.243-4.243 3 3 0 004.243 4.243z" />
</svg>

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

View File

@@ -143,11 +143,13 @@
}
.article__tags {
/* position: relative; */
margin-bottom: 1rem;
}
.article__tags__dropbox {
width: 90%;
/* Minus the twice the padding */
width: calc(100% - 2.5rem);
margin: 0;
padding: 0;
z-index: 1;
@@ -165,22 +167,27 @@
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: 1px;
top: 1px;
right: 1px;
bottom: 0;
top: 0;
right: 0;
width: 30px;
padding-bottom: 2px;
padding-top: 2px;
display: inline-flex;
align-items: center;
justify-content: center;
@@ -214,60 +221,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 > * + *,
@@ -348,6 +301,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;
}
@@ -446,12 +404,33 @@ input:checked + .field__toggle__slider:before {
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;
}
@@ -611,18 +590,21 @@ input:checked + .field__toggle__slider:before {
max-height: 16rem;
}
.metadata_field__file__button,
.metadata_field__preview_image__button {
background-color: transparent;
border: 2px dashed var(--vscode-button-background);
border: 1px dashed var(--vscode-button-background);
padding: 1.5rem;
filter: brightness(85%);
}
.metadata_field__file__button:hover,
.metadata_field__preview_image__button:hover {
background-color: rgba(255, 255, 255, .1);
filter: brightness(100%);
}
.metadata_field__file__button svg,
.metadata_field__preview_image__button svg {
color: var(--vscode-foreground);
display: block;
@@ -631,6 +613,7 @@ input:checked + .field__toggle__slider:before {
margin: 0 auto;
}
.metadata_field__file__button span,
.metadata_field__preview_image__button span {
color: var(--vscode-foreground);
display: inline-block;
@@ -638,6 +621,14 @@ input:checked + .field__toggle__slider:before {
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;
@@ -737,8 +728,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 {

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

View File

@@ -0,0 +1,3 @@
## Documentation
Our documentation can be found at: [https://frontmatter.codes/docs](https://frontmatter.codes/docs)

View File

@@ -0,0 +1,11 @@
## Getting started
Thanks for installing Front Matter!
To get started, open our dashboard which will guide you through the initialization process of your project.
When you haven't initialized your project yet, you will see the Front Matter's welcome screen on which you will have to perform the following steps:
- Project initialization
- Content folders registration
- Framework initialization

View File

@@ -0,0 +1,8 @@
## Support the project
Front Matter is an open source project and we are always looking for new contributors, supporters, and partners. If you are interested in backing the project, please consider supporting it by donating. You can donate at via the following links:
- [GitHub Sponsors](https://github.com/sponsors/estruyf)
- [Open Collective](https://opencollective.com/frontmatter)
> Each sponsor/backer will be mentioned on the [Front Matter](https://frontmatter.codes) website and on the [GitHub repository](https://github.com/estruyf/vscode-front-matter).

77
frontmatter.json Normal file
View File

@@ -0,0 +1,77 @@
{
"$schema": "https://beta.frontmatter.codes/frontmatter.schema.json",
"frontMatter.framework.id": "other",
"frontMatter.content.publicFolder": "",
"frontMatter.content.pageFolders": [
{
"title": ".vscode",
"path": "[[workspace]]/.vscode"
}
],
"frontMatter.content.snippets": {
"New version": {
"description": "Insert a new version to the changelog",
"body": [
"## [{{version}}] - {{year}}-{{month}}-{{day}}",
"",
"### ✨ New features",
"",
"### 🎨 Enhancements",
"",
"### ⚡️ Optimizations",
"",
"### 🐞 Fixes"
],
"fields": [
{
"type": "string",
"name": "version",
"title": "Version",
"single": true
},
{
"type": "string",
"name": "year",
"title": "Year",
"default": "2022"
},
{
"type": "string",
"name": "month",
"title": "Month",
"default": "xx"
},
{
"type": "string",
"name": "day",
"title": "Day",
"default": "xx"
}
],
"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": "}}"
}
}
}

13348
package-lock.json generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@ const tailwindcss = require('tailwindcss');
module.exports = {
plugins: [
require('postcss-nested'),
tailwindcss('./tailwind.config.js'),
require('autoprefixer'),
],

View File

@@ -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('.');
@@ -14,7 +15,24 @@ packageJson.homepage = "https://beta.frontmatter.codes";
console.log(packageJson.version);
core.summary.addHeading(`Version info`).addDetails(`${packageJson.version}`);
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);

View File

@@ -1,22 +1,24 @@
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 } from './../constants';
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 * as vscode from 'vscode';
import { TaxonomyType } from "../models";
import { Field, TaxonomyType } from "../models";
import { format } from "date-fns";
import { ArticleHelper, Settings, SlugHelper } from '../helpers';
import matter = require('gray-matter');
import { Notifications } from '../helpers/Notifications';
import { extname, basename, parse, dirname } from 'path';
import { COMMAND_NAME, DefaultFields } from '../constants';
import { DashboardData } from '../models/DashboardData';
import { ExplorerView } from '../explorerView/ExplorerView';
import { DateHelper } from '../helpers/DateHelper';
import { parseWinPath } from '../helpers/parseWinPath';
import { Telemetry } from '../helpers/Telemetry';
import { ParsedFrontMatter } from '../parsers';
import { MediaListener } from '../listeners/panel';
import { NavigationType } from '../dashboardWebView/models';
import { processKnownPlaceholders } from '../helpers/PlaceholderHelper';
export class Article {
private static prevContent = "";
/**
* Insert taxonomy
*
@@ -28,7 +30,7 @@ export class Article {
return;
}
const article = Article.getCurrent();
const article = ArticleHelper.getCurrent();
if (!article) {
return;
@@ -67,7 +69,8 @@ export class Article {
const selectedOptions = await vscode.window.showQuickPick(options, {
placeHolder: `Select your ${type === TaxonomyType.Tag ? "tags" : "categories"} to insert`,
canPickMany: true
canPickMany: true,
ignoreFocusOut: true
});
if (selectedOptions) {
@@ -104,7 +107,7 @@ export class Article {
* Update the date in the front matter
* @param article
*/
public static updateDate(article: matter.GrayMatterFile<string>, forceCreate: boolean = false) {
public static updateDate(article: ParsedFrontMatter, forceCreate: boolean = false) {
article.data = ArticleHelper.updateDates(article.data);
return article;
}
@@ -118,17 +121,47 @@ export class Article {
return;
}
const article = ArticleHelper.getFrontMatter(editor);
if (!article) {
const updatedArticle = this.setLastModifiedDateInner(editor.document);
if (typeof updatedArticle === "undefined") {
return;
}
ArticleHelper.update(
editor,
updatedArticle as ParsedFrontMatter
);
}
public static async setLastModifiedDateOnSave(
document: vscode.TextDocument
): Promise<vscode.TextEdit[]> {
const updatedArticle = this.setLastModifiedDateInner(document);
if (typeof updatedArticle === "undefined") {
return [];
}
const update = ArticleHelper.generateUpdate(document, updatedArticle);
return [update];
}
private static setLastModifiedDateInner(
document: vscode.TextDocument
): ParsedFrontMatter | undefined {
const article = ArticleHelper.getFrontMatterFromDocument(document);
// Only set the date, if there is already front matter set
if (!article || !article.data || Object.keys(article.data).length === 0) {
return;
}
const cloneArticle = Object.assign({}, article);
const dateField = Settings.get(SETTING_MODIFIED_FIELD) as string || DefaultFields.LastModified;
const dateField = ArticleHelper.getModifiedDateField(article) || DefaultFields.LastModified;
try {
cloneArticle.data[dateField] = Article.formatDate(new Date());
ArticleHelper.update(editor, cloneArticle);
return cloneArticle;
} catch (e: any) {
Notifications.error(`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`);
}
@@ -138,6 +171,8 @@ export class Article {
* 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;
const updateFileName = Settings.get(SETTING_SLUG_UPDATE_FILE_NAME) as string;
@@ -153,11 +188,35 @@ export class Article {
return;
}
const articleTitle: string = article.data["title"];
let slug = SlugHelper.createSlug(articleTitle);
const contentType = ArticleHelper.getContentType(article.data);
const titleField = "title";
const articleTitle: string = article.data[titleField];
const slug = SlugHelper.createSlug(articleTitle);
if (slug) {
slug = `${prefix}${slug}${suffix}`;
article.data["slug"] = slug;
let slugFieldValue = `${prefix}${slug}${suffix}`;
article.data["slug"] = slugFieldValue;
if (contentType) {
// Update the fields containing the slug placeholder
let fieldsToUpdate: Field[] = contentType.fields.filter(f => f.default === "{{slug}}");
for (const field of fieldsToUpdate) {
article.data[field.name] = 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 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 pField of customPlaceholderFields) {
article.data[pField.name] = customPlaceholder.value;
article.data[pField.name] = processKnownPlaceholders(article.data[pField.name], articleTitle, dateFormat);
}
}
}
ArticleHelper.update(editor, article);
// Check if the file name should be updated by the slug
@@ -203,7 +262,7 @@ export class Article {
const file = parseWinPath(editor.document.fileName);
if (!file.endsWith(`.md`) && !file.endsWith(`.markdown`) && !file.endsWith(`.mdx`)) {
if (!isValidFile(file)) {
return;
}
@@ -237,30 +296,17 @@ export class Article {
/**
* Article auto updater
* @param fileChanges
* @param event
*/
public static async autoUpdate(fileChanges: vscode.TextDocumentChangeEvent) {
const txtChanges = fileChanges.contentChanges.map(c => c.text);
const editor = vscode.window.activeTextEditor;
public static async autoUpdate(event: vscode.TextDocumentWillSaveEvent) {
const document = event.document;
if (document && ArticleHelper.isSupportedFile(document)) {
const autoUpdate = Settings.get(SETTING_AUTO_UPDATE_DATE);
if (txtChanges.length > 0 && editor && ArticleHelper.isMarkdownFile()) {
const autoUpdate = Settings.get(SETTING_AUTO_UPDATE_DATE);
if (autoUpdate) {
const article = ArticleHelper.getFrontMatter(editor);
if (!article) {
return;
}
if (article.content === Article.prevContent) {
return;
}
Article.prevContent = article.content;
Article.setLastModifiedDate();
if (autoUpdate) {
event.waitUntil(Article.setLastModifiedDateOnSave(document));
}
}
}
}
/**
@@ -279,17 +325,21 @@ export class Article {
/**
* Insert an image from the media dashboard into the article
*/
public static async insertImage() {
public static async insertMedia() {
let 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 position = editor.selection.active;
await vscode.commands.executeCommand(COMMAND_NAME.dashboard, {
type: "media",
data: {
pageBundle: !!contentType.pageBundle,
filePath: editor.document.uri.fsPath,
fieldName: basename(editor.document.uri.fsPath),
position
@@ -297,25 +347,34 @@ export class Article {
} as DashboardData);
// Let the editor panel know you are selecting an image
ExplorerView.getInstance().getMediaSelection();
MediaListener.getMediaSelection();
}
/**
* Get the current article
* Insert a snippet into the article
*/
private static getCurrent(): matter.GrayMatterFile<string> | undefined {
const editor = vscode.window.activeTextEditor;
public static async insertSnippet() {
let editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const article = ArticleHelper.getFrontMatter(editor);
if (!article) {
return;
}
const position = editor.selection.active;
const selectionText = editor.document.getText(editor.selection);
return article;
}
const article = ArticleHelper.getFrontMatter(editor);
await vscode.commands.executeCommand(COMMAND_NAME.dashboard, {
type: NavigationType.Snippets,
data: {
fileTitle: article?.data.title || "",
filePath: editor.document.uri.fsPath,
fieldName: basename(editor.document.uri.fsPath),
position,
selection: selectionText
}
} as DashboardData);
}
/**
* Update the article date and return it
@@ -324,7 +383,7 @@ export class Article {
* @param field
* @param forceCreate
*/
private static articleDate(article: matter.GrayMatterFile<string>, field: string, forceCreate: boolean) {
private static articleDate(article: ParsedFrontMatter, field: string, forceCreate: boolean) {
if (typeof article.data[field] !== "undefined" || forceCreate) {
article.data[field] = Article.formatDate(new Date());
}

75
src/commands/Backers.ts Normal file
View File

@@ -0,0 +1,75 @@
import { commands, ExtensionContext } from 'vscode';
import { CONTEXT } from '../constants';
import { Extension } from '../helpers';
import { Credentials } from "../services/Credentials";
import fetch from "node-fetch";
import { ExplorerView } from '../explorerView/ExplorerView';
import { Dashboard } from './Dashboard';
import { SettingsListener } from '../listeners/panel';
export class Backers {
private static creds: Credentials | null = null;
public static async init(context: ExtensionContext) {
Backers.creds = new Credentials();
await Backers.creds.initialize(context, Backers.tryUsernameCheck);
Backers.tryUsernameCheck();
context.subscriptions.push(
commands.registerCommand('frontMatter.authenticate', async () => {
Backers.tryUsernameCheck();
})
);
}
public static async tryUsernameCheck() {
try {
const username = await Backers.getUsername();
Backers.validate(username || "");
} catch (e) {
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;
}
return;
}
public static async validate(username: string) {
const ext = Extension.getInstance();
if (!username) {
ext.setState(CONTEXT.backer, undefined, 'global');
}
const isBeta = ext.isBetaVersion();
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');
await ext.setState(CONTEXT.backer, true, 'global');
if (!prevData) {
const explorerView = ExplorerView.getInstance();
if (explorerView.visible) {
SettingsListener.getSettings();
}
if (Dashboard.isOpen) {
Dashboard.reload();
}
}
} else {
ext.setState(CONTEXT.backer, false, 'global');
}
}
}

View File

@@ -1,9 +1,14 @@
import { commands, QuickPickItem, window } from 'vscode';
import { COMMAND_NAME } from '../constants';
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);
}
const options: QuickPickItem[] = [{
label: "Create content by content type",
@@ -15,7 +20,8 @@ export class Content {
const selectedOption = await window.showQuickPick(options, {
placeHolder: `Select how you want to create your new content`,
canPickMany: false
canPickMany: false,
ignoreFocusOut: true
});
if (selectedOption) {

View File

@@ -1,42 +1,20 @@
import { SETTINGS_CONTENT_STATIC_FOLDER, SETTING_DATE_FIELD, SETTING_SEO_DESCRIPTION_FIELD, SETTINGS_DASHBOARD_OPENONSTART, SETTINGS_DASHBOARD_MEDIA_SNIPPET, SETTING_TAXONOMY_CONTENT_TYPES, DefaultFields, HOME_PAGE_NAVIGATION_ID, ExtensionState, COMMAND_NAME, SETTINGS_FRAMEWORK_ID, SETTINGS_CONTENT_DRAFT_FIELD, SETTINGS_CONTENT_SORTING, CONTEXT, SETTING_CUSTOM_SCRIPTS, SETTINGS_CONTENT_SORTING_DEFAULT, SETTINGS_MEDIA_SORTING_DEFAULT } from '../constants';
import { ArticleHelper } from './../helpers/ArticleHelper';
import { basename, dirname, extname, join, parse } from "path";
import { existsSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs";
import { commands, Uri, ViewColumn, Webview, WebviewPanel, window, workspace, env, Position } from "vscode";
import { Settings as SettingsHelper } from '../helpers';
import { CustomScript as ICustomScript, DraftField, Framework, ScriptType, SortingSetting, SortOrder, SortType, TaxonomyType } from '../models';
import { Folders } from './Folders';
import { SETTING_DASHBOARD_OPENONSTART, CONTEXT } 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 { DashboardMessage } from '../dashboardWebView/DashboardMessage';
import { Page } from '../dashboardWebView/models/Page';
import { openFileInEditor } from '../helpers/openFileInEditor';
import { Template } from './Template';
import { Notifications } from '../helpers/Notifications';
import { Settings } from '../dashboardWebView/models/Settings';
import { Extension } from '../helpers/Extension';
import { ViewType } from '../dashboardWebView/state';
import { EditorHelper, WebviewHelper } from '@estruyf/vscode';
import { MediaInfo, MediaPaths } from './../models/MediaPaths';
import { decodeBase64Image } from '../helpers/decodeBase64Image';
import { WebviewHelper } from '@estruyf/vscode';
import { DashboardData } from '../models/DashboardData';
import { ExplorerView } from '../explorerView/ExplorerView';
import { MediaLibrary } from '../helpers/MediaLibrary';
import { parseWinPath } from '../helpers/parseWinPath';
import { DateHelper } from '../helpers/DateHelper';
import { FrameworkDetector } from '../helpers/FrameworkDetector';
import { ContentType } from '../helpers/ContentType';
import { SortingOption } from '../dashboardWebView/models';
import { Sorting } from '../helpers/Sorting';
import imageSize from 'image-size';
import { CustomScript } from '../helpers/CustomScript';
import { DashboardListener, MediaListener, SettingsListener, TelemetryListener, DataListener, PagesListener, ExtensionListener, SnippetListener } from '../listeners/dashboard';
import { MediaListener as PanelMediaListener } from '../listeners/panel'
import { ModeListener } from '../listeners/general';
export class Dashboard {
private static webview: WebviewPanel | null = null;
private static isDisposed: boolean = true;
private static media: MediaInfo[] = [];
private static timers: { [folder: string]: any } = {};
private static _viewData: DashboardData | undefined;
private static mediaLib: MediaLibrary;
private static isDisposed: boolean = true;
public static get viewData(): DashboardData | undefined {
return Dashboard._viewData;
@@ -46,7 +24,7 @@ export class Dashboard {
* Init the dashboard
*/
public static async init() {
const openOnStartup = SettingsHelper.get(SETTINGS_DASHBOARD_OPENONSTART);
const openOnStartup = SettingsHelper.get(SETTING_DASHBOARD_OPENONSTART);
if (openOnStartup) {
Dashboard.open();
}
@@ -56,12 +34,12 @@ export class Dashboard {
* Open or reveal the dashboard
*/
public static async open(data?: DashboardData) {
this.mediaLib = MediaLibrary.getInstance();
MediaLibrary.getInstance();
Dashboard._viewData = data;
if (Dashboard.isOpen) {
Dashboard.reveal();
Dashboard.reveal(!!data);
} else {
Dashboard.create();
}
@@ -79,15 +57,33 @@ export class Dashboard {
/**
* Reveal the dashboard if it is open
*/
public static reveal() {
public static reveal(hasData: boolean = false) {
if (Dashboard.webview) {
Dashboard.webview.reveal();
if (hasData) {
Dashboard.postWebviewMessage({ command: DashboardCommand.viewData, data: Dashboard.viewData });
}
}
}
public static close() {
Dashboard.webview?.dispose();
}
public static reload() {
if (Dashboard.isOpen) {
Dashboard.webview?.dispose();
setTimeout(() => {
Dashboard.open();
}, 100);
}
}
public static resetViewData() {
Dashboard._viewData = undefined;
}
/**
* Create the dashboard webview
@@ -101,7 +97,8 @@ export class Dashboard {
'FrontMatter Dashboard',
ViewColumn.One,
{
enableScripts: true
enableScripts: true,
retainContextWhenHidden: true
}
);
@@ -117,8 +114,9 @@ export class Dashboard {
Dashboard.webview.onDidChangeViewState(async () => {
if (!this.webview?.visible) {
Dashboard._viewData = undefined;
const panel = ExplorerView.getInstance(extensionUri);
panel.getMediaSelection();
PanelMediaListener.getMediaSelection();
Dashboard.postWebviewMessage({ command: DashboardCommand.viewData, data: null });
}
await commands.executeCommand('setContext', CONTEXT.isDashboardOpen, this.webview?.visible);
@@ -127,105 +125,35 @@ export class Dashboard {
Dashboard.webview.onDidDispose(async () => {
Dashboard.isDisposed = true;
Dashboard._viewData = undefined;
const panel = ExplorerView.getInstance(extensionUri);
panel.getMediaSelection();
PanelMediaListener.getMediaSelection();
await commands.executeCommand('setContext', CONTEXT.isDashboardOpen, false);
});
SettingsHelper.onConfigChange((global?: any) => {
Dashboard.getSettings();
SettingsListener.getSettings();
});
Dashboard.webview.webview.onDidReceiveMessage(async (msg) => {
switch(msg.command) {
case DashboardMessage.getViewType:
if (Dashboard._viewData) {
Dashboard.postWebviewMessage({ command: DashboardCommand.viewData, data: Dashboard._viewData });
}
break;
case DashboardMessage.getData:
Dashboard.getSettings();
Dashboard.getPages();
break;
case DashboardMessage.openFile:
openFileInEditor(msg.data);
break;
case DashboardMessage.createContent:
await commands.executeCommand(COMMAND_NAME.createContent);
break;
case DashboardMessage.createByContentType:
await commands.executeCommand(COMMAND_NAME.createByContentType);
break;
case DashboardMessage.createByTemplate:
await commands.executeCommand(COMMAND_NAME.createByTemplate);
break;
case DashboardMessage.updateSetting:
Dashboard.updateSetting(msg.data);
break;
case DashboardMessage.initializeProject:
await commands.executeCommand(COMMAND_NAME.init, Dashboard.getSettings);
break;
case DashboardMessage.reload:
if (!Dashboard.isDisposed) {
Dashboard.webview?.dispose();
setTimeout(() => {
Dashboard.open();
}, 100);
}
break;
case DashboardMessage.setPageViewType:
Extension.getInstance().setState(ExtensionState.PagesView, msg.data, "workspace");
break;
case DashboardMessage.getMedia:
Dashboard.getMedia(msg?.data?.page, msg?.data?.folder, msg?.data?.sorting);
break;
case DashboardMessage.copyToClipboard:
env.clipboard.writeText(msg.data);
break;
case DashboardMessage.refreshMedia:
Dashboard.resetMedia();
Dashboard.getMedia(0, msg?.data?.folder);
break;
case DashboardMessage.uploadMedia:
Dashboard.saveFile(msg?.data);
break;
case DashboardMessage.deleteMedia:
Dashboard.deleteFile(msg?.data);
break;
case DashboardMessage.insertPreviewImage:
Dashboard.insertImage(msg?.data);
break;
case DashboardMessage.updateMediaMetadata:
Dashboard.updateMediaMetadata(msg?.data);
break;
case DashboardMessage.createMediaFolder:
await commands.executeCommand(COMMAND_NAME.createFolder, msg?.data);
break;
case DashboardMessage.setFramework:
Dashboard.setFramework(msg?.data);
break;
case DashboardMessage.runCustomScript:
CustomScript.run(msg?.data?.script, msg?.data?.path);
break;
case DashboardMessage.setState:
if (msg?.data?.key && msg?.data?.value) {
Extension.getInstance().setState(msg?.data?.key, msg?.data?.value, "workspace");
}
break;
}
Logger.info(`Receiving message from webview: ${msg.command}`);
DashboardListener.process(msg);
ExtensionListener.process(msg);
MediaListener.process(msg);
PagesListener.process(msg);
SettingsListener.process(msg);
DataListener.process(msg);
TelemetryListener.process(msg);
SnippetListener.process(msg);
ModeListener.process(msg);
});
}
/**
* Reset media array
* Return the webview
* @returns The webview
*/
public static resetMedia() {
Dashboard.media = [];
}
public static switchFolder(folderPath: string) {
Dashboard.resetMedia();
Dashboard.getMedia(0, folderPath);
public static getWebview() {
return Dashboard.webview?.webview;
}
/**
@@ -242,483 +170,22 @@ export class Dashboard {
}
}
/**
* Insert an image into the front matter or contents
* @param data
*/
private static async insertImage(data: any) {
if (data?.file && data?.image) {
if (!data?.position) {
await commands.executeCommand(`workbench.view.extension.frontmatter-explorer`);
}
await EditorHelper.showFile(data.file);
Dashboard._viewData = undefined;
const extensionUri = Extension.getInstance().extensionPath;
const panel = ExplorerView.getInstance(extensionUri);
if (data?.position) {
const wsFolder = Folders.getWorkspaceFolder();
const editor = window.activeTextEditor;
const line = data.position.line;
const character = data.position.character;
if (line) {
let imgPath = data.image;
const filePath = data.file;
const absImgPath = join(parseWinPath(wsFolder?.fsPath || ""), imgPath);
const imgDir = dirname(absImgPath);
const fileDir = dirname(filePath);
if (imgDir === fileDir) {
imgPath = join('/', basename(imgPath));
// Snippets are already parsed, so update the URL of the image
if (data.snippet) {
data.snippet = data.snippet.replace(data.image, imgPath);
}
}
await editor?.edit(builder => builder.insert(new Position(line, character), data.snippet || `![${data.alt || data.caption || ""}](${imgPath})`));
}
panel.getMediaSelection();
} else {
panel.getMediaSelection();
panel.updateMetadata({field: data.fieldName, value: data.image });
}
}
}
/**
* Retrieve the settings for the dashboard
*/
private static async getSettings() {
const ext = Extension.getInstance();
const wsFolder = Folders.getWorkspaceFolder();
const isInitialized = await Template.isInitialized();
Dashboard.postWebviewMessage({
command: DashboardCommand.settings,
data: {
beta: ext.isBetaVersion(),
wsFolder: wsFolder ? wsFolder.fsPath : '',
staticFolder: SettingsHelper.get<string>(SETTINGS_CONTENT_STATIC_FOLDER),
folders: Folders.get(),
initialized: isInitialized,
tags: SettingsHelper.getTaxonomy(TaxonomyType.Tag),
categories: SettingsHelper.getTaxonomy(TaxonomyType.Category),
openOnStart: SettingsHelper.get(SETTINGS_DASHBOARD_OPENONSTART),
versionInfo: ext.getVersion(),
pageViewType: await ext.getState<ViewType | undefined>(ExtensionState.PagesView, "workspace"),
mediaSnippet: SettingsHelper.get<string[]>(SETTINGS_DASHBOARD_MEDIA_SNIPPET) || [],
contentTypes: SettingsHelper.get(SETTING_TAXONOMY_CONTENT_TYPES) || [],
draftField: SettingsHelper.get<DraftField>(SETTINGS_CONTENT_DRAFT_FIELD),
customSorting: SettingsHelper.get<SortingSetting[]>(SETTINGS_CONTENT_SORTING),
contentFolders: Folders.get(),
crntFramework: SettingsHelper.get<string>(SETTINGS_FRAMEWORK_ID),
framework: (!isInitialized && wsFolder) ? FrameworkDetector.get(wsFolder.fsPath) : null,
scripts: (SettingsHelper.get<ICustomScript[]>(SETTING_CUSTOM_SCRIPTS) || []).filter(s => s.type && s.type !== ScriptType.Content),
dashboardState: {
contents: {
sorting: await ext.getState<SortingOption | undefined>(ExtensionState.Dashboard.Contents.Sorting, "workspace"),
defaultSorting: SettingsHelper.get<string>(SETTINGS_CONTENT_SORTING_DEFAULT)
},
media: {
sorting: await ext.getState<SortingOption | undefined>(ExtensionState.Dashboard.Media.Sorting, "workspace"),
defaultSorting: SettingsHelper.get<string>(SETTINGS_MEDIA_SORTING_DEFAULT)
}
}
} as Settings
});
}
/**
* Set the current site-generator or framework + related settings
* @param frameworkId
*/
private static setFramework(frameworkId: string | null) {
SettingsHelper.update(SETTINGS_FRAMEWORK_ID, frameworkId, true);
if (frameworkId) {
const allFrameworks = FrameworkDetector.getAll();
const framework = allFrameworks.find((f: Framework) => f.name === frameworkId);
if (framework) {
SettingsHelper.update(SETTINGS_CONTENT_STATIC_FOLDER, framework.static, true);
} else {
SettingsHelper.update(SETTINGS_CONTENT_STATIC_FOLDER, "", true);
}
}
}
/**
* Update a setting from the dashboard
*/
private static async updateSetting(data: { name: string, value: any }) {
await SettingsHelper.update(data.name, data.value);
Dashboard.getSettings();
}
/**
* Retrieve all media files
*/
private static async getMedia(page: number = 0, requestedFolder: string = '', sort: SortingOption | null = null) {
const wsFolder = Folders.getWorkspaceFolder();
const staticFolder = SettingsHelper.get<string>(SETTINGS_CONTENT_STATIC_FOLDER);
const contentFolders = Folders.get();
const viewData = Dashboard.viewData;
let selectedFolder = requestedFolder;
const ext = Extension.getInstance();
const crntSort = sort === null ? await ext.getState<SortingOption | undefined>(ExtensionState.Dashboard.Media.Sorting, "workspace") : sort;
// If the static folder is not set, retreive the last opened location
if (!selectedFolder) {
const stateValue = await ext.getState<string | undefined>(ExtensionState.SelectedFolder, "workspace");
if (stateValue !== HOME_PAGE_NAVIGATION_ID) {
// Support for page bundles
if (viewData?.data?.filePath && viewData?.data?.filePath.endsWith('index.md')) {
const folderPath = parse(viewData.data.filePath).dir;
selectedFolder = folderPath;
} else if (stateValue && existsSync(stateValue)) {
selectedFolder = stateValue;
}
}
}
// Go to the home folder
if (selectedFolder === HOME_PAGE_NAVIGATION_ID) {
selectedFolder = '';
}
let relSelectedFolderPath = selectedFolder;
const parsedPath = parseWinPath(wsFolder?.fsPath || "");
if (selectedFolder && selectedFolder.startsWith(parsedPath)) {
relSelectedFolderPath = selectedFolder.replace(parsedPath, '');
}
if (relSelectedFolderPath.startsWith('/')) {
relSelectedFolderPath = relSelectedFolderPath.substring(1);
}
let allMedia: MediaInfo[] = [];
if (relSelectedFolderPath) {
const files = await workspace.findFiles(join(relSelectedFolderPath, '/*'));
const media = await Dashboard.updateMediaData(Dashboard.filterMedia(files));
allMedia = [...media];
} else {
if (staticFolder) {
const folderSearch = join(staticFolder || "", '/*');
const files = await workspace.findFiles(folderSearch);
const media = await Dashboard.updateMediaData(Dashboard.filterMedia(files));
allMedia = [...media];
}
if (contentFolders && wsFolder) {
for (let i = 0; i < contentFolders.length; i++) {
const contentFolder = contentFolders[i];
const relFolderPath = contentFolder.path.substring(wsFolder.fsPath.length + 1);
const folderSearch = relSelectedFolderPath ? join(relSelectedFolderPath, '/*') : join(relFolderPath, '/*');
const files = await workspace.findFiles(folderSearch);
const media = await Dashboard.updateMediaData(Dashboard.filterMedia(files));
allMedia = [...allMedia, ...media];
}
}
}
if (crntSort?.type === SortType.string) {
allMedia = allMedia.sort(Sorting.alphabetically("fsPath"));
} else if (crntSort?.type === SortType.date) {
allMedia = allMedia.sort(Sorting.dateWithFallback("mtime", "fsPath"));
} else {
allMedia = allMedia.sort(Sorting.alphabetically("fsPath"));
}
if (crntSort?.order === SortOrder.desc) {
allMedia = allMedia.reverse();
}
Dashboard.media = Object.assign([], allMedia);
let files: MediaInfo[] = Dashboard.media;
// Retrieve the total after filtering and before the slicing happens
const total = files.length;
// Get media set
files = files.slice(page * 16, ((page + 1) * 16));
files = files.map((file) => {
try {
const metadata = Dashboard.mediaLib.get(file.fsPath);
return {
...file,
dimensions: imageSize(file.fsPath),
...metadata
};
} catch (e) {
return {...file};
}
});
files = files.filter(f => f.mtime !== undefined);
// Retrieve all the folders
let allContentFolders: string[] = [];
let allFolders: string[] = [];
if (selectedFolder) {
if (existsSync(selectedFolder)) {
allFolders = readdirSync(selectedFolder, { withFileTypes: true }).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(selectedFolder, dir.name)));
}
} else {
for (const contentFolder of contentFolders) {
const contentPath = contentFolder.path;
if (contentPath && existsSync(contentPath)) {
const subFolders = readdirSync(contentPath, { withFileTypes: true }).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(contentPath, dir.name)));
allContentFolders = [...allContentFolders, ...subFolders];
}
}
const staticPath = join(parseWinPath(wsFolder?.fsPath || ""), staticFolder || "");
if (staticPath && existsSync(staticPath)) {
allFolders = readdirSync(staticPath, { withFileTypes: true }).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(staticPath, dir.name)));
}
}
// Store the last opened folder
await Extension.getInstance().setState(ExtensionState.SelectedFolder, requestedFolder === HOME_PAGE_NAVIGATION_ID ? HOME_PAGE_NAVIGATION_ID : selectedFolder, "workspace");
let sortedFolders = [...allContentFolders, ...allFolders];
sortedFolders = sortedFolders.sort((a, b) => {
if (a.toLowerCase() < b.toLowerCase()) {
return -1;
}
if (a.toLowerCase() > b.toLowerCase()) {
return 1;
}
return 0;
});
if (crntSort?.order === SortOrder.desc) {
sortedFolders = sortedFolders.reverse();
}
Dashboard.postWebviewMessage({
command: DashboardCommand.media,
data: {
media: files,
total: total,
folders: sortedFolders,
selectedFolder
} as MediaPaths
});
}
/**
* Update the metadata of the retrieved files
* @param files
*/
private static async updateMediaData(files: MediaInfo[]) {
files = files.map((m: MediaInfo) => {
const stats = statSync(m.fsPath);
return Object.assign({}, m, stats);
});
return Object.assign([], files);
}
/**
* Retrieve all the markdown pages
*/
private static async getPages() {
const wsFolder = Folders.getWorkspaceFolder();
const descriptionField = SettingsHelper.get(SETTING_SEO_DESCRIPTION_FIELD) as string || DefaultFields.Description;
const dateField = SettingsHelper.get(SETTING_DATE_FIELD) as string || DefaultFields.PublishingDate;
const staticFolder = SettingsHelper.get<string>(SETTINGS_CONTENT_STATIC_FOLDER);
const folderInfo = await Folders.getInfo();
const pages: Page[] = [];
if (folderInfo) {
for (const folder of folderInfo) {
for (const file of folder.lastModified) {
if (file.fileName.endsWith(`.md`) || file.fileName.endsWith(`.markdown`) || file.fileName.endsWith(`.mdx`)) {
try {
const article = ArticleHelper.getFrontMatterByPath(file.filePath);
if (article?.data.title) {
const page: Page = {
...article.data,
// FrontMatter properties
fmFolder: folder.title,
fmModified: file.mtime,
fmFilePath: file.filePath,
fmFileName: file.fileName,
fmDraft: ContentType.getDraftStatus(article?.data),
fmYear: article?.data[dateField] ? DateHelper.tryParse(article?.data[dateField])?.getFullYear() : null,
// Make sure these are always set
title: article?.data.title,
slug: article?.data.slug,
date: article?.data[dateField] || "",
draft: article?.data.draft,
description: article?.data[descriptionField] || "",
};
const contentType = ArticleHelper.getContentType(article.data);
const previewField = contentType.fields.find(field => field.isPreviewImage && field.type === "image")?.name || "preview";
if (article?.data[previewField] && wsFolder) {
let fieldValue = article?.data[previewField];
if (fieldValue && Array.isArray(fieldValue)) {
if (fieldValue.length > 0) {
fieldValue = fieldValue[0];
} else {
fieldValue = undefined;
}
}
// Revalidate as the array could have been empty
if (fieldValue) {
const staticPath = join(wsFolder.fsPath, staticFolder || "", fieldValue);
const contentFolderPath = join(dirname(file.filePath), fieldValue);
let previewUri = null;
if (existsSync(staticPath)) {
previewUri = Uri.file(staticPath);
} else if (existsSync(contentFolderPath)) {
previewUri = Uri.file(contentFolderPath);
}
if (previewUri) {
const preview = Dashboard.webview?.webview.asWebviewUri(previewUri);
page[previewField] = preview?.toString() || "";
} else {
page[previewField] = "";
}
}
}
pages.push(page);
}
} catch (error: any) {
Notifications.error(`File error: ${file.filePath} - ${error?.message || error}`);
}
}
}
}
}
Dashboard.postWebviewMessage({
command: DashboardCommand.pages,
data: pages
});
}
/**
* Filter the media files
*/
private static filterMedia(files: Uri[]) {
return files.filter(file => {
const ext = extname(file.fsPath);
return ['.jpg', '.jpeg', '.png', '.gif', '.svg'].includes(ext);
}).map((file) => ({
fsPath: file.fsPath,
vsPath: Dashboard.webview?.webview.asWebviewUri(file).toString(),
stats: undefined
} as MediaInfo));
}
/**
* Save the dropped file in the current folder
* @param fileData
*/
private static async saveFile({fileName, contents, folder}: { fileName: string; contents: string; folder: string | null }) {
if (fileName && contents) {
const wsFolder = Folders.getWorkspaceFolder();
const staticFolder = SettingsHelper.get<string>(SETTINGS_CONTENT_STATIC_FOLDER);
const wsPath = wsFolder ? wsFolder.fsPath : "";
let absFolderPath = join(wsPath, staticFolder || "");
if (folder) {
absFolderPath = folder;
}
if (!existsSync(absFolderPath)) {
absFolderPath = join(wsPath, folder || "");
}
if (!existsSync(absFolderPath)) {
Notifications.error(`We couldn't find your selected folder.`);
return;
}
const staticPath = join(absFolderPath, fileName);
const imgData = decodeBase64Image(contents);
if (imgData) {
writeFileSync(staticPath, imgData.data);
Notifications.info(`File ${fileName} uploaded to: ${folder}`);
const folderPath = `${folder}`;
if (Dashboard.timers[folderPath]) {
clearTimeout(Dashboard.timers[folderPath]);
delete Dashboard.timers[folderPath];
}
Dashboard.timers[folderPath] = setTimeout(() => {
Dashboard.media = [];
Dashboard.getMedia(0, folder || "");
delete Dashboard.timers[folderPath];
}, 500);
} else {
Notifications.error(`Something went wrong uploading ${fileName}`);
}
}
}
/**
* Delete the selected file
* @param fileData
*/
private static async deleteFile({ file, page, folder }: { file: string; page: number; folder: string | null; }) {
if (!file) {
return;
}
try {
unlinkSync(file);
Dashboard.media = [];
Dashboard.getMedia(page || 0, folder || "");
} catch(err) {
Notifications.error(`Something went wrong deleting ${basename(file)}`);
}
}
/**
* Update the metadata of the selected file
*/
private static async updateMediaMetadata({ file, filename, page, folder, ...metadata }: { file:string; filename:string; page: number; folder: string | null; metadata: any; }) {
Dashboard.mediaLib.set(file, metadata);
// Check if filename needs to be updated
Dashboard.mediaLib.updateFilename(file, filename);
Dashboard.getMedia(page || 0, folder || "");
}
/**
* Retrieve the webview HTML contents
* @param webView
*/
private static getWebviewContent(webView: Webview, extensionPath: Uri): string {
const scriptUri = webView.asWebviewUri(Uri.joinPath(extensionPath, 'dist', 'pages.js'));
const dashboardFile = "dashboardWebView.js";
const localPort = `9000`;
const localServerUrl = `localhost:${localPort}`;
let scriptUri = "";
const isProd = Extension.getInstance().isProductionMode;
if (isProd) {
scriptUri = webView.asWebviewUri(Uri.joinPath(extensionPath, 'dist', dashboardFile)).toString();
} else {
scriptUri = `http://${localServerUrl}/${dashboardFile}`;
}
const nonce = WebviewHelper.getNonce();
@@ -726,21 +193,31 @@ export class Dashboard {
const version = ext.getVersion();
const isBeta = ext.isBetaVersion();
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'`,
`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}`}`
];
return `
<!DOCTYPE html>
<html lang="en" style="width:100%;height:100%;margin:0;padding:0;">
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${`vscode-file://vscode-app`} ${webView.cspSource} https://api.visitorbadge.io 'self' 'unsafe-inline'; script-src 'nonce-${nonce}'; style-src ${webView.cspSource} 'self' 'unsafe-inline'; font-src ${webView.cspSource}; connect-src https://o1022172.ingest.sentry.io">
<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 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-environment="${isBeta ? "BETA" : "main"}" data-version="${version.usedVersion}" style="width:100%;height:100%;margin:0;padding:0;" ${version.usedVersion ? "" : `data-showWelcome="true"`}></div>
<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>
<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 nonce="${nonce}" src="${scriptUri}"></script>
<script ${isProd ? `nonce="${nonce}"` : ""} src="${scriptUri}"></script>
</body>
</html>
`;

View File

@@ -1,16 +1,21 @@
import { Questions } from './../helpers/Questions';
import { SETTINGS_CONTENT_PAGE_FOLDERS, SETTINGS_CONTENT_STATIC_FOLDER } from './../constants';
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, join } from "path";
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 { Settings } from "../helpers";
import { Logger, Settings } from "../helpers";
import { existsSync, mkdirSync } from 'fs';
import { format } from 'date-fns';
import { Dashboard } from './Dashboard';
import { parseWinPath } from '../helpers/parseWinPath';
import { MediaHelpers } from '../helpers/MediaHelpers';
import { MediaListener, PagesListener, SettingsListener } from '../listeners/dashboard';
import { DEFAULT_FILE_TYPES } from '../constants/DefaultFileTypes';
import { Telemetry } from '../helpers/Telemetry';
import { glob } from 'glob';
export const WORKSPACE_PLACEHOLDER = `[[workspace]]`;
@@ -22,7 +27,7 @@ export class Folders {
*/
public static async addMediaFolder(data?: {selectedFolder?: string}) {
let wsFolder = Folders.getWorkspaceFolder();
const staticFolder = Settings.get<string>(SETTINGS_CONTENT_STATIC_FOLDER);
const staticFolder = Settings.get<string>(SETTING_CONTENT_STATIC_FOLDER);
let startPath = "";
@@ -62,8 +67,11 @@ export class Folders {
}
if (Dashboard.isOpen) {
Dashboard.switchFolder(folderName);
MediaHelpers.resetMedia();
MediaListener.sendMediaFiles(0, folderName);
}
Telemetry.send(TelemetryEvent.addMediaFolder);
}
/**
@@ -90,7 +98,10 @@ export class Folders {
* Register the new folder path
* @param folder
*/
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, '\\');
@@ -103,11 +114,14 @@ export class Folders {
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({
prompt: `Which name would you like to specify for this folder?`,
placeHolder: `Folder name`,
value: basename(folder.fsPath),
ignoreFocusOut: true
});
}
folders.push({
title: folderName,
@@ -118,6 +132,10 @@ export class Folders {
await Folders.update(folders);
Notifications.info(`Folder registered`);
Telemetry.send(TelemetryEvent.registerFolder);
SettingsListener.getSettings();
}
}
@@ -130,6 +148,8 @@ export class Folders {
let folders = Folders.get();
folders = folders.filter(f => f.path !== folder.fsPath);
await Folders.update(folders);
Telemetry.send(TelemetryEvent.unregisterFolder);
}
}
@@ -199,6 +219,7 @@ export class Folders {
* Get the registered folders information
*/
public static async getInfo(limit?: number): Promise<FolderInfo[] | null> {
const supportedFiles = Settings.get<string[]>(SETTING_CONTENT_SUPPORTED_FILETYPES);
const folders = Folders.get();
if (folders && folders.length > 0) {
let folderInfo: FolderInfo[] = [];
@@ -211,22 +232,29 @@ export class Folders {
if (projectStart) {
projectStart = projectStart.replace(/\\/g, '/');
projectStart = projectStart.startsWith('/') ? projectStart.substr(1) : projectStart;
const mdFiles = await workspace.findFiles(join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.md'));
const markdownFiles = await workspace.findFiles(join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.markdown'));
const mdxFiles = await workspace.findFiles(join(projectStart, folder.excludeSubdir ? '/' : '**/', '*.mdx'));
let files = [...mdFiles, ...markdownFiles, ...mdxFiles];
let files: Uri[] = [];
for (const fileType of (supportedFiles || DEFAULT_FILE_TYPES)) {
const filePath = join(projectStart, folder.excludeSubdir ? '/' : '**', `*${fileType.startsWith('.') ? '' : '.'}${fileType}`);
const foundFiles = await workspace.findFiles(filePath, '**/node_modules/**');
files = [...files, ...foundFiles];
}
if (files) {
let fileStats: FileInfo[] = [];
for (const file of files) {
try {
const fileName = basename(file.fsPath);
const folderName = dirname(file.fsPath).split(sep).pop();
const stats = await workspace.fs.stat(file);
fileStats.push({
filePath: file.fsPath,
fileName,
folderName,
...stats
});
} catch (error) {
@@ -264,19 +292,38 @@ export class Folders {
*/
public static get(): ContentFolder[] {
const wsFolder = Folders.getWorkspaceFolder();
const folders: ContentFolder[] = Settings.get(SETTINGS_CONTENT_PAGE_FOLDERS) as ContentFolder[];
const folders: ContentFolder[] = Settings.get(SETTING_CONTENT_PAGE_FOLDERS) as ContentFolder[];
const contentFolders = folders.map(folder => {
if (!folder.title) {
folder.title = basename(folder.path);
}
let folderPath = Folders.absWsFolder(folder, wsFolder);
if (!existsSync(folderPath)) {
Notifications.errorShowOnce(`Folder "${folder.title} (${folder.path})" does not exist. Please remove it from the settings.`, "Remove folder").then(answer => {
if (answer === "Remove folder") {
let folders = Folders.get();
Folders.update(folders.filter(f => f.path !== folder.path));
}
});
return null;
}
return {
...folder,
path: folderPath
}
})
return folders.map(folder => ({
...folder,
path: Folders.absWsFolder(folder, wsFolder)
}));
return contentFolders.filter(folder => folder !== null) as ContentFolder[];
}
/**
* Update the folder settings
* @param folders
*/
private static async update(folders: ContentFolder[]) {
public static async update(folders: ContentFolder[]) {
const wsFolder = Folders.getWorkspaceFolder();
let folderDetails = folders.map(folder => ({
@@ -284,7 +331,23 @@ export class Folders {
path: Folders.relWsFolder(folder, wsFolder)
}));
await Settings.update(SETTINGS_CONTENT_PAGE_FOLDERS, folderDetails, true);
await Settings.update(SETTING_CONTENT_PAGE_FOLDERS, folderDetails, true);
// Reinitialize the folder listeners
PagesListener.startWatchers();
}
/**
* Retrieve the absolute file path
* @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 || ""));
absPath = isWindows ? absPath.split('/').join('\\') : absPath;
return absPath;
}
/**
@@ -295,7 +358,7 @@ export class Folders {
*/
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;
}
@@ -306,10 +369,52 @@ export class Folders {
* @param wsFolder
* @returns
*/
private static relWsFolder(folder: ContentFolder, wsFolder?: Uri) {
public static relWsFolder(folder: ContentFolder, wsFolder?: Uri) {
const isWindows = process.platform === 'win32';
let absPath = 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));
}
/**
* 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);
});
});
}
}

View File

@@ -1,13 +1,15 @@
import { SETTING_PREVIEW_HOST, SETTING_PREVIEW_PATHNAME, CONTEXT } from './../constants';
import { Telemetry } from './../helpers/Telemetry';
import { SETTING_PREVIEW_HOST, SETTING_PREVIEW_PATHNAME, CONTEXT, TelemetryEvent, PreviewCommands } from './../constants';
import { ArticleHelper } from './../helpers/ArticleHelper';
import { join } from "path";
import { commands, env, Uri, ViewColumn, window } from "vscode";
import { Settings } from '../helpers';
import { Extension, Settings } from '../helpers';
import { 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';
export class Preview {
@@ -70,8 +72,8 @@ export class Preview {
);
webView.iconPath = {
dark: Uri.file(join(extensionPath, 'assets/frontmatter-dark.svg')),
light: Uri.file(join(extensionPath, 'assets/frontmatter.svg'))
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(
@@ -80,59 +82,64 @@ export class Preview {
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;
}
.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 dashboardFile = "dashboardWebView.js";
const localPort = `9000`;
const localServerUrl = `localhost:${localPort}`;
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 nonce = WebviewHelper.getNonce();
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}`;
}
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}" style="width:100%;height:100%;margin:0;padding:0;"></div>
<script ${isProd ? `nonce="${nonce}"` : ""} src="${scriptUri}"></script>
</body>
</html>
`;
Telemetry.send(TelemetryEvent.openPreview);
}
/**

View File

@@ -1,16 +1,19 @@
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 { Settings } from "../helpers";
import { FrameworkDetector, Logger, Settings } from "../helpers";
import { SETTING_CONTENT_DEFAULT_FILETYPE, TelemetryEvent } from "../constants";
import { SettingsListener } from '../listeners/dashboard';
export class Project {
private static content = `---
title: "{{name}}"
slug: "/{{kebabCase name}}/"
title:
slug:
description:
author:
date: 2019-08-22T15:20:28.000Z
@@ -21,35 +24,67 @@ categories: []
---
`;
public static isInitialized() {
return Settings.hasProjectFile();
}
/**
* Initialize a new "Project" instance.
*/
public static async init(sampleTemplate: boolean = true) {
public static async init(sampleTemplate?: boolean) {
try {
Settings.createTeamSettings();
const folder = Template.getSettings();
const templatePath = Project.templatePath();
if (!folder || !templatePath) {
return;
}
const article = Uri.file(join(templatePath.fsPath, "article.md"));
if (!fs.existsSync(templatePath.fsPath)) {
await workspace.fs.createDirectory(templatePath);
}
if (sampleTemplate) {
fs.writeFileSync(article.fsPath, Project.content, { encoding: "utf-8" });
if (sampleTemplate !== undefined) {
await Project.createSampleTemplate();
} else {
Notifications.info("Project initialized successfully.");
}
Telemetry.send(TelemetryEvent.initialization);
// Check if you can find the framework
const wsFolder = Folders.getWorkspaceFolder();
const framework = FrameworkDetector.get(wsFolder?.fsPath || "");
if (framework) {
SettingsListener.setFramework(framework.name);
}
SettingsListener.getSettings();
} catch (err: any) {
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 (!fs.existsSync(templatePath.fsPath)) {
await workspace.fs.createDirectory(templatePath);
}
if (sampleTemplate) {
fs.writeFileSync(article.fsPath, Project.content, { encoding: "utf-8" });
Notifications.info("Sample template created.");
}
}
/**
* Get the template path for the current project
*/

View File

@@ -1,10 +1,9 @@
import * as vscode from 'vscode';
import * as matter from 'gray-matter';
import * as fs from 'fs';
import { TaxonomyType } from "../models";
import { SETTING_TAXONOMY_TAGS, SETTING_TAXONOMY_CATEGORIES, EXTENSION_NAME } from '../constants';
import { ArticleHelper, Settings as SettingsHelper, FilesHelper } from '../helpers';
import { TomlEngine, getFmLanguage, getFormatOpts } from '../helpers/TomlEngine';
import { FrontMatterParser } from '../parsers';
import { DumpOptions } from 'js-yaml';
import { Notifications } from '../helpers/Notifications';
@@ -18,7 +17,8 @@ export class Settings {
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"}`
placeHolder: `Name of the ${type === TaxonomyType.Tag ? "tag" : "category"}`,
ignoreFocusOut: true
});
if (newOption) {
@@ -37,7 +37,11 @@ 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") {
const editor = vscode.window.activeTextEditor;
@@ -90,10 +94,6 @@ export class Settings {
const progressNr = allMdFiles.length/100;
progress.report({ increment: 0});
// Get language options
const language = getFmLanguage();
const langOpts = getFormatOpts(language);
let i = 0;
for (const file of allMdFiles) {
progress.report({ increment: (++i/progressNr) });
@@ -102,10 +102,7 @@ export class Settings {
const txtData = mdFile.getText();
if (txtData) {
try {
const article = matter(txtData, {
...TomlEngine,
...langOpts
});
const article = FrontMatterParser.fromFile(txtData);
if (article && article.data) {
const { data } = article;
const mdTags = data["tags"];
@@ -157,7 +154,8 @@ export class Settings {
"Category"
], {
placeHolder: `What do you want to remap?`,
canPickMany: false
canPickMany: false,
ignoreFocusOut: true
});
if (!taxType) {
return;
@@ -173,7 +171,8 @@ export class Settings {
const selectedOption = await vscode.window.showQuickPick(options, {
placeHolder: `Select your ${type === TaxonomyType.Tag ? "tags" : "categories"} to insert`,
canPickMany: false
canPickMany: false,
ignoreFocusOut: true
});
if (!selectedOption) {
@@ -182,11 +181,16 @@ export class Settings {
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"}`
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"}?` });
const deleteAnswer = await vscode.window.showQuickPick(["yes", "no"], {
canPickMany: false,
placeHolder: `Delete ${selectedOption} ${type === TaxonomyType.Tag ? "tag" : "category"}?`,
ignoreFocusOut: true
});
if (deleteAnswer === "no") {
return;
}
@@ -218,13 +222,8 @@ export class Settings {
progress.report({ increment: (++i/progressNr) });
const mdFile = fs.readFileSync(file.path, { encoding: "utf8" });
if (mdFile) {
const language = getFmLanguage();
const langOpts = getFormatOpts(language);
try {
const article = matter(mdFile, {
...TomlEngine,
...langOpts
});
const article = FrontMatterParser.fromFile(mdFile);
if (article && article.data) {
const { data } = article;
let taxonomies: string[] = data[matterProp];
@@ -239,9 +238,7 @@ export class Settings {
data[matterProp] = [...new Set(taxonomies)].sort();
const spaces = vscode.window.activeTextEditor?.options?.tabSize;
// Update the file
fs.writeFileSync(file.path, matter.stringify(article.content, article.data, {
...TomlEngine,
...langOpts,
fs.writeFileSync(file.path, FrontMatterParser.toFile(article.content, article.data, mdFile, {
indent: spaces || 2
} as DumpOptions as any), { encoding: "utf8" });
}

View File

@@ -1,9 +1,11 @@
import { SETTING_SEO_DESCRIPTION_FIELD, SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_TITLE_LENGTH } from './../constants';
import { CONTEXT, SETTING_SEO_DESCRIPTION_FIELD, SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_TITLE_LENGTH } from './../constants';
import * as vscode from 'vscode';
import { ArticleHelper, 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';
export class StatusListener {
@@ -23,8 +25,10 @@ export class StatusListener {
}
let editor = vscode.window.activeTextEditor;
if (editor && ArticleHelper.isMarkdownFile()) {
if (editor && ArticleHelper.isSupportedFile()) {
try {
commands.executeCommand('setContext', CONTEXT.isValidFile, true);
const article = ArticleHelper.getFrontMatter(editor);
// Update the StatusBar based on the article draft state
@@ -58,7 +62,7 @@ export class StatusListener {
const panel = ExplorerView.getInstance();
if (panel && panel.visible) {
panel.pushMetadata(article!.data);
DataListener.pushMetadata(article!.data);
}
return;
@@ -66,9 +70,11 @@ export class StatusListener {
// Nothing to do
}
} else {
commands.executeCommand('setContext', CONTEXT.isValidFile, false);
const panel = ExplorerView.getInstance();
if (panel && panel.visible) {
panel.pushMetadata(null);
DataListener.pushMetadata(null);
}
}

View File

@@ -2,7 +2,7 @@ import { Questions } from './../helpers/Questions';
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import { SETTING_TEMPLATES_FOLDER, SETTING_TEMPLATES_PREFIX } 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';
@@ -11,6 +11,9 @@ 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';
export class Template {
@@ -20,6 +23,10 @@ export class Template {
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);
}
}
/**
@@ -49,14 +56,16 @@ export class Template {
public static async generate() {
const folder = Template.getSettings();
const editor = vscode.window.activeTextEditor;
const fileType = Settings.get<string>(SETTING_CONTENT_DEFAULT_FILETYPE);
if (folder && editor && ArticleHelper.isMarkdownFile()) {
if (folder && editor && ArticleHelper.isSupportedFile()) {
const article = ArticleHelper.getFrontMatter(editor);
const clonedArticle = Object.assign({}, article);
const titleValue = await vscode.window.showInputBox({
prompt: `What name would you like to give your template?`,
placeHolder: `article`
placeHolder: `article`,
ignoreFocusOut: true
});
if (!titleValue) {
@@ -69,6 +78,7 @@ export class Template {
{
canPickMany: false,
placeHolder: `Do you want to keep the contents for the template?`,
ignoreFocusOut: true
}
);
@@ -82,7 +92,7 @@ export class Template {
if (templatePath) {
let fileContents = ArticleHelper.stringifyFrontMatter(keepContents === "no" ? "" : clonedArticle.content, clonedArticle.data);
const templateFile = path.join(templatePath.fsPath, `${titleValue}.md`);
const templateFile = path.join(templatePath.fsPath, `${titleValue}.${fileType}`);
fs.writeFileSync(templateFile, fileContents, { encoding: "utf-8" });
Notifications.info(`Template created and is now available in your ${folder} folder.`);
@@ -90,11 +100,24 @@ export class Template {
}
}
/**
* 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) {
@@ -102,19 +125,15 @@ 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`
placeHolder: `Select the content template to use`,
ignoreFocusOut: true
});
if (!selectedTemplate) {
Notifications.warning(`No template selected.`);
@@ -139,7 +158,8 @@ export class Template {
contentType = contentTypes?.find(t => t.name === templateData.data.type);
}
let newFilePath: string | undefined = ArticleHelper.createContent(contentType, folderPath, titleValue);
const fileExtension = extname(template.fsPath).replace(".", "");
let newFilePath: string | undefined = ArticleHelper.createContent(contentType, folderPath, titleValue, fileExtension);
if (!newFilePath) {
return;
}
@@ -155,13 +175,7 @@ export class Template {
}
if (frontMatter.data) {
const fmData = frontMatter.data;
if (typeof fmData.title !== "undefined") {
fmData.title = titleValue;
}
if (typeof fmData.slug !== "undefined") {
fmData.slug = ArticleHelper.sanitize(titleValue);
}
frontMatter.data = ArticleHelper.updatePlaceholders(frontMatter.data, titleValue);
frontMatter = Article.updateDate(frontMatter);
@@ -176,6 +190,11 @@ export class Template {
}
Notifications.info(`Your new content has been created.`);
Telemetry.send(TelemetryEvent.createContentFromTemplate);
// Trigger a refresh for the dashboard
PagesListener.refresh();
}
/**

View File

@@ -1,5 +1,5 @@
import { commands, window, Selection, QuickPickItem } from "vscode";
import { COMMAND_NAME, CONTEXT, SETTINGS_CONTENT_WYSIWYG } from "../constants";
import { COMMAND_NAME, CONTEXT, SETTING_CONTENT_WYSIWYG } from "../constants";
import { Settings } from "../helpers";
enum MarkupType {
@@ -24,7 +24,7 @@ export class Wysiwyg {
*/
public static async registerCommands(subscriptions: any) {
const wysiwygEnabled = Settings.get(SETTINGS_CONTENT_WYSIWYG);
const wysiwygEnabled = Settings.get(SETTING_CONTENT_WYSIWYG);
if (!wysiwygEnabled) {
return;
@@ -54,12 +54,13 @@ export class Wysiwyg {
{ 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 },
]
const option = await window.showQuickPick([ ...qpItems ], {
placeHolder: "Which type of markup would you like to insert?",
canPickMany: false,
ignoreFocusOut: false,
canPickMany: false,
ignoreFocusOut: true
});
if (option) {
@@ -73,6 +74,8 @@ export class Wysiwyg {
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);
}
}
}));
@@ -158,8 +161,8 @@ export class Wysiwyg {
"Heading 6"
], {
canPickMany: false,
placeHolder: "Which heading level do you want to insert?",
ignoreFocusOut: false
placeHolder: "Which heading level do you want to insert?",
ignoreFocusOut: true
});
if (headingLvl) {

View File

@@ -0,0 +1,26 @@
import * as React from 'react';
export interface IFeatureFlagProps {
flag: string;
features: string[] | null;
alternative?: JSX.Element;
}
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;
}
return null;
}
return (
<>
{children}
</>
);
};

View File

@@ -0,0 +1,41 @@
import * as invariant from 'invariant';
import { createAutoField } from 'uniforms';
import { PreviewImageField } from '../../panelWebView/components/Fields/PreviewImageField';
export { AutoFieldProps } from 'uniforms';
import BoolField from './BoolField';
import DateField from './DateField';
import ListField from './ListField';
import NestField from './NestField';
import NumField from './NumField';
import RadioField from './RadioField';
import SelectField from './SelectField';
import TextField from './TextField';
const AutoField = createAutoField(props => {
if (props.allowedValues) {
return props.checkboxes && props.fieldType !== Array
? RadioField
: SelectField;
}
switch (props.fieldType) {
case Array:
return ListField;
case Boolean:
return BoolField;
case Date:
return DateField;
case Number:
return NumField;
case Object:
return NestField;
case String:
return TextField;
}
return invariant(false, 'Unsupported field type: %s', props.fieldType);
});
export default AutoField;

View File

@@ -0,0 +1,29 @@
import { ComponentType, createElement, Fragment } from 'react';
import { useForm } from 'uniforms';
import AutoField from './AutoField';
export type AutoFieldsProps = {
autoField?: ComponentType<{ name: string }>;
element?: ComponentType | string;
fields?: string[];
omitFields?: string[];
};
export default function AutoFields({
autoField = AutoField,
element = Fragment,
fields,
omitFields = [],
...props
}: AutoFieldsProps) {
const { schema } = useForm();
return createElement(
element,
props,
(fields ?? schema.getSubfields())
.filter(field => !omitFields.includes(field))
.map(field => createElement(autoField, { key: field, name: field })),
);
}

View File

@@ -0,0 +1,13 @@
import { AutoForm } from 'uniforms';
import ValidatedQuickForm from './ValidatedQuickForm';
function Auto(parent: any) {
class _ extends AutoForm.Auto(parent) {
static Auto = Auto;
}
return _ as unknown as AutoForm;
}
export default Auto(ValidatedQuickForm);

Some files were not shown because too many files have changed in this diff Show More