Compare commits

..

No commits in common. "master" and "blog-generator" have entirely different histories.

41 changed files with 6502 additions and 12958 deletions

View File

@ -1,19 +0,0 @@
Copyright 2023 Evert "Diamond" Prants <evert@lunasqu.ee>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -333,20 +333,6 @@
"css": "archive",
"code": 59415,
"src": "entypo"
},
{
"uid": "44d7da736a0c6aa588f9151ebcf9e80e",
"css": "gitea",
"code": 59416,
"src": "custom_icons",
"selected": true,
"svg": {
"path": "M181.1 223.5C171 223.5 159.6 224.4 146.7 227.2 133.1 230 94.4 238.7 62.7 269.2-7.7 331.9 10.3 431.6 12.5 446.6 15.2 464.8 23.3 515.6 62 559.8 133.6 647.5 287.6 645.5 287.6 645.5S306.6 690.6 335.5 732.2C374.5 783.9 414.7 824.2 453.7 829.1 552.2 829.1 748.9 828.9 748.9 828.9S767.7 829.1 793.1 812.8C815 799.5 834.5 776.2 834.5 776.2S854.7 754.7 882.8 705.5C891.4 690.3 898.6 675.6 904.8 661.7 904.8 661.7 991.1 478.7 991.1 300.6 989.4 246.7 976.1 237.2 973 234.1 966.6 227.6 958 227.8 958 227.8S774.8 238.1 680 240.3C659.2 240.8 638.6 241.2 618.1 241.4V424.5C609.5 420.5 600.8 416.2 592.2 412.2 592.2 355.3 592 241.6 592 241.6 546.7 242.2 452.6 238.1 452.6 238.1S231.7 227 207.6 224.8C200 224.4 191.2 223.5 181.1 223.5ZM200.2 298.6S211.2 391.4 224.7 445.8C235.9 491.4 263.4 567.2 263.4 567.2S222.7 562.3 196.2 553C155.8 539.7 138.6 523.7 138.6 523.7S108.7 502.8 93.7 461.6C68 392.5 91.6 350.3 91.6 350.3S104.7 315.1 151.7 303.4C173.3 297.6 200.2 298.6 200.2 298.6ZM534.1 403.1C545.5 402.4 557.3 408.3 557.3 408.3L592.9 425.5C585.7 440.1 578.4 454.9 571.2 469.5 560.8 469.4 551.1 475 546.1 484.2 540.8 494.1 541.9 506.2 549.1 515.1L510.6 593.9C497.8 594.1 486.6 603 483.6 615.5S486.7 640.9 497.8 646.7C509.8 653 525.2 649.5 533.3 638.3 541.2 627.2 540 611.9 530.5 602.2L568 525.5C570.3 525.6 573.7 525.8 577.7 524.7 584.1 523.3 588.7 519.1 588.7 519.1 595.3 521.9 602.2 525 609.4 528.6 616.9 532.3 623.9 536.2 630.3 540 631.7 540.8 633.1 541.7 634.7 543 637.2 545 640 547.8 642 551.6 645 560.1 639.1 574.8 639.1 574.8 635.5 586.7 610.3 638.3 610.3 638.3 597.7 638 586.4 646.1 582.7 657.8 578.6 670.5 584.4 684.8 596.6 691.1S623.7 693.7 631.7 682.8C639.5 672.2 638.9 657.3 630 647.5 633 641.7 635.8 635.9 638.7 629.8 646.6 613.6 659.8 582.3 659.8 582.3 661.2 579.7 668.7 566.2 664.1 549.1 660.2 531.2 644.4 523 644.4 523 625.3 510.6 598.7 499.2 598.7 499.2S598.7 492.8 597 488.1C595.3 483.3 592.7 480.1 590.9 478.3 598 463.7 605 449.3 612.1 434.8L730.3 492.2S750 501.1 754.2 517.5C757.2 529.1 753.4 539.4 751.4 544.4 741.6 568.4 665.5 721.1 665.5 721.1S655.9 743.7 634.8 745.1C625.8 745.8 618.7 743.3 618.7 743.3S618.3 743.1 610.5 740L434.1 654.1S417 645.1 414.1 629.7C410.6 617 418.3 601.4 418.3 601.4L503.1 426.6S510.6 411.4 522.2 406.2C523.1 405.8 525.8 404.7 529.2 403.9 530.8 403.5 532.4 403.2 534.1 403.1Z",
"width": 1000
},
"search": [
"gitea"
]
}
]
}

View File

@ -23,7 +23,6 @@
.icon-search:before { content: '\e815'; } /* '' */
.icon-share:before { content: '\e816'; } /* '' */
.icon-archive:before { content: '\e817'; } /* '' */
.icon-gitea:before { content: '\e818'; } /* '' */
.icon-github-circled:before { content: '\f09b'; } /* '' */
.icon-rss:before { content: '\f09e'; } /* '' */
.icon-html5:before { content: '\f13b'; } /* '' */

File diff suppressed because one or more lines are too long

View File

