@bbki.ng/site 5.6.6 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/index.html +1 -1
- package/package.json +1 -1
- package/public/stickers/copilot.svg +1 -0
- package/public/stickers/npm.svg +8 -0
- package/public/stickers/ollama.svg +3 -0
- package/public/stickers/react.svg +9 -0
- package/public/stickers/vitejs.svg +15 -0
- package/src/{blog → app}/app.tsx +12 -17
- package/src/{blog → app}/components/BaseLayout.tsx +2 -2
- package/src/{blog/pages → app/components}/cover/index.tsx +12 -13
- package/src/app/constants/index.ts +1 -0
- package/src/{blog → app}/context/bbcontext.tsx +2 -2
- package/src/{blog/hooks/use_loading.ts → app/hooks/use_global_loading.ts} +1 -1
- package/src/{blog → app}/hooks/use_paths.ts +14 -12
- package/src/{blog → app}/hooks/use_plugin_entries.ts +1 -3
- package/src/{blog → app}/index.tsx +2 -2
- package/src/{blog → app}/main.css +3 -3
- package/src/{blog → app}/swr.tsx +1 -1
- package/src/{blog → app}/utils/index.ts +1 -1
- package/src/core/hooks/use_plugins.ts +1 -1
- package/src/core/pluginManager.ts +64 -19
- package/src/core/pluginManifestService.ts +2 -1
- package/src/index.tsx +3 -3
- package/src/plugins/blog/components/app.tsx +15 -0
- package/src/plugins/blog/constants/index.ts +1 -0
- package/src/plugins/blog/context/index.ts +11 -0
- package/src/{blog → plugins/blog}/hooks/use_blog_scroll_pos_restoration.ts +2 -4
- package/src/{blog → plugins/blog}/hooks/use_posts.ts +8 -9
- package/src/plugins/blog/index.ts +34 -0
- package/src/{blog → plugins/blog}/pages/extensions/txt/article.tsx +3 -3
- package/src/{blog → plugins/blog}/pages/extensions/txt/index.tsx +6 -3
- package/src/plugins/manifest.ts +6 -0
- package/src/plugins/sticker/components/StickerCom.tsx +22 -6
- package/src/plugins/sticker/const.ts +58 -0
- package/src/plugins/sticker/types.ts +10 -0
- package/src/plugins/store/components/storePage.tsx +2 -2
- package/src/types/hostApi.ts +3 -2
- package/src/types/plugin.ts +1 -0
- package/src/utils/index.tsx +15 -0
- package/tsconfig.json +0 -1
- package/public/stamp.svg +0 -61
- package/src/blog/constants/index.ts +0 -1
- package/src/blog/constants/routes.ts +0 -20
- package/src/blog/hooks/index.ts +0 -2
- package/src/blog/hooks/use_blog_context.ts +0 -14
- package/src/blog/hooks/use_mouse_position.ts +0 -17
- package/src/blog/hooks/use_role.ts +0 -14
- package/src/blog/hooks/use_sticker.ts +0 -11
- package/src/blog/pages/index.tsx +0 -2
- package/src/blog/pages/login/index.tsx +0 -24
- package/src/blog/types/blog-context.ts +0 -6
- package/src/blog/types/font.ts +0 -4
- package/src/blog/types/glsl.d.ts +0 -8
- /package/public/{sticker-unlock.svg → stickers/sticker-unlock.svg} +0 -0
- /package/src/{blog/pages → app/components}/bot/index.tsx +0 -0
- /package/src/{blog → app}/context/global_loading_state_provider.tsx +0 -0
- /package/src/{blog → app}/context/global_routes_provider.tsx +0 -0
- /package/src/{blog → app}/hooks/use_pathname.ts +0 -0
- /package/src/{blog → app}/utils/fingerprints.ts +0 -0
- /package/src/{blog → plugins/blog}/components/article/index.tsx +0 -0
- /package/src/{blog → plugins/blog}/components/index.tsx +0 -0
- /package/src/{blog/types → types}/path.ts +0 -0
package/CHANGELOG.md
CHANGED
package/index.html
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 512 416" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"><path d="M181.33 266.143c0-11.497 9.32-20.818 20.818-20.818 11.498 0 20.819 9.321 20.819 20.818v38.373c0 11.497-9.321 20.818-20.819 20.818-11.497 0-20.818-9.32-20.818-20.818v-38.373zM308.807 245.325c-11.477 0-20.798 9.321-20.798 20.818v38.373c0 11.497 9.32 20.818 20.798 20.818 11.497 0 20.818-9.32 20.818-20.818v-38.373c0-11.497-9.32-20.818-20.818-20.818z" fill-rule="nonzero"/><path d="M512.002 246.393v57.384c-.02 7.411-3.696 14.638-9.67 19.011C431.767 374.444 344.695 416 256 416c-98.138 0-196.379-56.542-246.33-93.21-5.975-4.374-9.65-11.6-9.671-19.012v-57.384a35.347 35.347 0 016.857-20.922l15.583-21.085c8.336-11.312 20.757-14.31 33.98-14.31 4.988-56.953 16.794-97.604 45.024-127.354C155.194 5.77 226.56 0 256 0c29.441 0 100.807 5.77 154.557 62.722 28.19 29.75 40.036 70.401 45.025 127.354 13.263 0 25.602 2.936 33.958 14.31l15.583 21.127c4.476 6.077 6.878 13.345 6.878 20.88zm-97.666-26.075c-.677-13.058-11.292-18.19-22.338-21.824-11.64 7.309-25.848 10.183-39.46 10.183-14.454 0-41.432-3.47-63.872-25.869-5.667-5.625-9.527-14.454-12.155-24.247a212.902 212.902 0 00-20.469-1.088c-6.098 0-13.099.349-20.551 1.088-2.628 9.793-6.509 18.622-12.155 24.247-22.4 22.4-49.418 25.87-63.872 25.87-13.612 0-27.86-2.855-39.501-10.184-11.005 3.613-21.558 8.828-22.277 21.824-1.17 24.555-1.272 49.11-1.375 73.645-.041 12.318-.082 24.658-.288 36.976.062 7.166 4.374 13.818 10.882 16.774 52.97 24.124 103.045 36.278 149.137 36.278 46.01 0 96.085-12.154 149.014-36.278 6.508-2.956 10.84-9.608 10.881-16.774.637-36.832.124-73.809-1.642-110.62h.041zM107.521 168.97c8.643 8.623 24.966 14.392 42.56 14.392 13.448 0 39.03-2.874 60.156-24.329 9.28-8.951 15.05-31.35 14.413-54.079-.657-18.231-5.769-33.28-13.448-39.665-8.315-7.371-27.203-10.574-48.33-8.644-22.399 2.238-41.267 9.588-50.875 19.833-20.798 22.728-16.323 80.317-4.476 92.492zm130.556-56.008c.637 3.51.965 7.35 1.273 11.517 0 2.875 0 5.77-.308 8.952 6.406-.636 11.847-.636 16.959-.636s10.553 0 16.959.636c-.329-3.182-.329-6.077-.329-8.952.329-4.167.657-8.007 1.294-11.517-6.735-.637-12.812-.965-17.924-.965s-11.21.328-17.924.965zm49.275-8.008c-.637 22.728 5.133 45.128 14.413 54.08 21.105 21.454 46.708 24.328 60.155 24.328 17.596 0 33.918-5.769 42.561-14.392 11.847-12.175 16.322-69.764-4.476-92.492-9.608-10.245-28.476-17.595-50.875-19.833-21.127-1.93-40.015 1.273-48.33 8.644-7.679 6.385-12.791 21.434-13.448 39.665z"/></svg>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
3
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="540px" height="210px" viewBox="0 0 18 7">
|
|
4
|
+
<path fill="#CB3837" d="M0,0h18v6H9v1H5V6H0V0z M1,5h2V2h1v3h1V1H1V5z M6,1v5h2V5h2V1H6z M8,2h1v2H8V2z M11,1v4h2V2h1v3h1V2h1v3h1V1H11z"/>
|
|
5
|
+
<polygon fill="#FFFFFF" points="1,5 3,5 3,2 4,2 4,5 5,5 5,1 1,1 "/>
|
|
6
|
+
<path fill="#FFFFFF" d="M6,1v5h2V5h2V1H6z M9,4H8V2h1V4z"/>
|
|
7
|
+
<polygon fill="#FFFFFF" points="11,1 11,5 13,5 13,2 14,2 14,5 15,5 15,2 16,2 16,5 17,5 17,1 "/>
|
|
8
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="17" height="25" viewBox="0 0 17 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.40517 0.102088C4.62117 0.198678 4.81617 0.357766 4.99317 0.56799C5.28817 0.915712 5.53718 1.41342 5.72718 2.00318C5.91818 2.59635 6.04218 3.25316 6.08918 3.91224C6.71878 3.5075 7.41754 3.26103 8.13818 3.18953L8.18918 3.18498C9.05919 3.10544 9.91919 3.28384 10.6692 3.72361C10.7702 3.78384 10.8692 3.84861 10.9662 3.91679C11.0162 3.27021 11.1382 2.62817 11.3262 2.04863C11.5162 1.45773 11.7652 0.961166 12.0592 0.612308C12.2235 0.410338 12.4245 0.251368 12.6482 0.146406C12.9052 0.032771 13.1782 0.0123167 13.4442 0.098679C13.8452 0.228223 14.1892 0.516855 14.4602 0.936167C14.7082 1.3191 14.8942 1.81 15.0212 2.39863C15.2512 3.45998 15.2912 4.85655 15.1362 6.54061L15.1892 6.58607L15.2152 6.60766C15.9722 7.26219 16.4992 8.19513 16.7782 9.27807C17.2133 10.9678 16.9943 12.8632 16.2442 13.9235L16.2262 13.9473L16.2282 13.9507C16.6453 14.8166 16.8983 15.7314 16.9523 16.678L16.9543 16.7121C17.0183 17.9223 16.7542 19.1404 16.1402 20.337L16.1332 20.3484L16.1432 20.3756C16.6152 21.6904 16.7632 23.0142 16.5812 24.3369L16.5752 24.3813C16.547 24.5744 16.4525 24.7472 16.3125 24.8612C16.1725 24.9753 15.9983 25.0219 15.8282 24.9903C15.744 24.9753 15.6632 24.9417 15.5904 24.8912C15.5177 24.8408 15.4544 24.7744 15.4042 24.696C15.3541 24.6178 15.318 24.529 15.2981 24.4347C15.2782 24.3406 15.2748 24.2428 15.2882 24.1472C15.4552 22.9733 15.2982 21.7961 14.8082 20.5984C14.7625 20.4871 14.7422 20.3645 14.7492 20.242C14.7562 20.1194 14.7902 20.0009 14.8482 19.8972L14.8522 19.8904C15.4562 18.8404 15.7062 17.8109 15.6522 16.7996C15.6062 15.9143 15.3272 15.045 14.8522 14.2166C14.7598 14.0556 14.7269 13.8597 14.7606 13.6713C14.7943 13.4829 14.8918 13.3171 15.0322 13.2098L15.0412 13.203C15.2842 13.0223 15.5082 12.561 15.6212 11.9303C15.7459 11.1846 15.7133 10.4159 15.5262 9.68716C15.3212 8.89171 14.9462 8.22809 14.4212 7.77468C13.8262 7.25878 13.0382 7.00992 12.0412 7.08151C11.9108 7.09115 11.7809 7.05613 11.6682 6.98097C11.5556 6.90581 11.4653 6.79399 11.4092 6.65993C11.0952 5.90426 10.6372 5.36336 10.0662 5.02814C9.51799 4.71723 8.90425 4.58657 8.29418 4.65087C7.04918 4.76337 5.95118 5.56108 5.62418 6.56675C5.57792 6.70829 5.4947 6.8304 5.38568 6.91672C5.27666 7.00301 5.14703 7.04942 5.01417 7.0497C3.94717 7.05197 3.12117 7.33606 2.51717 7.84855C1.99517 8.29172 1.63916 8.91103 1.45116 9.65307C1.28104 10.3515 1.25774 11.0857 1.38316 11.7962C1.49516 12.4303 1.71416 12.9553 1.96517 13.2382L1.97317 13.2462C2.18517 13.4814 2.23017 13.8485 2.08217 14.1382C1.72216 14.845 1.45316 15.8984 1.40916 16.9109C1.35916 18.0677 1.59516 19.0722 2.12817 19.7927L2.14417 19.8143C2.22461 19.9208 2.27633 20.0514 2.29319 20.1905C2.31003 20.3295 2.29127 20.4711 2.23917 20.5984C1.66316 22.0029 1.48616 23.1574 1.67716 24.0665C1.71148 24.2556 1.67954 24.4524 1.58812 24.6149C1.4967 24.7776 1.35302 24.8933 1.18766 24.9374C1.0223 24.9817 0.848322 24.9506 0.702741 24.8512C0.557141 24.7517 0.451463 24.5917 0.408163 24.4051C0.165162 23.2483 0.330162 21.9233 0.881162 20.4302L0.895162 20.3904L0.887162 20.3768C0.616341 19.9222 0.414243 19.4195 0.289162 18.8893L0.284162 18.8677C0.132362 18.2062 0.0726416 17.5218 0.107162 16.8393C0.151162 15.8052 0.385163 14.7462 0.729162 13.8962L0.741162 13.8666L0.739162 13.8644C0.446163 13.3894 0.229162 12.7814 0.109162 12.1087L0.104162 12.0814C-0.0611788 11.1431 -0.0293187 10.1737 0.197162 9.25194C0.459163 8.21218 0.974162 7.31901 1.73316 6.67356C1.79316 6.62243 1.85616 6.57129 1.91916 6.52357C1.76016 4.827 1.80016 3.42134 2.03117 2.35317C2.15817 1.76455 2.34517 1.27365 2.59317 0.890713C2.86317 0.472537 3.20717 0.183905 3.60817 0.0532252C3.87417 -0.0331371 4.14817 -0.0126829 4.40517 0.102088ZM8.52118 10.4315C9.45719 10.4315 10.3212 10.7871 10.9672 11.403C11.5972 12.0019 11.9722 12.8064 11.9722 13.6076C11.9722 14.6166 11.5662 15.403 10.8392 15.9052C10.2192 16.3314 9.38819 16.5382 8.43618 16.5382C7.42718 16.5382 6.56518 16.2439 5.94318 15.7041C5.32618 15.17 4.98017 14.42 4.98017 13.6076C4.98017 12.8042 5.37818 11.9973 6.03618 11.3962C6.70418 10.786 7.58618 10.4315 8.52118 10.4315ZM8.52118 11.4496C7.82742 11.4428 7.15204 11.7031 6.60518 12.1883C6.14418 12.6087 5.88318 13.1371 5.88318 13.6087C5.88318 14.095 6.09318 14.5507 6.49318 14.8973C6.94818 15.2916 7.61718 15.52 8.43618 15.52C9.23519 15.52 9.90919 15.353 10.3682 15.0359C10.8312 14.7178 11.0682 14.2564 11.0682 13.6076C11.0682 13.1269 10.8222 12.5962 10.3852 12.1803C9.90119 11.7201 9.24519 11.4496 8.52118 11.4496ZM9.18319 12.8246L9.18719 12.8292C9.30719 13.0007 9.28219 13.2496 9.13119 13.386L8.83919 13.6473V14.1541C8.83865 14.267 8.79877 14.375 8.72829 14.4544C8.6578 14.5339 8.56246 14.5783 8.46318 14.578C8.3639 14.5783 8.26856 14.5339 8.19808 14.4544C8.12758 14.375 8.0877 14.267 8.08718 14.1541V13.6314L7.81618 13.3837C7.78042 13.3511 7.7507 13.3109 7.72872 13.2652C7.70674 13.2195 7.69294 13.1694 7.6881 13.1176C7.68326 13.0658 7.6875 13.0135 7.70056 12.9636C7.71362 12.9137 7.73524 12.8672 7.76418 12.8269C7.8232 12.7452 7.9082 12.6934 8.0007 12.6825C8.09318 12.6717 8.18572 12.7027 8.25818 12.7689L8.47318 12.9644L8.69318 12.7667C8.76538 12.7018 8.85702 12.6716 8.94854 12.6825C9.04009 12.6933 9.12427 12.7443 9.18319 12.8246ZM4.14317 10.644C4.62117 10.644 5.01017 11.0871 5.01017 11.6337C5.01043 11.8957 4.91917 12.1471 4.75641 12.3327C4.59365 12.5183 4.37273 12.6229 4.14217 12.6235C3.91195 12.6226 3.69143 12.518 3.52893 12.3327C3.36641 12.1474 3.27517 11.8965 3.27517 11.6349C3.27463 11.3729 3.36565 11.1213 3.52821 10.9355C3.69079 10.7497 3.91261 10.6449 4.14317 10.644ZM12.8492 10.644C13.3292 10.644 13.7172 11.0871 13.7172 11.6337C13.7175 11.8957 13.6262 12.1471 13.4634 12.3327C13.3007 12.5183 13.0798 12.6229 12.8492 12.6235C12.619 12.6226 12.3985 12.518 12.236 12.3327C12.0734 12.1474 11.9822 11.8965 11.9822 11.6349C11.9817 11.3729 12.0727 11.1213 12.2352 10.9355C12.3978 10.7497 12.6186 10.6449 12.8492 10.644ZM3.94017 1.47705L3.93717 1.47932C3.82131 1.53657 3.72239 1.63046 3.65217 1.74977L3.64717 1.75659C3.50917 1.97136 3.38917 2.28727 3.29917 2.70203C3.12917 3.48839 3.08317 4.55541 3.17517 5.86335C3.60517 5.7179 4.07417 5.62699 4.57917 5.59404L4.58917 5.5929L4.60817 5.55426C4.65417 5.46108 4.70317 5.37131 4.75617 5.28268C4.87917 4.40655 4.77817 3.35998 4.50317 2.50545C4.36917 2.09182 4.20617 1.76682 4.05017 1.5816C4.01797 1.5431 3.98207 1.5088 3.94317 1.47932L3.94017 1.47705ZM13.1142 1.52251L13.1122 1.52364C13.0733 1.55312 13.0374 1.58741 13.0052 1.62591C12.8492 1.81114 12.6852 2.13727 12.5522 2.5509C12.2622 3.45316 12.1652 4.56905 12.3222 5.47358L12.3802 5.58381L12.3882 5.59972H12.4182C12.9145 5.59988 13.4082 5.68101 13.8842 5.84062C13.9702 4.56337 13.9222 3.51907 13.7562 2.74749C13.6662 2.33272 13.5462 2.01682 13.4072 1.80205L13.4032 1.79523C13.3331 1.67548 13.2342 1.58121 13.1182 1.52364L13.1142 1.52251Z" fill="black"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-11.5 -10.23174 23 20.46348">
|
|
2
|
+
<title>React Logo</title>
|
|
3
|
+
<circle cx="0" cy="0" r="2.05" fill="#61dafb"/>
|
|
4
|
+
<g stroke="#61dafb" stroke-width="1" fill="none">
|
|
5
|
+
<ellipse rx="11" ry="4.2"/>
|
|
6
|
+
<ellipse rx="11" ry="4.2" transform="rotate(60)"/>
|
|
7
|
+
<ellipse rx="11" ry="4.2" transform="rotate(120)"/>
|
|
8
|
+
</g>
|
|
9
|
+
</svg>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
|
|
3
|
+
<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
|
|
6
|
+
<stop stop-color="#41D1FF"/>
|
|
7
|
+
<stop offset="1" stop-color="#BD34FE"/>
|
|
8
|
+
</linearGradient>
|
|
9
|
+
<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
|
|
10
|
+
<stop stop-color="#FFEA83"/>
|
|
11
|
+
<stop offset="0.0833333" stop-color="#FFDD35"/>
|
|
12
|
+
<stop offset="1" stop-color="#FFA800"/>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
</defs>
|
|
15
|
+
</svg>
|
package/src/{blog → app}/app.tsx
RENAMED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Route, Routes } from 'react-router-dom';
|
|
3
3
|
import { NotFound } from '@bbki.ng/ui';
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import { BotRedirect } from '@/pages/bot';
|
|
8
|
-
import { BBContext } from '@/context/bbcontext';
|
|
5
|
+
import { BotRedirect } from '#/app/components/bot';
|
|
6
|
+
import { BBContext } from '#/app/context/bbcontext';
|
|
9
7
|
import { Slot } from '#/core/components/SlotComp';
|
|
10
8
|
import { usePlugins } from '#/core/hooks/use_plugins';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { BaseLayout } from './components/BaseLayout';
|
|
9
|
+
import { Cover } from '#/app/components/cover';
|
|
10
|
+
import { SWR } from '#/app/swr';
|
|
11
|
+
import { usePluginEntries } from '#/app/hooks/use_plugin_entries';
|
|
12
|
+
import { BaseLayout } from '#/app/components/BaseLayout';
|
|
16
13
|
|
|
17
14
|
const AppRoutes = () => {
|
|
18
15
|
usePlugins();
|
|
@@ -23,15 +20,13 @@ const AppRoutes = () => {
|
|
|
23
20
|
<Routes>
|
|
24
21
|
<Route path="/" element={<BaseLayout />}>
|
|
25
22
|
<Route index element={<Cover />} />
|
|
26
|
-
|
|
27
|
-
<Route path="blog" element={<Outlet />}>
|
|
28
|
-
<Route path="" element={<Txt />} />
|
|
29
|
-
<Route path=":title" element={<ArticlePage />} />
|
|
30
|
-
</Route>
|
|
31
|
-
|
|
32
23
|
<Route path="bot" element={<BotRedirect />} />
|
|
33
24
|
{pluginEntries?.map(route => (
|
|
34
|
-
<Route
|
|
25
|
+
<Route
|
|
26
|
+
key={route.path}
|
|
27
|
+
path={`${route.path}/*`}
|
|
28
|
+
element={<Slot name="route" data={route} />}
|
|
29
|
+
/>
|
|
35
30
|
))}
|
|
36
31
|
<Route path="*" element={pluginEntries?.length ? <NotFound /> : null} />
|
|
37
32
|
</Route>
|
|
@@ -3,8 +3,8 @@ import { useNavigate, Outlet } from 'react-router-dom';
|
|
|
3
3
|
import { Logo, Nav, Page, Grid, ErrorBoundary, Container } from '@bbki.ng/ui';
|
|
4
4
|
|
|
5
5
|
import { Slot } from '#/core/components/SlotComp';
|
|
6
|
-
import { usePaths } from '
|
|
7
|
-
import { GlobalLoadingContext } from '
|
|
6
|
+
import { usePaths } from '#/app/hooks/use_paths';
|
|
7
|
+
import { GlobalLoadingContext } from '#/app/context/global_loading_state_provider';
|
|
8
8
|
import { useMiddlewareTransformedData } from '#/core/hooks/useMiddlewareTransData';
|
|
9
9
|
|
|
10
10
|
export const BaseLayout = () => {
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import React, { useEffect
|
|
2
|
-
import { LinkProps } from '@bbki.ng/ui';
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { LinkProps, LinkListProps, LinkList } from '@bbki.ng/ui';
|
|
3
3
|
|
|
4
|
-
import { CenterLinkList } from '@/components';
|
|
5
4
|
import { useMiddlewareRunner } from '#/core/hooks';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
{
|
|
11
|
-
|
|
12
|
-
children: 'cd ./blog',
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
[]
|
|
6
|
+
const CenterLinkList = (props: LinkListProps) => {
|
|
7
|
+
return (
|
|
8
|
+
<div className="flex justify-center relative h-full">
|
|
9
|
+
<LinkList {...props} />
|
|
10
|
+
</div>
|
|
16
11
|
);
|
|
12
|
+
};
|
|
17
13
|
|
|
14
|
+
const baseEntries: Array<LinkProps> = [];
|
|
15
|
+
|
|
16
|
+
export const Cover = (_: { className?: string }) => {
|
|
18
17
|
const [entries, setEntries] = React.useState<Array<LinkProps>>(baseEntries);
|
|
19
18
|
|
|
20
19
|
const { run } = useMiddlewareRunner<Array<LinkProps>>({
|
|
@@ -26,7 +25,7 @@ export const Cover = (_: { className?: string }) => {
|
|
|
26
25
|
|
|
27
26
|
useEffect(() => {
|
|
28
27
|
run(baseEntries).then(setEntries);
|
|
29
|
-
}, [
|
|
28
|
+
}, [run]);
|
|
30
29
|
|
|
31
30
|
return (
|
|
32
31
|
<>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const API_ENDPOINT = 'https://cf.bbki.ng';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
-
import { GlobalLoadingStateProvider } from '
|
|
4
|
-
import { GlobalRoutesProvider } from '
|
|
3
|
+
import { GlobalLoadingStateProvider } from '#/app/context/global_loading_state_provider';
|
|
4
|
+
import { GlobalRoutesProvider } from '#/app/context/global_routes_provider';
|
|
5
5
|
|
|
6
6
|
export const BBContext = (props: { children: ReactNode }) => {
|
|
7
7
|
return (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useContext, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
-
import { GlobalLoadingContext } from '
|
|
3
|
+
import { GlobalLoadingContext } from '#/app/context/global_loading_state_provider';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Hook to register a loading state with the global loading context.
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import { useLocation } from 'react-router-dom';
|
|
2
1
|
import { useMemo } from 'react';
|
|
3
2
|
|
|
4
|
-
import { usePathName } from '
|
|
5
|
-
import { pathObj } from '
|
|
3
|
+
import { usePathName } from '#/app/hooks/use_pathname';
|
|
4
|
+
import { pathObj } from '#/types/path';
|
|
6
5
|
|
|
7
6
|
export const usePaths = (): pathObj[] => {
|
|
8
7
|
const pathname = usePathName();
|
|
9
|
-
const { pathname: locationPathname } = useLocation();
|
|
10
8
|
|
|
11
|
-
const pathNameArr = pathname.split('/');
|
|
9
|
+
const pathNameArr = useMemo(() => pathname.split('/'), [pathname]);
|
|
12
10
|
|
|
13
|
-
const pathsArr: string[] =
|
|
14
|
-
|
|
15
|
-
.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
const pathsArr: string[] = useMemo(
|
|
12
|
+
() =>
|
|
13
|
+
pathNameArr.map((p: string, index: number) => {
|
|
14
|
+
return pathNameArr
|
|
15
|
+
.slice(0, index + 1)
|
|
16
|
+
.join('/')
|
|
17
|
+
.replace(/^$/, '/');
|
|
18
|
+
}),
|
|
19
|
+
[pathNameArr]
|
|
20
|
+
);
|
|
19
21
|
|
|
20
22
|
const result = useMemo(() => {
|
|
21
23
|
return pathsArr.map((path, index) => {
|
|
@@ -28,7 +30,7 @@ export const usePaths = (): pathObj[] => {
|
|
|
28
30
|
path,
|
|
29
31
|
};
|
|
30
32
|
});
|
|
31
|
-
}, [
|
|
33
|
+
}, [pathNameArr, pathsArr]);
|
|
32
34
|
|
|
33
35
|
if (pathname === '/') {
|
|
34
36
|
return [{ name: '~' }];
|
|
@@ -3,7 +3,7 @@ import { type PathRouteProps } from 'react-router-dom';
|
|
|
3
3
|
|
|
4
4
|
import { useMiddlewareRunner } from '#/core/hooks';
|
|
5
5
|
|
|
6
|
-
const protectedRoutesSet = new Set<string>(['/bot', '/', '
|
|
6
|
+
const protectedRoutesSet = new Set<string>(['/bot', '/', 'default']);
|
|
7
7
|
|
|
8
8
|
type PluginRoute = Omit<PathRouteProps, 'element'>;
|
|
9
9
|
|
|
@@ -35,7 +35,5 @@ export const usePluginEntries = () => {
|
|
|
35
35
|
return false;
|
|
36
36
|
}) as Array<PluginRoute>;
|
|
37
37
|
|
|
38
|
-
console.log('safe plugin routes:', safeRoutes);
|
|
39
|
-
|
|
40
38
|
return safeRoutes ?? [];
|
|
41
39
|
};
|
|
@@ -2,10 +2,10 @@ import React from 'react';
|
|
|
2
2
|
import { createRoot } from 'react-dom/client';
|
|
3
3
|
import { BrowserRouter as Router } from 'react-router-dom';
|
|
4
4
|
|
|
5
|
-
import App from './app';
|
|
5
|
+
import { App } from './app';
|
|
6
6
|
import './main.css';
|
|
7
7
|
|
|
8
|
-
export const
|
|
8
|
+
export const RenderApp = (ele: Element) => {
|
|
9
9
|
const root = createRoot(ele);
|
|
10
10
|
root.render(
|
|
11
11
|
<React.StrictMode>
|
|
@@ -58,7 +58,7 @@ body {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
body,
|
|
61
|
-
#
|
|
61
|
+
#app {
|
|
62
62
|
height: 100lvh;
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -77,7 +77,7 @@ a {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
#
|
|
80
|
+
#app {
|
|
81
81
|
overflow: auto;
|
|
82
82
|
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
|
83
83
|
scrollbar-width: none;
|
|
@@ -86,7 +86,7 @@ a {
|
|
|
86
86
|
box-sizing: border-box;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
#
|
|
89
|
+
#app::-webkit-scrollbar {
|
|
90
90
|
display: none;
|
|
91
91
|
}
|
|
92
92
|
|
package/src/{blog → app}/swr.tsx
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useMemo, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
import { useGlobalLoading } from '
|
|
3
|
+
import { useGlobalLoading } from '#/app/hooks/use_global_loading';
|
|
4
4
|
import { pluginManager } from '#/core/pluginManager';
|
|
5
5
|
import { PluginID } from '#/types/plugin';
|
|
6
6
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { PathRouteProps } from 'react-router-dom';
|
|
3
|
+
import { LinkProps } from '@bbki.ng/ui';
|
|
2
4
|
|
|
3
5
|
import { IHostContext } from '#/types/hostApi';
|
|
4
6
|
import type { SlotName, HookPoint, IComPropsRegisteredToSlot } from '#/types/slots';
|
|
5
|
-
import { IPlugin, PluginEvents, PluginID, PluginPerm } from '#/types/plugin';
|
|
6
|
-
import { getStableDeviceId } from '
|
|
7
|
-
import { cfApiFetcher } from '
|
|
7
|
+
import { IPlugin, IPluginEntry, PluginEvents, PluginID, PluginPerm } from '#/types/plugin';
|
|
8
|
+
import { getStableDeviceId } from '#/app/utils/fingerprints';
|
|
9
|
+
import { cfApiFetcher } from '#/app/utils';
|
|
10
|
+
import { buildEntrySlotCom } from '#/utils';
|
|
8
11
|
|
|
9
12
|
import { registry } from './registry';
|
|
10
13
|
import { createEventBus } from './utils/eventBus';
|
|
@@ -18,6 +21,59 @@ class PluginManager {
|
|
|
18
21
|
|
|
19
22
|
private bus = createEventBus<PluginEvents>();
|
|
20
23
|
|
|
24
|
+
private registryEntry = (entry: IPluginEntry, id: string) => {
|
|
25
|
+
this.registerMiddleware(
|
|
26
|
+
'extendedRoutes',
|
|
27
|
+
(routes: Array<Omit<PathRouteProps, 'element'>>) => {
|
|
28
|
+
return [
|
|
29
|
+
...routes,
|
|
30
|
+
{
|
|
31
|
+
path: entry.path,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
},
|
|
35
|
+
id,
|
|
36
|
+
10
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
this.registerSlot('route', buildEntrySlotCom(entry), id);
|
|
40
|
+
|
|
41
|
+
if (!entry.label) return;
|
|
42
|
+
|
|
43
|
+
this.registerMiddleware(
|
|
44
|
+
'transformCoverEntry',
|
|
45
|
+
(entries: Array<LinkProps>) => {
|
|
46
|
+
return [
|
|
47
|
+
...entries,
|
|
48
|
+
{
|
|
49
|
+
to: entry.path,
|
|
50
|
+
children: entry.label,
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
},
|
|
54
|
+
id,
|
|
55
|
+
10
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
private registerMiddleware = <T>(
|
|
60
|
+
point: HookPoint,
|
|
61
|
+
fn: (data: T) => Promise<T> | T,
|
|
62
|
+
pluginId: string,
|
|
63
|
+
weight = 0
|
|
64
|
+
) => {
|
|
65
|
+
registry.registerMiddleware(point, fn, pluginId, weight);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
private registerSlot = (
|
|
69
|
+
slotName: SlotName,
|
|
70
|
+
component: React.ComponentType<IComPropsRegisteredToSlot>,
|
|
71
|
+
pluginId: string,
|
|
72
|
+
weight = 0
|
|
73
|
+
) => {
|
|
74
|
+
registry.registerComponent(slotName, component, pluginId, weight);
|
|
75
|
+
};
|
|
76
|
+
|
|
21
77
|
private createHostContext(perm: PluginPerm = 'guest'): IHostContext {
|
|
22
78
|
const adminCtx =
|
|
23
79
|
perm === 'admin'
|
|
@@ -35,28 +91,17 @@ class PluginManager {
|
|
|
35
91
|
onLoadingChanged: (listener: (payload: PluginEvents['site:loading:changed']) => void) => {
|
|
36
92
|
return this.bus.on('site:loading:changed', listener);
|
|
37
93
|
},
|
|
38
|
-
|
|
39
|
-
point: HookPoint,
|
|
40
|
-
fn: (data: T) => Promise<T> | T,
|
|
41
|
-
pluginId: string,
|
|
42
|
-
weight = 0
|
|
43
|
-
) => {
|
|
44
|
-
registry.registerMiddleware(point, fn, pluginId, weight);
|
|
45
|
-
},
|
|
94
|
+
|
|
46
95
|
getDeviceId: getStableDeviceId,
|
|
47
96
|
getVersionHash: () => {
|
|
48
97
|
const hashStr: string =
|
|
49
98
|
typeof GLOBAL_COMMIT_HASH === 'string' ? GLOBAL_COMMIT_HASH : '0000000';
|
|
50
99
|
return hashStr;
|
|
51
100
|
},
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
weight = 0
|
|
57
|
-
) => {
|
|
58
|
-
registry.registerComponent(slotName, component, pluginId, weight);
|
|
59
|
-
},
|
|
101
|
+
|
|
102
|
+
registerSlot: this.registerSlot,
|
|
103
|
+
registerMiddleware: this.registerMiddleware,
|
|
104
|
+
registerEntry: this.registryEntry,
|
|
60
105
|
},
|
|
61
106
|
};
|
|
62
107
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cfApiFetcher } from '
|
|
1
|
+
import { cfApiFetcher } from '#/app/utils';
|
|
2
2
|
import { FALLBACK_MANIFEST } from '#/plugins/manifest';
|
|
3
3
|
import { IPluginManifestEntry, PluginID } from '#/types/plugin';
|
|
4
4
|
|
|
@@ -11,6 +11,7 @@ const KnownPluginIDSet = new Set<string>([
|
|
|
11
11
|
'now',
|
|
12
12
|
'default',
|
|
13
13
|
'fx',
|
|
14
|
+
'blog',
|
|
14
15
|
]);
|
|
15
16
|
|
|
16
17
|
interface PluginsApiResponse {
|
package/src/index.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RenderApp } from './app';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const appContainer = document.getElementById('app') as Element;
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
RenderApp(appContainer);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useRoutes } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
import ArticlePage from '#/plugins/blog/pages/extensions/txt/article';
|
|
5
|
+
import Txt from '#/plugins/blog/pages/extensions/txt';
|
|
6
|
+
import { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
7
|
+
|
|
8
|
+
export const BlogPageApp = (_: IComPropsRegisteredToSlot) => {
|
|
9
|
+
const element = useRoutes([
|
|
10
|
+
{ path: '/', element: <Txt /> },
|
|
11
|
+
{ path: '/:title', element: <ArticlePage /> },
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
return <>{element}</>;
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const PLUGIN_NAME = 'blog';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import { ISlotProps } from '#/core/components/SlotComp';
|
|
4
|
+
import { createPluginCtx } from '#/core/context';
|
|
5
|
+
|
|
6
|
+
export interface IBlogContext {
|
|
7
|
+
Slot: React.FC<ISlotProps>;
|
|
8
|
+
setLoading: (loading: boolean) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const BlogContext = createPluginCtx<IBlogContext>();
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
-
import { useLocation } from 'react-router-dom';
|
|
3
2
|
|
|
4
3
|
const SCROLL_STORAGE_KEY = 'div-scroll-positions';
|
|
5
4
|
|
|
@@ -42,7 +41,6 @@ export function useBlogScroll() {
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
export function useBlogScrollRestoration(debounceMs: number = 100) {
|
|
45
|
-
const location = useLocation();
|
|
46
44
|
const isFirstRender = useRef(true);
|
|
47
45
|
const scrollTimeoutRef = useRef<number>();
|
|
48
46
|
const element = document.getElementById('blog');
|
|
@@ -62,7 +60,7 @@ export function useBlogScrollRestoration(debounceMs: number = 100) {
|
|
|
62
60
|
element.scrollTop = savedPosition;
|
|
63
61
|
});
|
|
64
62
|
isFirstRender.current = false;
|
|
65
|
-
}, []);
|
|
63
|
+
}, [element, scrollKey]);
|
|
66
64
|
|
|
67
65
|
// Save scroll position with debouncing
|
|
68
66
|
useEffect(() => {
|
|
@@ -87,5 +85,5 @@ export function useBlogScrollRestoration(debounceMs: number = 100) {
|
|
|
87
85
|
return () => {
|
|
88
86
|
element.removeEventListener('scroll', handleScroll);
|
|
89
87
|
};
|
|
90
|
-
}, []);
|
|
88
|
+
}, [debounceMs, element, scrollKey]);
|
|
91
89
|
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import useSWR from 'swr';
|
|
2
2
|
import { useEffect, useMemo, useState } from 'react';
|
|
3
3
|
|
|
4
|
-
import { useGlobalLoading } from '@/hooks';
|
|
5
|
-
import { baseFetcher } from '@/utils';
|
|
6
|
-
import { API_ENDPOINT } from '@/constants/routes';
|
|
7
4
|
import { IPost } from '#/types/posts';
|
|
8
5
|
import { useMiddlewareRunner } from '#/core/hooks/useMiddlewareTransData';
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
const POSTS_API = !isProd ? '/api/posts' : `${API_ENDPOINT}/posts`;
|
|
7
|
+
import { BlogContext } from '../context';
|
|
12
8
|
|
|
13
9
|
interface PostsApiResponse {
|
|
14
10
|
data: IPost[];
|
|
@@ -23,11 +19,13 @@ export interface TitleListItem {
|
|
|
23
19
|
}
|
|
24
20
|
|
|
25
21
|
export const usePosts = (name: string = '', suspense?: boolean) => {
|
|
26
|
-
const { data: response, error: swrError } = useSWR<PostsApiResponse>(
|
|
22
|
+
const { data: response, error: swrError } = useSWR<PostsApiResponse>('posts', {
|
|
27
23
|
revalidateOnFocus: false,
|
|
28
24
|
suspense,
|
|
29
25
|
});
|
|
30
26
|
|
|
27
|
+
const { setLoading } = BlogContext.useCtx();
|
|
28
|
+
|
|
31
29
|
const data = response?.data;
|
|
32
30
|
const isDataLoading = !data && !swrError;
|
|
33
31
|
|
|
@@ -43,7 +41,6 @@ export const usePosts = (name: string = '', suspense?: boolean) => {
|
|
|
43
41
|
|
|
44
42
|
const [fullTitleList, setFullTitleList] = useState<TitleListItem[]>(baseTitleList);
|
|
45
43
|
|
|
46
|
-
// Use middleware hook to transform title list
|
|
47
44
|
const {
|
|
48
45
|
loading: isTransforming,
|
|
49
46
|
error: transformError,
|
|
@@ -58,7 +55,9 @@ export const usePosts = (name: string = '', suspense?: boolean) => {
|
|
|
58
55
|
}
|
|
59
56
|
}, [baseTitleList, run]);
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
setLoading(isDataLoading || isTransforming);
|
|
60
|
+
}, [isDataLoading, isTransforming, setLoading]);
|
|
62
61
|
|
|
63
62
|
const posts =
|
|
64
63
|
isDataLoading || name === '' || swrError || !data
|
|
@@ -69,6 +68,6 @@ export const usePosts = (name: string = '', suspense?: boolean) => {
|
|
|
69
68
|
posts,
|
|
70
69
|
titleList: fullTitleList ?? [],
|
|
71
70
|
isError: swrError || transformError,
|
|
72
|
-
isLoading:
|
|
71
|
+
isLoading: isDataLoading || isTransforming,
|
|
73
72
|
};
|
|
74
73
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BBPlugin } from '#/core/bbplugin';
|
|
2
|
+
import { Slot } from '#/core/components/SlotComp';
|
|
3
|
+
import { IHostContext } from '#/types/hostApi';
|
|
4
|
+
import { PluginID } from '#/types/plugin';
|
|
5
|
+
|
|
6
|
+
import { BlogPageApp } from './components/app';
|
|
7
|
+
import { BlogContext } from './context';
|
|
8
|
+
|
|
9
|
+
const { withCtx } = BlogContext;
|
|
10
|
+
|
|
11
|
+
export class BlogPlugin extends BBPlugin {
|
|
12
|
+
id: PluginID = 'blog';
|
|
13
|
+
|
|
14
|
+
override onInstall = async (ctx: IHostContext) => {
|
|
15
|
+
ctx.api.registerEntry(
|
|
16
|
+
{
|
|
17
|
+
path: '/blog',
|
|
18
|
+
label: 'cd ./blog',
|
|
19
|
+
pageComponent: withCtx(
|
|
20
|
+
{
|
|
21
|
+
setLoading: loading => {
|
|
22
|
+
ctx.api.setLoading('blog', loading);
|
|
23
|
+
},
|
|
24
|
+
Slot: Slot,
|
|
25
|
+
},
|
|
26
|
+
BlogPageApp
|
|
27
|
+
),
|
|
28
|
+
},
|
|
29
|
+
this.id
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default new BlogPlugin();
|