@ -23,7 +23,6 @@
.icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe815;&nbsp;'); }
.icon-share { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe816;&nbsp;'); }
.icon-archive { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe817;&nbsp;'); }
.icon-gitea { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe818;&nbsp;'); }
.icon-github-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09b;&nbsp;'); }
.icon-rss { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09e;&nbsp;'); }
.icon-html5 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13b;&nbsp;'); }

View File

@ -34,7 +34,6 @@
.icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe815;&nbsp;'); }
.icon-share { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe816;&nbsp;'); }
.icon-archive { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe817;&nbsp;'); }
.icon-gitea { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe818;&nbsp;'); }
.icon-github-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09b;&nbsp;'); }
.icon-rss { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09e;&nbsp;'); }
.icon-html5 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13b;&nbsp;'); }

View File

@ -1,11 +1,11 @@
@font-face {
font-family: 'lunasquee-site';
src: url('../font/lunasquee-site.eot?93359753');
src: url('../font/lunasquee-site.eot?93359753#iefix') format('embedded-opentype'),
url('../font/lunasquee-site.woff2?93359753') format('woff2'),
url('../font/lunasquee-site.woff?93359753') format('woff'),
url('../font/lunasquee-site.ttf?93359753') format('truetype'),
url('../font/lunasquee-site.svg?93359753#lunasquee-site') format('svg');
src: url('../font/lunasquee-site.eot?93518691');
src: url('../font/lunasquee-site.eot?93518691#iefix') format('embedded-opentype'),
url('../font/lunasquee-site.woff2?93518691') format('woff2'),
url('../font/lunasquee-site.woff?93518691') format('woff'),
url('../font/lunasquee-site.ttf?93518691') format('truetype'),
url('../font/lunasquee-site.svg?93518691#lunasquee-site') format('svg');
font-weight: normal;
font-style: normal;
}
@ -15,7 +15,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'lunasquee-site';
src: url('../font/lunasquee-site.svg?93359753#lunasquee-site') format('svg');
src: url('../font/lunasquee-site.svg?93518691#lunasquee-site') format('svg');
}
}
*/
@ -78,7 +78,6 @@
.icon-search:before { content: '\e815'; } /* '' */
.icon-share:before { content: '\e816'; } /* '' */
.icon-archive:before { content: '\e817'; } /* '' */
.icon-gitea:before { content: '\e818'; } /* '' */
.icon-github-circled:before { content: '\f09b'; } /* '' */
.icon-rss:before { content: '\f09e'; } /* '' */
.icon-html5:before { content: '\f13b'; } /* '' */

View File

@ -146,11 +146,11 @@
}
@font-face {
font-family: 'lunasquee-site';
src: url('./font/lunasquee-site.eot?49498894');
src: url('./font/lunasquee-site.eot?49498894#iefix') format('embedded-opentype'),
url('./font/lunasquee-site.woff?49498894') format('woff'),
url('./font/lunasquee-site.ttf?49498894') format('truetype'),
url('./font/lunasquee-site.svg?49498894#lunasquee-site') format('svg');
src: url('./font/lunasquee-site.eot?14312899');
src: url('./font/lunasquee-site.eot?14312899#iefix') format('embedded-opentype'),
url('./font/lunasquee-site.woff?14312899') format('woff'),
url('./font/lunasquee-site.ttf?14312899') format('truetype'),
url('./font/lunasquee-site.svg?14312899#lunasquee-site') format('svg');
font-weight: normal;
font-style: normal;
}
@ -295,9 +295,6 @@
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xe818">
<i class="demo-icon icon-gitea">&#xe818;</i> <span class="i-name">icon-gitea</span><span class="i-code">0xe818</span>
</div>
<div class="span3" title="Code: 0xf09b">
<i class="demo-icon icon-github-circled">&#xf09b;</i> <span class="i-name">icon-github-circled</span><span class="i-code">0xf09b</span>
</div>
@ -307,8 +304,6 @@
<div class="span3" title="Code: 0xf13b">
<i class="demo-icon icon-html5">&#xf13b;</i> <span class="i-name">icon-html5</span><span class="i-code">0xf13b</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf281">
<i class="demo-icon icon-reddit-alien">&#xf281;</i> <span class="i-name">icon-reddit-alien</span><span class="i-code">0xf281</span>
</div>

View File

@ -54,8 +54,6 @@
<glyph glyph-name="archive" unicode="&#xe817;" d="M840 600l0-50-696 0 0 50q0 22 13 35t25 15l608 0q6 0 14-1t22-14 14-35z m-148 150q6 0 14-1t22-14 14-35l-498 0q0 22 13 35t25 15l410 0z m248-200q34-32 38-46 6-18 0-54l-76-450q-4-22-20-35t-28-15l-710 0q-52 0-60 50-6 26-39 223t-39 227q-10 22-3 44t10 26 21 20l10 10 30 30 0-80 836 0 0 80z m-248-270l0 100-70 0 0-80-260 0 0 80-68 0 0-100q0-50 48-50l300 0q22 0 35 12t13 24z" horiz-adv-x="981" />
<glyph glyph-name="gitea" unicode="&#xe818;" d="M181 627c-10 0-21-1-34-4-14-3-53-12-84-42-71-63-53-163-50-178 2-18 10-69 49-113 72-87 226-85 226-85s19-46 48-87c39-52 79-92 118-97 98 0 295 0 295 0s19 0 44 16c22 14 42 37 42 37s20 21 48 71c8 15 16 29 22 43 0 0 86 183 86 361-2 54-15 64-18 67-6 6-15 6-15 6s-183-10-278-12c-21-1-41-1-62-1v-183c-8 4-17 8-26 12 0 57 0 170 0 170-45 0-139 4-139 4s-221 11-245 13c-8 1-17 2-27 2z m19-76s11-92 25-147c11-45 38-121 38-121s-40 5-67 14c-40 13-57 29-57 29s-30 21-45 62c-26 70-2 112-2 112s13 35 60 47c21 5 48 4 48 4z m334-104c12 1 23-5 23-5l36-17c-7-15-15-30-22-44-10 0-20-6-25-15-5-10-4-22 3-31l-38-79c-13 0-24-9-27-21s3-26 14-32c12-6 27-2 35 9 8 11 7 26-2 36l37 77c2-1 6-1 10 0 6 2 11 6 11 6 6-3 13-6 20-10 8-3 15-7 21-11 2-1 3-2 5-3 2-2 5-5 7-9 3-8-3-23-3-23-3-12-29-63-29-63-12 0-24-8-27-20-4-12 1-27 14-33s27-3 35 8c8 11 7 26-2 36 3 5 6 11 9 17 8 16 21 48 21 48 1 2 9 16 4 33-4 18-20 26-20 26-19 12-45 24-45 24s0 6-2 11c-2 5-4 8-6 10 7 14 14 29 21 43l118-57s20-9 24-25c3-12-1-22-3-27-9-24-85-177-85-177s-10-23-31-24c-9-1-16 2-16 2s-1 0-8 3l-177 86s-17 9-20 24c-3 13 4 29 4 29l85 174s8 16 19 21c1 0 4 1 7 2 2 1 3 1 5 1z" horiz-adv-x="1000" />
<glyph glyph-name="github-circled" unicode="&#xf09b;" d="M429 779q116 0 215-58t156-156 57-215q0-140-82-252t-211-155q-15-3-22 4t-7 17q0 1 0 43t0 75q0 54-29 79 32 3 57 10t53 22 45 37 30 58 11 84q0 67-44 115 21 51-4 114-16 5-46-6t-51-25l-21-13q-52 15-107 15t-108-15q-8 6-23 15t-47 22-47 7q-25-63-5-114-44-48-44-115 0-47 12-83t29-59 45-37 52-22 57-10q-21-20-27-58-12-5-25-8t-32-3-36 12-31 35q-11 18-27 29t-28 14l-11 1q-12 0-16-2t-3-7 5-8 7-6l4-3q12-6 24-21t18-29l6-13q7-21 24-34t37-17 39-3 31 1l13 3q0-22 0-50t1-30q0-10-8-17t-22-4q-129 43-211 155t-82 252q0 117 58 215t155 156 216 58z m-267-616q2 4-3 7-6 1-8-1-1-4 4-7 5-3 7 1z m18-19q4 3-1 9-6 5-9 2-4-3 1-9 5-6 9-2z m16-25q6 4 0 11-4 7-9 3-5-3 0-10t9-4z m24-23q4 4-2 10-7 7-11 2-5-5 2-11 6-6 11-1z m32-14q1 6-8 9-8 2-10-4t7-9q8-3 11 4z m35-3q0 7-10 6-9 0-9-6 0-7 10-6 9 0 9 6z m32 5q-1 7-10 5-9-1-8-8t10-4 8 7z" horiz-adv-x="857.1" />
<glyph glyph-name="rss" unicode="&#xf09e;" d="M214 100q0-45-31-76t-76-31-76 31-31 76 31 76 76 31 76-31 31-76z m286-69q1-15-9-26-10-12-27-12h-75q-14 0-24 9t-11 23q-12 128-103 219t-219 103q-14 1-23 11t-9 24v75q0 16 12 26 9 10 24 10h3q89-7 170-45t145-101q63-63 101-145t45-171z m286-1q1-15-10-26-10-11-26-11h-80q-14 0-25 10t-10 23q-7 120-57 228t-129 188-188 129-227 57q-14 1-24 11t-10 24v80q0 16 11 26 10 10 25 10h1q147-8 280-67t238-164q104-104 164-238t67-280z" horiz-adv-x="785.7" />

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="main_outline" enable-background="new 0 0 640 640" version="1.1" viewBox="0 0 640 640" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<path d="m115.91 143.07c-6.4625 0-13.762 0.52617-22.012 2.3262-8.7 1.8-33.501 7.4004-53.801 26.9-45 40.1-33.5 103.9-32.1 113.5 1.7 11.7 6.8992 44.2 31.699 72.5 45.8 56.1 144.4 54.799 144.4 54.799s12.1 28.9 30.6 55.5c25 33.1 50.701 58.9 75.701 62 63 0 188.9-0.09961 188.9-0.09961s11.999 0.09922 28.299-10.301c14-8.5 26.5-23.398 26.5-23.398s12.9-13.801 30.9-45.301c5.5-9.7 10.1-19.1 14.1-28 0 0 55.201-117.1 55.201-231.1-1.1-34.5-9.6016-40.6-11.602-42.6-4.1-4.1-9.5996-4-9.5996-4s-117.2 6.6-177.9 8c-13.3 0.3-26.5 0.59922-39.6 0.69922v117.2c-5.5-2.6-11.1-5.2984-16.6-7.8984 0-36.4-0.09961-109.2-0.09961-109.2-29 0.4-89.201-2.1992-89.201-2.1992s-141.4-7.1-156.8-8.5c-4.9-0.3-10.526-0.82617-16.988-0.82617zm12.188 48.025s7.1012 59.401 15.701 94.201c7.2 29.2 24.799 77.699 24.799 77.699s-26.1-3.0996-43-9.0996c-25.9-8.5-36.9-18.701-36.9-18.701s-19.099-13.399-28.699-39.799c-16.5-44.2-1.4004-71.201-1.4004-71.201s8.4-22.5 38.5-30c13.8-3.7 31-3.0996 31-3.0996zm213.7 66.918c7.3213-0.46895 14.9 3.2832 14.9 3.2832l22.744 11.033c-4.5912 9.365-9.2608 18.809-13.844 28.166-6.7-0.1-12.9 3.5004-16.1 9.4004-3.4 6.3-2.6996 14.099 1.9004 19.799l-24.6 50.4c-8.2 0.1-15.401 5.8008-17.301 13.801s1.9996 16.3 9.0996 20c7.7 4 17.501 1.7996 22.701-5.4004 5.1-7.1 4.2992-16.9-1.8008-23.1l24-49.1c1.5 0.1 3.6992 0.2 6.1992-0.5 4.1-0.9 7.1016-3.6016 7.1016-3.6016 4.2 1.8 8.5992 3.8016 13.199 6.1016 4.8 2.4 9.3004 4.8988 13.4 7.2988 0.9 0.5 1.7988 1.1004 2.7988 1.9004 1.6 1.3 3.4012 3.1 4.7012 5.5 1.9 5.5-1.9004 14.9-1.9004 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-0.2-15.299 5-17.699 12.5-2.6 8.1 1.1004 17.301 8.9004 21.301s17.4 1.6992 22.5-5.3008c5-6.8 4.5984-16.3-1.1016-22.6 1.9-3.7 3.7016-7.4008 5.6016-11.301 5-10.4 13.5-30.4 13.5-30.4 0.9-1.7 5.6992-10.299 2.6992-21.299-2.5-11.4-12.6-16.701-12.6-16.701-12.2-7.9-29.201-15.199-29.201-15.199s3.9e-4 -4.0996-1.0996-7.0996c-1.1-3.1-2.8004-5.1008-3.9004-6.3008 4.5072-9.3022 9.0162-18.516 13.523-27.811l75.678 36.711s12.599 5.6992 15.299 16.199c1.9 7.4-0.49883 14.001-1.7988 17.201-6.3 15.4-55 113.1-55 113.1s-6.0996 14.5-19.6 15.4c-5.8 0.4-10.301-1.2012-10.301-1.2012s-0.30078-0.09961-5.3008-2.0996l-112.9-55s-10.901-5.6996-12.801-15.6c-2.2-8.1 2.6992-18.1 2.6992-18.1l54.301-111.9s4.7992-9.7 12.199-13c0.6-0.3 2.3-1 4.5-1.5 1.0125-0.2625 2.0537-0.41543 3.0996-0.48242z"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,17 +1,10 @@
.blog {
--blog-background: #eeeeee;
--blog-section-title-color: #4f4f4f;
--blog-text-color: #555555;
--blog-link-color: #195f7a;
--blog-sidebar-link-color: #006891;
--blog-title-color: #000000;
width: 100%;
min-height: 100vh;
background-color: var(--blog-background);
background-color: #eee;
a {
color: var(--blog-link-color);
color: #258fb8;
}
&__header {
@ -40,7 +33,7 @@
a {
padding: 1rem 1.2rem;
color: var(--blog-sidebar-link-color);
color: #006891;
@media all and (max-width: 768px) {
padding: 0.8rem 1rem;
@ -86,16 +79,15 @@
h1 {
font-size: 2rem;
color: var(--blog-title-color);
}
a {
color: var(--blog-title-color);
color: #000;
}
}
&__content {
color: var(--blog-text-color);
color: #555;
padding: 0 20px;
line-height: 1.5;
@ -173,15 +165,6 @@
}
}
&__continue {
margin: 0 0 20px 20px;
display: inline-block;
background-color: #efefef;
padding: 0.5rem 1.5rem;
border-radius: 8px;
color: #000 !important;
}
&__inner {
overflow: hidden;
background-color: #fff;
@ -189,13 +172,13 @@
}
&__meta {
margin-bottom: 0.6rem;
margin-bottom: 1em;
margin-left: 5px;
font-size: 14px;
a {
letter-spacing: 2px;
color: var(--blog-section-title-color);
color: #999;
line-height: 1em;
text-shadow: 0 1px #fff;
font-weight: bold;
@ -215,38 +198,7 @@
gap: 1rem;
.blog-post__tag {
color: var(--blog-section-title-color);
}
}
&__page {
display: flex;
margin-top: 1.2rem;
justify-content: space-between;
&-link {
display: flex;
flex-direction: column;
&--newer {
margin-left: auto;
text-align: right;
}
&:hover {
text-decoration: none;
.blog-post__page-name {
text-decoration: underline;
}
}
}
&-title {
color: var(--blog-section-title-color);
line-height: 1em;
text-shadow: 0 1px #fff;
font-weight: bold;
color: #999;
}
}
}
@ -261,7 +213,7 @@
text-decoration: none;
text-transform: uppercase;
letter-spacing: 2px;
color: var(--blog-section-title-color);
color: #999;
margin-bottom: 1em;
margin-left: 5px;
line-height: 1em;
@ -283,7 +235,7 @@
}
a {
color: var(--blog-sidebar-link-color);
color: #006891;
}
ul {
@ -311,7 +263,7 @@
line-height: 1em;
a {
color: var(--blog-section-title-color);
color: #999;
text-shadow: 0 1px #fff;
font-weight: bold;
}
@ -328,7 +280,7 @@
}
&__time {
color: var(--blog-section-title-color);
color: #999 !important;
text-decoration: none;
font-size: 0.85em;
line-height: 1em;

View File

@ -3,7 +3,6 @@
flex-direction: column;
color: #eee;
min-height: 100vh;
background-color: #313131;
.section-expand {
flex-grow: 1;

View File

@ -21,14 +21,14 @@
</template>
<script setup lang="ts">
import type { BlogPost } from '~~/lib/types/post';
import { BlogPost } from '~~/lib/types/post';
interface Archive {
year: number;
posts: BlogPost[];
}
const props = defineProps<{ posts: BlogPost[] | null }>();
const props = defineProps<{ posts: BlogPost[] }>();
const monthNames = [
'Jan',
@ -49,10 +49,10 @@ const yearGroup = computed<Archive[]>(() => {
const groups: Archive[] = [];
props.posts
?.sort((a, b) =>
.sort((a, b) =>
new Date(b.date)
.toISOString()
.localeCompare(new Date(a.date).toISOString(), 'en', { numeric: true }),
.localeCompare(new Date(a.date).toISOString(), 'en', { numeric: true })
)
.forEach((post) => {
const date = new Date(post.date);

View File

@ -1,5 +1,5 @@
<template>
<article class="blog-post" v-if="post">
<article class="blog-post">
<div class="blog-post__meta">
<NuxtLink :to="'/blog/' + post.fullSlug">
<time :datetime="new Date(post.date).toISOString()">
@ -18,15 +18,7 @@
</template>
</h1>
</header>
<template v-if="detail">
<div class="blog-post__content" v-html="post.html"></div>
</template>
<template v-else>
<div class="blog-post__content" v-html="post.summary"></div>
<NuxtLink :to="'/blog/' + post.fullSlug" class="blog-post__continue"
>Continue reading...</NuxtLink
>
</template>
<div class="blog-post__content" v-html="post.html"></div>
<div class="blog-post__footer">
<div class="blog-post__tags">
<NuxtLink
@ -38,31 +30,11 @@
</div>
</div>
</div>
<div v-if="detail" class="blog-post__page">
<NuxtLink
v-if="post.prev"
:to="'/blog/' + post.prev.fullSlug"
class="blog-post__page-link blog-post__page-link--older"
>
<span class="blog-post__page-title">Older</span>
<span class="blog-post__page-name">{{ post.prev.title }}</span>
</NuxtLink>
<NuxtLink
v-if="post.next"
:to="'/blog/' + post.next.fullSlug"
class="blog-post__page-link blog-post__page-link--newer"
>
<span class="blog-post__page-title">Newer</span>
<span class="blog-post__page-name">{{ post.next.title }}</span>
</NuxtLink>
</div>
</article>
</template>
<script setup lang="ts">
import type { BlogPost } from '~~/lib/types/post';
import { BlogPost } from '~~/lib/types/post';
defineProps<{ post: BlogPost | null; detail?: boolean }>();
defineProps<{ post: BlogPost; detail?: boolean }>();
</script>

View File

@ -9,7 +9,7 @@ date: 2018-02-03 12:43:10
---
Hello!
In the past week, Ive been working on a simple 3D game using [Godot Engine 3.0](https://godotengine.org/) (_go-doh_). In this article, I will show off some of the features and discuss how it all works.<!-- more --> Heres a quick demo of the gameplay:
In the past week, Ive been working on a simple 3D game using [Godot Engine 3.0](https://godotengine.org/) (_go-doh_). In this article, I will show off some of the features and discuss how it all works. Heres a quick demo of the gameplay:
# Mechanics

View File

@ -7,7 +7,6 @@ date: 2018-03-15 17:21:22
---
Today Im going to instruct you through the steps of installing your own Arch Linux system.
<!-- more -->
## Download the ISO

View File

@ -8,7 +8,6 @@ date: 2019-02-23 23:17:18
---
Today I will be describing to you my experiences with self-hosting and how you can get started as well.
<!-- more -->
Im not going to go into detail in this article about how to install and configure anything, but the websites for respective pieces of software have great documentation and you can always look for more information online. Followup blog posts may come in the future describing setups that Ive created.

View File

@ -10,8 +10,6 @@ date: 2018-01-26 12:00:00
So, Ive decided to start a new blog using [Hexo](https://hexo.io/).
Ill probably be using this to share my projects and write some tutorials.
<!-- more -->
## Current projects
Im currently taking a break from writing code due to personal reasons, but Im mainly working on my network, [Icy Network](https://icynet.eu). The main project in the works is [Episodes.Community](https://github.com/IcyNet/Episodes.Community), which is basically a site where people can watch and share links to their favorite TV shows and cartoons.

View File

@ -1,5 +1,5 @@
<template>
<main class="blog">
<div class="blog">
<Head>
<Meta property="og:type" content="website" />
<Meta property="og:title" content="Evert's Blog" />
@ -45,10 +45,8 @@
<div class="blog__sidebar">
<BlogSidebar title="Tags">
<ul>
<li v-for="postTag of tags">
<NuxtLink :to="'/blog/tags/' + postTag.name">{{
postTag.name
}}</NuxtLink>
<li v-for="tag of tags">
<NuxtLink :to="'/blog/tags/' + tag.name">{{ tag.name }}</NuxtLink>
</li>
</ul>
</BlogSidebar>
@ -56,10 +54,10 @@
<BlogSidebar title="Tag cloud">
<div class="tag-cloud">
<NuxtLink
v-for="postTag of tags"
:to="'/blog/tags/' + postTag.name"
:style="{ fontSize: getFontSize(postTag) }"
>{{ postTag.name }}</NuxtLink
v-for="tag of tags"
:to="'/blog/tags/' + tag.name"
:style="{ fontSize: getFontSize(tag) }"
>{{ tag.name }}</NuxtLink
>
</div>
</BlogSidebar>
@ -83,15 +81,15 @@
</BlogSidebar>
</div>
</section>
</main>
</div>
</template>
<script setup lang="ts">
import type { ArchiveDto, BlogPost, BlogPostTag } from '~~/lib/types/post';
import { BlogPostTag } from '~~/lib/types/post';
const { data: tags } = await useFetch<BlogPostTag[]>('/api/blog/tags');
const { data: archive } = await useFetch<ArchiveDto>('/api/blog/archive');
const { data: recents } = await useFetch<BlogPost[]>('/api/blog', {
const { data: tags } = await useFetch('/api/blog/tags');
const { data: archive } = await useFetch('/api/blog/archive');
const { data: recents } = await useFetch('/api/blog', {
key: 'recents',
params: { limit: 6, render: false },
});
@ -114,11 +112,10 @@ const monthNames = [
const monthList = computed(() => {
let links = [];
const res = archive.value;
if (!res) return [];
for (const year of Object.keys(res).sort((a, b) => Number(b) - Number(a))) {
for (const month of Object.keys(res[year]).sort(
(a, b) => Number(b) - Number(a),
(a, b) => Number(b) - Number(a)
)) {
const monthName = monthNames[new Date(`${year}-${month}-01`).getMonth()];
@ -133,30 +130,24 @@ const monthList = computed(() => {
});
const minTag = computed(() =>
tags.value?.reduce<number>(
tags.value.reduce<number>(
(min, current) => (min > current.count ? current.count : min),
1000,
),
1000
)
);
const maxTag = computed(() =>
tags.value?.reduce<number>(
tags.value.reduce<number>(
(max, current) => (max < current.count ? current.count : max),
0,
),
0
)
);
function convertRange(value: number, r1: number[], r2: number[]) {
return ((value - r1[0]) * (r2[1] - r2[0])) / (r1[1] - r1[0]) + r2[0];
}
const getFontSize = (postTag: BlogPostTag): string => {
return (
convertRange(
postTag.count,
[minTag.value ?? 0, maxTag.value ?? 0],
[10, 20],
) + 'px'
);
const getFontSize = (tag: BlogPostTag): string => {
return convertRange(tag.count, [minTag.value, maxTag.value], [10, 20]) + 'px';
};
</script>

View File

@ -4,24 +4,18 @@ import yaml from 'yaml';
import { marked } from 'marked';
import hljs from 'highlight.js';
import { getDateObject } from '../utils/date-object';
import type { ArchiveDto, BlogPost, BlogPostTag } from '../types/post';
import { BlogPost, BlogPostTag } from '../types/post';
const dir = join('content', 'blog');
marked.use({
renderer: {
code: (code, info, escaped): string => {
const language = hljs.getLanguage(info as string)
? (info as string)
: 'plaintext';
const language = hljs.getLanguage(info) ? info : 'plaintext';
const created = hljs.highlight(code, { language }).value;
return `<div class="codeblock"><pre><code class="hljs language-${language}">${created}</code></pre></div>`;
},
link: (
href: string,
title: string | undefined | null,
text: string,
): string => {
link: (href: string, title: string, text: string): string => {
return `<a href="${href}" rel="nofollow" target="_blank"${
title ? ` title="${title}"` : ''
}>${text}</a>`;
@ -29,27 +23,38 @@ marked.use({
},
});
async function readBlogPosts() {
export async function readBlogPosts(
condition?: (body: BlogPost) => boolean,
render = true,
includeContent = true
) {
const files = await fs.readdir(dir);
const readMD = files.filter((file) => file.endsWith('.md'));
const readFiles: BlogPost[] = [];
const readFiles = [];
for (const file of readMD) {
const post = await readBlogPost(file.replace('.md', ''));
const post = await readBlogPost(
file.replace('.md', ''),
condition,
render,
includeContent
);
if (!post) continue;
readFiles.push(post);
}
readFiles.sort((a, b) =>
new Date(b.date)
.toISOString()
.localeCompare(new Date(a.date).toISOString(), 'en', { numeric: true }),
.localeCompare(new Date(a.date).toISOString(), 'en', { numeric: true })
);
return readFiles;
}
async function readBlogPost(slug: string): Promise<BlogPost> {
export async function readBlogPost(
slug: string,
condition?: (body: BlogPost) => boolean,
render = true,
includeContent = true
): Promise<BlogPost[]> {
const decoded = decodeURIComponent(slug);
if (!slug || decoded.includes('/') || decoded.includes('.'))
throw new Error('Invalid post slug');
@ -59,77 +64,30 @@ async function readBlogPost(slug: string): Promise<BlogPost> {
const read = await fs.readFile(mdpath, { encoding: 'utf-8' });
const { header: parsedHeader, length: headerLength } = await readHeader(read);
const renderedMd = await marked(read.substring(headerLength), {
async: true,
});
const boundary = renderedMd.indexOf('<!-- more -->');
const renderedMd = render
? await marked(read.substring(headerLength), { async: true })
: undefined;
const { year, month, day } = getDateObject(parsedHeader);
const content = {
...parsedHeader,
file,
slug,
summary: renderedMd.substring(0, boundary > -1 ? boundary : 240),
fullSlug: `${year}/${month}/${day}/${slug}`,
markdown: read.substring(headerLength),
html: renderedMd.replace('<!-- more -->', ''),
markdown: includeContent ? read.substring(headerLength) : undefined,
html: renderedMd,
};
if (condition) {
if (!condition(content)) {
return;
}
}
return content;
}
let blogPostCache: BlogPost[] = [];
export const blogPostList = async () => {
if (!blogPostCache.length) {
blogPostCache = await readBlogPosts();
}
return blogPostCache;
};
export const getFilteredBlogPosts = async (
condition?: (body: BlogPost) => boolean,
htmlContent = true,
includeMarkdown = true,
): Promise<BlogPost[]> => {
const posts = await blogPostList();
return posts
.filter((item) => (condition ? condition(item) : true))
.map((item) => ({
...item,
html: htmlContent ? item.html : undefined,
markdown: includeMarkdown ? item.markdown : undefined,
}));
};
export const getBlogPost = async (
slug: string,
htmlContent = true,
includeMarkdown = true,
): Promise<BlogPost | undefined> => {
const posts = await blogPostList();
const item = posts.find((item) => item.slug === slug);
if (!item) return;
const index = posts.indexOf(item);
const next = index > 0 ? posts[index - 1] : undefined;
const prev = posts[index + 1];
return {
...item,
html: htmlContent ? item.html : undefined,
markdown: includeMarkdown ? item.markdown : undefined,
next: next
? { title: next.title, slug: next.slug, fullSlug: next.fullSlug }
: undefined,
prev: prev
? { title: prev.title, slug: prev.slug, fullSlug: prev.fullSlug }
: undefined,
};
};
export async function getTags(): Promise<BlogPostTag[]> {
const posts = await getFilteredBlogPosts(undefined, false, false);
const posts = await readBlogPosts(undefined, false, false);
const obj: BlogPostTag[] = [];
for (const post of posts) {
@ -155,8 +113,8 @@ export async function getTags(): Promise<BlogPostTag[]> {
}
export async function getArchiveTree(condition?: (body: BlogPost) => boolean) {
const posts = await getFilteredBlogPosts(condition, false, false);
const obj: ArchiveDto = {};
const posts = await readBlogPosts(condition, false, false);
const obj = {};
for (const post of posts) {
const { year, month, day } = getDateObject(post);

View File

@ -5,11 +5,8 @@ export interface BlogPost {
file: string;
slug: string;
fullSlug: string;
markdown?: string;
summary: string;
html?: string;
next?: Partial<BlogPost>;
prev?: Partial<BlogPost>;
markdown: string;
html: string;
}
export interface BlogPostTag {
@ -17,8 +14,3 @@ export interface BlogPostTag {
count: number;
posts: string[];
}
export type ArchiveDto = Record<
string,
Record<string, Record<string, string[]>>
>;

View File

@ -1,4 +1,4 @@
import type { BlogPost } from '../types/post';
import { BlogPost } from '../types/post';
export function getDateObject(post: BlogPost) {
const date = new Date(post.date);

View File

@ -37,7 +37,7 @@ export default defineNuxtConfig({
hooks: {
async 'nitro:config'(config) {
const routes = await generatePaths('/blog/');
config.prerender?.routes?.push(...routes, '/blog/atom.xml');
config.prerender.routes.push(...routes, '/blog/atom.xml');
},
},
});

18774
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,15 +8,15 @@
"postinstall": "nuxt prepare"
},
"devDependencies": {
"@types/marked": "^5.0.1",
"marked": "^12.0.2",
"nuxt": "^3.11.2",
"prettier": "^3.2.5",
"yaml": "^2.4.1"
"@types/marked": "^4.0.7",
"marked": "^4.1.1",
"nuxt": "3.0.0-rc.11",
"prettier": "^2.7.1",
"yaml": "^2.1.3"
},
"dependencies": {
"feed": "^4.2.2",
"highlight.js": "^11.9.0",
"sass": "^1.75.0"
"highlight.js": "^11.6.0",
"sass": "^1.55.0"
}
}

View File

@ -3,10 +3,10 @@
<Head>
<Meta name="description" :content="preview" />
<Meta property="og:type" content="article" />
<Meta property="og:title" :content="post?.title || ''" />
<Meta property="og:title" content="Self-hosting, Part 1" />
<Meta
property="og:url"
:content="'https://lunasqu.ee/blog/' + post?.fullSlug || ''"
:content="'https://lunasqu.ee/blog/' + post.fullSlug"
/>
<Meta property="og:site_name" content="Evert's Blog" />
<Meta property="og:description" :content="preview" />
@ -14,13 +14,9 @@
<Meta property="article:published_time" :content="isostamp" />
<Meta property="article:modified_time" :content="isostamp" />
<Meta property="article:author" content="Evert Prants" />
<Meta
v-for="tag in post?.tags || []"
property="article:tag"
:content="tag"
/>
<Meta v-for="tag in post.tags" property="article:tag" :content="tag" />
<Meta name="twitter:card" content="summary" />
<Title>{{ post?.title }} | Evert's Blog | lunasqu.ee</Title>
<Title>{{ post.title }} | Evert's Blog | lunasqu.ee</Title>
</Head>
<BlogPost :post="post" :detail="true" />
@ -38,14 +34,11 @@ const { data: post } = await useFetch<BlogPost>(
}
);
const isostamp = computed(() =>
post.value ? new Date(post.value.date).toISOString() : ''
);
const isostamp = computed(() => new Date(post.value.date).toISOString());
const preview = computed(() =>
post.value?.summary
post.value.html
.replace(/<[^>]*>?/gm, '')
.replace('\n', ' ')
.substring(0, 240)
.substring(0, 120)
);
</script>

View File

@ -1,17 +1,15 @@
<template>
<div style="display: contents">
<NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }}/{{ route.params.month }}/{{
route.params.day
}}
| Evert's Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" />
</NuxtLayout>
</div>
<NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }}/{{ route.params.month }}/{{
route.params.day
}}
| Evert's Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" />
</NuxtLayout>
</template>
<script setup lang="ts">

View File

@ -1,15 +1,13 @@
<template>
<div style="display: contents">
<NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }}/{{ route.params.month }} | Evert's
Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" />
</NuxtLayout>
</div>
<NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }}/{{ route.params.month }} | Evert's
Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" />
</NuxtLayout>
</template>
<script setup lang="ts">

View File

@ -1,14 +1,12 @@
<template>
<div style="display: contents">
<NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }} | Evert's Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" />
</NuxtLayout>
</div>
<NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }} | Evert's Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" />
</NuxtLayout>
</template>
<script setup lang="ts">

View File

@ -1,12 +1,10 @@
<template>
<div style="display: contents">
<NuxtLayout name="blog">
<Head>
<Title>Archive | Evert's Blog | lunasqu.ee</Title>
</Head>
<BlogArchive :posts="posts" />
</NuxtLayout>
</div>
<NuxtLayout name="blog">
<Head>
<Title>Archive | Evert's Blog | lunasqu.ee</Title>
</Head>
<BlogArchive :posts="posts" />
</NuxtLayout>
</template>
<script setup lang="ts">

View File

@ -1,18 +1,14 @@
<template>
<div style="display: contents">
<NuxtLayout name="blog">
<template v-for="post of posts">
<BlogPost :post="post" :detail="false" />
</template>
</NuxtLayout>
</div>
<NuxtLayout name="blog">
<template v-for="post of posts">
<BlogPost :post="post" :detail="false" />
</template>
</NuxtLayout>
</template>
<script setup lang="ts">
import type { BlogPost } from '~~/lib/types/post';
const { data: posts } = await useFetch<BlogPost[]>('/api/blog', {
const { data: posts } = await useFetch('/api/blog', {
key: 'frontpage',
params: { limit: 16, render: false },
params: { limit: 16 },
});
</script>

View File

@ -33,10 +33,88 @@
</div>
</Section>
<Section>
<template v-slot:header>
<h1>Featured projects</h1>
</template>
<FeaturedProject
variant="left"
title="Icy Network"
image="/images/projects/icy_network_portal.png"
href="https://icynet.eu"
>
<p>
<b>Icy Network</b> is a single-sign-on (SSO) provider for projects
created by me and my friends.
</p>
<p>
The Icy Network website provides authorization using the
industry-standard OAuth 2.0 protocol.
</p>
<h3>Features</h3>
<ul>
<li>User accounts with display names and avatars</li>
<li>
Administration panel created using Vue.js for managing users and
OAuth clients
</li>
<li>A news outlet</li>
</ul>
</FeaturedProject>
<FeaturedProject
variant="right"
title="Various web-based games"
image="/images/projects/games.png"
href="/apps"
>
<p>
I have also created various experimental web-based games in order to
learn Canvas APIs.
</p>
<h3>Games include..</h3>
<ul>
<li>Battleship</li>
<li>Connect Four</li>
<li>Tower Defense</li>
<li>Minesweeper</li>
<li>Hook Miner</li>
<li>Tile-based modifyable world</li>
</ul>
</FeaturedProject>
<FeaturedProject
variant="left"
title="Icy Network TV"
image="/images/projects/icytv.png"
href="https://tv.icynet.eu"
>
<p>
<b>Icy Network TV</b> is a livestreaming platform for Icy Network
affiliates.
</p>
<p>
This project uses
<a href="https://github.com/arut/nginx-rtmp-module" target="_blank"
>nginx-rtmp-module</a
>
as the livestream server and channels are created for select Icy
Network users only.
</p>
<h3>Features</h3>
<ul>
<li>Integrated video player</li>
<li>Video dashboard</li>
<li>HLS video output</li>
</ul>
</FeaturedProject>
</Section>
<footer>
<p>
There are no cookies. There is no data collection.
<a href="https://git.icynet.eu/evert/lunasqu.ee-nuxt" target="_blank"
<a href="https://gitlab.icynet.eu/evert/lunasqu.ee-nuxt" target="_blank"
>Source code</a
>
</p>
@ -80,14 +158,14 @@ const linksList = [
const socialLinks = [
{
href: 'https://git.icynet.eu/evert',
icon: 'icon-gitea',
name: 'Gitea (personal git)',
href: 'https://gitlab.icynet.eu/evert',
icon: 'icon-gitlab',
name: 'GitLab',
},
{
href: 'https://social.lunasqu.ee/diamond',
icon: 'icon-pleroma',
name: 'Akkoma (Mastodon)',
name: 'Pleroma',
},
{
href: 'https://reddit.com/user/LunaSquee',
@ -97,12 +175,12 @@ const socialLinks = [
{
href: 'https://github.com/LunaSquee',
icon: 'icon-github-circled',
name: 'GitHub (mostly archives)',
name: 'GitHub (old stuff)',
},
];
const currentYear = computed(() => new Date().getFullYear());
const evertAge = computed(() => {
const currentYear = new Date().getFullYear();
const evertAge = (() => {
const today = new Date();
const birthDate = new Date('2000-04-18');
let age = today.getFullYear() - birthDate.getFullYear();
@ -111,5 +189,5 @@ const evertAge = computed(() => {
age--;
}
return age;
});
})();
</script>

View File

@ -1,25 +0,0 @@
import { defineNuxtPlugin } from '#imports';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.$router.options.scrollBehavior = async (to, from, savedPosition) => {
let goTo;
if (to.hash) {
goTo = {
el: to.hash,
behavior: 'smooth',
top: 64,
};
} else if (savedPosition) {
goTo = savedPosition;
} else {
goTo = { top: 0 };
}
return new Promise((resolve) => {
setTimeout(() => {
resolve(goTo);
}, 100);
});
};
});

View File

@ -1,9 +1,10 @@
import { getBlogPost } from '~~/lib/blog/read-posts';
import { H3Error } from 'h3';
import { readBlogPost } from '~~/lib/blog/read-posts';
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, 'slug');
try {
const post = await getBlogPost(slug as string);
const post = await readBlogPost(slug);
return post;
} catch (e) {}
});

View File

@ -1,15 +1,10 @@
import { getArchiveTree } from '~~/lib/blog/read-posts';
import type { BlogPost } from '~~/lib/types/post';
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const include = (content: BlogPost) => {
const include = (content) => {
if (query.tag) {
const tags = Array.isArray(query.tag) ? query.tag : [query.tag];
if (
!content.tags?.length ||
!tags.every((tag) => content.tags.includes(tag))
) {
if (!content.tags?.length || !content.tags.includes(query.tag)) {
return false;
}
}

View File

@ -1,9 +1,8 @@
import { getFilteredBlogPosts } from '~~/lib/blog/read-posts';
import type { BlogPost } from '~~/lib/types/post';
import { readBlogPosts } from '~~/lib/blog/read-posts';
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const include = (content: BlogPost) => {
const include = (content) => {
const dateObj = new Date(content.date);
if (query.year) {
@ -25,11 +24,7 @@ export default defineEventHandler(async (event) => {
}
if (query.tag) {
const tags = Array.isArray(query.tag) ? query.tag : [query.tag];
if (
!content.tags?.length ||
!tags.every((tag) => content.tags.includes(tag))
) {
if (!content.tags?.length || !content.tags.includes(query.tag)) {
return false;
}
}
@ -37,10 +32,10 @@ export default defineEventHandler(async (event) => {
return true;
};
const posts = await getFilteredBlogPosts(
const posts = await readBlogPosts(
include,
query.render !== 'false',
query.body === 'true',
query.body === 'true'
);
const limit = Number(query.limit) || 10;

View File

@ -1,26 +1,26 @@
import { Feed } from 'feed';
import { getFilteredBlogPosts } from '~~/lib/blog/read-posts';
import { readBlogPosts } from '~~/lib/blog/read-posts';
const BASE_URL = 'https://lunasqu.ee/blog';
export default defineEventHandler(async (event) => {
const posts = await getFilteredBlogPosts(undefined, true, false);
const posts = await readBlogPosts(undefined, true, false);
const feed = new Feed({
title: "Evert's Blog",
description: 'Projects and Tutorials',
id: BASE_URL,
link: BASE_URL,
copyright: 'Evert "Diamond" Prants 2024',
copyright: 'Evert "Diamond" Prants 2022',
language: 'en',
updated: new Date(posts[0].date),
generator: 'https://git.icynet.eu/evert/lunasqu.ee-nuxt',
generator: 'https://gitlab.icynet.eu/evert/lunasqu.ee-nuxt',
feedLinks: {
atom: `${BASE_URL}/atom.xml`,
},
});
posts.forEach((post) => {
const description = post.summary
const description = post.html
.replace(/<[^>]*>?/gm, '')
.replace('\n', ' ')
.substring(0, 240);