forgor lol
This commit is contained in:
parent
869f3dfbe3
commit
862b11b9ef
34 changed files with 516 additions and 179 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -12,3 +12,4 @@ node_modules/
|
|||
vendor/
|
||||
|
||||
sync.sh
|
||||
static/extra
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ nav li a {
|
|||
}
|
||||
|
||||
nav li.selected a {
|
||||
background-color: var(--theme-foreground);
|
||||
background-color: var(--theme-primary);
|
||||
color: var(--theme-background);
|
||||
border-radius: var(--radius-sm);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
nav a {
|
||||
|
|
@ -108,19 +108,31 @@ section::before {
|
|||
|
||||
.typewriting a::after,
|
||||
#donation a::after,
|
||||
#links a::after {
|
||||
#links a::after,
|
||||
#about a::after,
|
||||
article a::after {
|
||||
display: inline-block;
|
||||
width: 0.9em;
|
||||
height: 0.9em;
|
||||
margin-left: var(--space-1);
|
||||
vertical-align: -0.1em;
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23cac7ee' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M12 6h-6a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-6' /%3E%3Cpath d='M11 13l9 -9' /%3E%3Cpath d='M15 4h5v5' /%3E%3C/svg%3E");
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23a7a0ff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M12 6h-6a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-6' /%3E%3Cpath d='M11 13l9 -9' /%3E%3Cpath d='M15 4h5v5' /%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
.typewriting a::after,
|
||||
#donation a::after,
|
||||
#links a::after,
|
||||
#about a::after,
|
||||
article a::after {
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236f65f2' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M12 6h-6a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-6' /%3E%3Cpath d='M11 13l9 -9' /%3E%3Cpath d='M15 4h5v5' /%3E%3C/svg%3E");
|
||||
}
|
||||
}
|
||||
|
||||
section.typewriting a,
|
||||
#donation a,
|
||||
#links a {
|
||||
color: var(--theme-foreground);
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
header {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
margin-bottom: var(--space-2);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: var(--radius-md);
|
||||
border-radius: var(--radius-lg);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
-webkit-text-stroke: 2px var(--theme-separator);
|
||||
opacity: 8%;
|
||||
opacity: 0.16;
|
||||
}
|
||||
|
||||
.project-card:hover {
|
||||
|
|
@ -193,6 +193,7 @@
|
|||
transition: opacity var(--transition-fast);
|
||||
border-radius: var(--radius-music);
|
||||
z-index: var(--z-base);
|
||||
color: var(--theme-foreground);
|
||||
}
|
||||
|
||||
.fm-more::before {
|
||||
|
|
@ -320,28 +321,28 @@ u #friends::before {
|
|||
#about h2::before,
|
||||
#languages h2::before,
|
||||
#trivia h2::before {
|
||||
background-color: var(--theme-foreground);
|
||||
background-color: #9f99f0;
|
||||
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
|
||||
}
|
||||
|
||||
#links h2::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='%23cac7ee' %3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M10 2a3 3 0 0 1 2.995 2.824l.005 .176v1h3a2 2 0 0 1 1.995 1.85l.005 .15v3h1a3 3 0 0 1 .176 5.995l-.176 .005h-1v3a2 2 0 0 1 -1.85 1.995l-.15 .005h-3a2 2 0 0 1 -1.995 -1.85l-.005 -.15v-1a1 1 0 0 0 -1.993 -.117l-.007 .117v1a2 2 0 0 1 -1.85 1.995l-.15 .005h-3a2 2 0 0 1 -1.995 -1.85l-.005 -.15v-3a2 2 0 0 1 1.85 -1.995l.15 -.005h1a1 1 0 0 0 .117 -1.993l-.117 -.007h-1a2 2 0 0 1 -1.995 -1.85l-.005 -.15v-3a2 2 0 0 1 1.85 -1.995l.15 -.005h3v-1a3 3 0 0 1 3 -3z' /%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='%239f99f0' %3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M10 2a3 3 0 0 1 2.995 2.824l.005 .176v1h3a2 2 0 0 1 1.995 1.85l.005 .15v3h1a3 3 0 0 1 .176 5.995l-.176 .005h-1v3a2 2 0 0 1 -1.85 1.995l-.15 .005h-3a2 2 0 0 1 -1.995 -1.85l-.005 -.15v-1a1 1 0 0 0 -1.993 -.117l-.007 .117v1a2 2 0 0 1 -1.85 1.995l-.15 .005h-3a2 2 0 0 1 -1.995 -1.85l-.005 -.15v-3a2 2 0 0 1 1.85 -1.995l.15 -.005h1a1 1 0 0 0 .117 -1.993l-.117 -.007h-1a2 2 0 0 1 -1.995 -1.85l-.005 -.15v-3a2 2 0 0 1 1.85 -1.995l.15 -.005h3v-1a3 3 0 0 1 3 -3z' /%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
#donation h2::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='%23cac7ee'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M15.999 2a1 1 0 0 1 1.001 1v3.255l.026 .018a7 7 0 0 1 2.204 2.537l.092 .19h.676a2 2 0 0 1 1.995 1.85l.005 .15v2a2 2 0 0 1 -2 2h-.676l-.104 .213a7 7 0 0 1 -1.097 1.558l-.123 .125v1.604a2.5 2.5 0 0 1 -2.336 2.495l-.162 .005c-1.16 0 -2.135 -.79 -2.418 -1.86l-.032 -.141l-4.05 .001l-.05 -.002l-.032 .141a2.5 2.5 0 0 1 -2.254 1.856l-.164 .005a2.5 2.5 0 0 1 -2.5 -2.5v-1.602l-.056 -.055a7 7 0 0 1 -1.576 -7.085l.092 -.256a7 7 0 0 1 6.539 -4.502h2.196l4.25 -2.832a1 1 0 0 1 .436 -.161zm-.999 8a1 1 0 0 0 -.993 .883l-.007 .127a1 1 0 0 0 1.993 .117l.007 -.127a1 1 0 0 0 -1 -1'/%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='%239f99f0'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M15.999 2a1 1 0 0 1 1.001 1v3.255l.026 .018a7 7 0 0 1 2.204 2.537l.092 .19h.676a2 2 0 0 1 1.995 1.85l.005 .15v2a2 2 0 0 1 -2 2h-.676l-.104 .213a7 7 0 0 1 -1.097 1.558l-.123 .125v1.604a2.5 2.5 0 0 1 -2.336 2.495l-.162 .005c-1.16 0 -2.135 -.79 -2.418 -1.86l-.032 -.141l-4.05 .001l-.05 -.002l-.032 .141a2.5 2.5 0 0 1 -2.254 1.856l-.164 .005a2.5 2.5 0 0 1 -2.5 -2.5v-1.602l-.056 -.055a7 7 0 0 1 -1.576 -7.085l.092 -.256a7 7 0 0 1 6.539 -4.502h2.196l4.25 -2.832a1 1 0 0 1 .436 -.161zm-.999 8a1 1 0 0 0 -.993 .883l-.007 .127a1 1 0 0 0 1.993 .117l.007 -.127a1 1 0 0 0 -1 -1'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
#projects h2::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='%23cac7ee'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M17.108 22.085c-1.266 -.068 -2.924 -.859 -5.071 -2.355l-.04 -.027l-.037 .027c-2.147 1.497 -3.804 2.288 -5.072 2.356l-.178 .005c-2.747 0 -3.097 -2.64 -1.718 -7.244l.054 -.178l-.1 -.075c-6.056 -4.638 -5.046 -7.848 2.554 -8.066l.202 -.005l.115 -.326c1.184 -3.33 2.426 -5.085 4.027 -5.192l.156 -.005c1.674 0 2.957 1.76 4.182 5.197l.114 .326l.204 .005c7.6 .218 8.61 3.428 2.553 8.065l-.102 .075l.055 .178c1.35 4.512 1.04 7.137 -1.556 7.24l-.163 .003z' /%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='%239f99f0'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M17.108 22.085c-1.266 -.068 -2.924 -.859 -5.071 -2.355l-.04 -.027l-.037 .027c-2.147 1.497 -3.804 2.288 -5.072 2.356l-.178 .005c-2.747 0 -3.097 -2.64 -1.718 -7.244l.054 -.178l-.1 -.075c-6.056 -4.638 -5.046 -7.848 2.554 -8.066l.202 -.005l.115 -.326c1.184 -3.33 2.426 -5.085 4.027 -5.192l.156 -.005c1.674 0 2.957 1.76 4.182 5.197l.114 .326l.204 .005c7.6 .218 8.61 3.428 2.553 8.065l-.102 .075l.055 .178c1.35 4.512 1.04 7.137 -1.556 7.24l-.163 .003z' /%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
#friends h2::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23cac7ee' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M9 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0' /%3E%3Cpath d='M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2' /%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75' /%3E%3Cpath d='M21 21v-2a4 4 0 0 0 -3 -3.85' /%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239f99f0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M9 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0' /%3E%3Cpath d='M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2' /%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75' /%3E%3Cpath d='M21 21v-2a4 4 0 0 0 -3 -3.85' /%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
#media h2::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23cac7ee' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 10v3'/%3E%3Cpath d='M6 6v11'/%3E%3Cpath d='M10 3v18'/%3E%3Cpath d='M14 8v7'/%3E%3Cpath d='M18 5v13'/%3E%3Cpath d='M22 10v3'/%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239f99f0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 10v3'/%3E%3Cpath d='M6 6v11'/%3E%3Cpath d='M10 3v18'/%3E%3Cpath d='M14 8v7'/%3E%3Cpath d='M18 5v13'/%3E%3Cpath d='M22 10v3'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.typecycle {
|
||||
|
|
@ -350,7 +351,7 @@ u #friends::before {
|
|||
|
||||
.typecycle::after {
|
||||
content: "";
|
||||
border-right: 0.15em solid var(--theme-foreground);
|
||||
border-right: 0.15em solid var(--theme-primary);
|
||||
animation: caret 2s ease-in-out infinite;
|
||||
padding-left: 0.25ch;
|
||||
}
|
||||
|
|
@ -381,7 +382,7 @@ u #friends::before {
|
|||
}
|
||||
8.33%,
|
||||
16.66% {
|
||||
width: 6ch;
|
||||
width: 4ch;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -443,7 +444,7 @@ u #friends::before {
|
|||
font-size: var(--font-size-xs);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
margin-bottom: var(--space-3);
|
||||
margin-bottom: var(--space-0);
|
||||
font-weight: 600;
|
||||
color: var(--theme-foreground-alt);
|
||||
}
|
||||
|
|
@ -453,19 +454,10 @@ u #friends::before {
|
|||
padding-left: 0;
|
||||
}
|
||||
|
||||
.griddy .column a::before {
|
||||
content: "$ ";
|
||||
color: var(--theme-foreground);
|
||||
}
|
||||
|
||||
.griddy .column li {
|
||||
font-style: italic;
|
||||
color: var(--theme-foreground-bruh);
|
||||
}
|
||||
|
||||
.griddy .column a {
|
||||
font-style: normal;
|
||||
color: var(--theme-foreground);
|
||||
font-size: 0.9em;
|
||||
color: var(--theme-foreground-alt);
|
||||
}
|
||||
|
||||
.pfps {
|
||||
|
|
@ -521,7 +513,7 @@ footer {
|
|||
|
||||
footer a,
|
||||
.highlight {
|
||||
color: var(--theme-foreground);
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
#languages ul,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
border: 1px solid var(--theme-separator);
|
||||
padding: var(--space-4) var(--space-5);
|
||||
margin-bottom: var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
border-radius: var(--radius-lg);
|
||||
transition: all var(--transition-fast);
|
||||
opacity: 75%;
|
||||
position: relative;
|
||||
|
|
@ -31,10 +31,11 @@
|
|||
line-height: 1;
|
||||
text-align: center;
|
||||
-webkit-text-stroke: 2px var(--theme-separator);
|
||||
opacity: 0.5;
|
||||
opacity: 0.16;
|
||||
}
|
||||
|
||||
.reports li, .report:hover {
|
||||
.reports li,
|
||||
.report:hover {
|
||||
opacity: 1;
|
||||
filter: none;
|
||||
}
|
||||
|
|
@ -45,6 +46,11 @@
|
|||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.report .readingTime {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--theme-foreground-bruh);
|
||||
}
|
||||
|
||||
.report h3 {
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: 600;
|
||||
|
|
@ -59,7 +65,8 @@
|
|||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.report .excerpt, .report .title {
|
||||
.report .excerpt,
|
||||
.report .title {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
|
|
@ -71,6 +78,7 @@
|
|||
.report .tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
|
|
@ -80,7 +88,7 @@
|
|||
padding: var(--space-0) var(--space-2);
|
||||
background-color: var(--theme-background);
|
||||
border: 1px solid var(--theme-separator);
|
||||
border-radius: var(--radius-sm);
|
||||
border-radius: var(--radius-lg);
|
||||
color: var(--theme-foreground-alt);
|
||||
}
|
||||
|
||||
|
|
@ -111,13 +119,20 @@ article header .meta {
|
|||
align-items: center;
|
||||
font-size: var(--font-size-md);
|
||||
color: var(--theme-foreground-bruh);
|
||||
margin-bottom: var(--space-4);
|
||||
margin-bottom: var(--space-2);
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
body > a[href="/reports"] {
|
||||
color: var(--theme-foreground-alt);
|
||||
font-size: 0.75em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
article header h1 {
|
||||
font-size: var(--font-size-xl);
|
||||
margin: var(--space-3) 0;
|
||||
margin-top: var(--space-5);
|
||||
margin-bottom: var(--space-3);
|
||||
color: var(--theme-foreground);
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +147,7 @@ article header .tag {
|
|||
padding: var(--space-1) var(--space-3);
|
||||
background-color: var(--theme-background-alt);
|
||||
border: 1px solid var(--theme-separator);
|
||||
border-radius: 2px;
|
||||
border-radius: var(--radius-lg);
|
||||
color: var(--theme-foreground-alt);
|
||||
}
|
||||
|
||||
|
|
@ -179,3 +194,19 @@ article footer {
|
|||
color: var(--theme-foreground-alt);
|
||||
font-size: var(--font-size-md);
|
||||
}
|
||||
|
||||
#reports-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
#reports-header > a {
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#reports-header > a > svg {
|
||||
margin-left: var(--space-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -7,7 +7,8 @@
|
|||
--theme-background: #121317;
|
||||
--theme-background-alt: #090a0d;
|
||||
--theme-foreground: #cac7ee;
|
||||
--theme-foreground-alt: #a4a3bd;
|
||||
--theme-primary: #9f99f0;
|
||||
--theme-foreground-alt: #9593b9;
|
||||
--theme-foreground-bruh: #7d7d86;
|
||||
--theme-separator: #232833;
|
||||
|
||||
|
|
@ -71,6 +72,7 @@
|
|||
--theme-foreground: #1d1d1f;
|
||||
--theme-foreground-alt: #515154;
|
||||
--theme-foreground-bruh: #86868b;
|
||||
--theme-separator: #d2d2d7;
|
||||
--theme-separator: #b9b9bf;
|
||||
--theme-primary: #6f65f2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -34,11 +34,13 @@ export function Fm() {
|
|||
▷
|
||||
</span>
|
||||
)
|
||||
: (track.loved && (
|
||||
<span class="loved" title="Loved">
|
||||
❤
|
||||
</span>
|
||||
))}
|
||||
: (
|
||||
track.loved && (
|
||||
<span class="loved" title="Loved">
|
||||
❤
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 misties
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ export default function Footer() {
|
|||
</p>
|
||||
<br />
|
||||
<p class="alt alt-font">
|
||||
© 2025 <span class="highlight">favewa</span>{" "}
|
||||
© 2025 <span class="highlight">miwa</span>{" "}
|
||||
• Powered by FreeBSD and autism
|
||||
</p>
|
||||
</footer>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -7,10 +7,9 @@ export function Header(props: any) {
|
|||
return (
|
||||
<header {...props}>
|
||||
<h1 class="typecycle">
|
||||
~
|
||||
<span>favewa</span>
|
||||
~<span>miwa</span>
|
||||
<span>lívia</span>
|
||||
<span>laura</span>
|
||||
<span>clara</span>
|
||||
</h1>
|
||||
<h2>
|
||||
she/her ∘ free software advocate ∘ linguistics enthusiast ૮ ˶ᵔ ᵕ ᵔ˶ sა
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Report } from "../utils/atproto.ts";
|
||||
import { formatReadingTime } from "../utils/blog.ts";
|
||||
|
||||
export interface ReportsProps {
|
||||
reports: Report[];
|
||||
|
|
@ -13,7 +14,28 @@ export default function Reports({ reports }: ReportsProps) {
|
|||
return (
|
||||
<>
|
||||
<header>
|
||||
<h1>$reports</h1>
|
||||
<h1 id="reports-header">
|
||||
$reports
|
||||
<a href="/rss.xml" class="rss">
|
||||
[rss
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M4 11a9 9 0 0 1 9 9" />
|
||||
<path d="M4 4a16 16 0 0 1 16 16" />
|
||||
<circle cx="5" cy="19" r="1" />
|
||||
</svg>
|
||||
]
|
||||
</a>
|
||||
</h1>
|
||||
<h2>thoughts, ramblings, and occasional coherence</h2>
|
||||
</header>
|
||||
|
||||
|
|
@ -21,13 +43,17 @@ export default function Reports({ reports }: ReportsProps) {
|
|||
{reports.map((report) => (
|
||||
<li key={report.rkey}>
|
||||
<a href={`/reports/${report.rkey}`} class="report">
|
||||
<span class="date">{report.createdAt}</span>
|
||||
<span class="date">
|
||||
{report.createdAt} · {formatReadingTime(report.readingTime)}
|
||||
</span>
|
||||
<h3>{report.title}</h3>
|
||||
<p class="excerpt">{report.excerpt}</p>
|
||||
{report.tags && (
|
||||
<div class="tags">
|
||||
{report.tags.map((tag) => (
|
||||
<span key={tag} class="tag">{tag}</span>
|
||||
<span key={tag} class="tag">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"start": "deno serve -A _fresh/server.js",
|
||||
"update": "deno run -A -r jsr:@fresh/update ."
|
||||
"update": "deno run -A -r jsr:@fresh/update .",
|
||||
"rss": "deno run --allow-net --allow-write scripts/generate-rss.ts"
|
||||
},
|
||||
"fmt": {
|
||||
"useTabs": true
|
||||
|
|
@ -33,9 +34,9 @@
|
|||
"@musicorum/lastfm": "npm:@musicorum/lastfm@^0.4.0",
|
||||
"fresh": "jsr:@fresh/core@^2.1.4",
|
||||
"preact": "npm:preact@^10.27.2",
|
||||
"@preact/signals": "npm:@preact/signals@^2.4.0",
|
||||
"@preact/signals": "npm:@preact/signals@^2.5.0",
|
||||
"@fresh/plugin-vite": "jsr:@fresh/plugin-vite@^1.0.7",
|
||||
"vite": "npm:vite@^7.2.1"
|
||||
"vite": "npm:vite@^7.2.2"
|
||||
},
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
|
|
|
|||
132
deno.lock
generated
132
deno.lock
generated
|
|
@ -30,15 +30,15 @@
|
|||
"npm:@mjackson/node-fetch-server@0.7": "0.7.0",
|
||||
"npm:@musicorum/lastfm@0.4": "0.4.0",
|
||||
"npm:@opentelemetry/api@^1.9.0": "1.9.0",
|
||||
"npm:@preact/signals@^2.2.1": "2.4.0_preact@10.27.2",
|
||||
"npm:@preact/signals@^2.4.0": "2.4.0_preact@10.27.2",
|
||||
"npm:@prefresh/vite@^2.4.8": "2.4.11_preact@10.27.2_vite@7.2.1__picomatch@4.0.3",
|
||||
"npm:@preact/signals@^2.2.1": "2.5.0_preact@10.27.2",
|
||||
"npm:@preact/signals@^2.5.0": "2.5.0_preact@10.27.2",
|
||||
"npm:@prefresh/vite@^2.4.8": "2.4.11_preact@10.27.2_vite@7.2.2__picomatch@4.0.3",
|
||||
"npm:esbuild-wasm@~0.25.11": "0.25.12",
|
||||
"npm:esbuild@0.25.7": "0.25.7",
|
||||
"npm:preact-render-to-string@^6.6.3": "6.6.3_preact@10.27.2",
|
||||
"npm:preact@^10.27.0": "10.27.2",
|
||||
"npm:preact@^10.27.2": "10.27.2",
|
||||
"npm:vite@^7.2.1": "7.2.1_picomatch@4.0.3"
|
||||
"npm:vite@^7.2.2": "7.2.2_picomatch@4.0.3"
|
||||
},
|
||||
"jsr": {
|
||||
"@deno/esbuild-plugin@1.2.0": {
|
||||
|
|
@ -671,8 +671,8 @@
|
|||
"@preact/signals-core@1.12.1": {
|
||||
"integrity": "sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA=="
|
||||
},
|
||||
"@preact/signals@2.4.0_preact@10.27.2": {
|
||||
"integrity": "sha512-kVEih9Ty55O+6OKJ85beQJ0gaV++Xci2N2kaQc3LjSUtHKQqB47oMaW6OfwHwzWLRbYsms/326s2ITGiHL7paw==",
|
||||
"@preact/signals@2.5.0_preact@10.27.2": {
|
||||
"integrity": "sha512-+9KrYvCtnssF4Q7e5xdX08aERL2th4w8kkzPAgI3mSEu2FsVeI93hInS2ifwNIzpEw8+9+e5FPtR7di1WvZiWg==",
|
||||
"dependencies": [
|
||||
"@preact/signals-core",
|
||||
"preact"
|
||||
|
|
@ -681,8 +681,8 @@
|
|||
"@prefresh/babel-plugin@0.5.2": {
|
||||
"integrity": "sha512-AOl4HG6dAxWkJ5ndPHBgBa49oo/9bOiJuRDKHLSTyH+Fd9x00shTXpdiTj1W41l6oQIwUOAgJeHMn4QwIDpHkA=="
|
||||
},
|
||||
"@prefresh/core@1.5.8_preact@10.27.2": {
|
||||
"integrity": "sha512-T7HMpakS1iPVCFZvfDLMGyrWAcO3toUN9/RkJUqqoRr/vNhQrZgHjidfhq3awDzAQtw1emDWH8dsOeu0DWqtgA==",
|
||||
"@prefresh/core@1.5.9_preact@10.27.2": {
|
||||
"integrity": "sha512-IKBKCPaz34OFVC+adiQ2qaTF5qdztO2/4ZPf4KsRTgjKosWqxVXmEbxCiUydYZRY8GVie+DQlKzQr9gt6HQ+EQ==",
|
||||
"dependencies": [
|
||||
"preact"
|
||||
]
|
||||
|
|
@ -690,7 +690,7 @@
|
|||
"@prefresh/utils@1.2.1": {
|
||||
"integrity": "sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw=="
|
||||
},
|
||||
"@prefresh/vite@2.4.11_preact@10.27.2_vite@7.2.1__picomatch@4.0.3": {
|
||||
"@prefresh/vite@2.4.11_preact@10.27.2_vite@7.2.2__picomatch@4.0.3": {
|
||||
"integrity": "sha512-/XjURQqdRiCG3NpMmWqE9kJwrg9IchIOWHzulCfqg2sRe/8oQ1g5De7xrk9lbqPIQLn7ntBkKdqWXIj4E9YXyg==",
|
||||
"dependencies": [
|
||||
"@babel/core",
|
||||
|
|
@ -709,113 +709,113 @@
|
|||
"picomatch@2.3.1"
|
||||
]
|
||||
},
|
||||
"@rollup/rollup-android-arm-eabi@4.52.5": {
|
||||
"integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==",
|
||||
"@rollup/rollup-android-arm-eabi@4.53.2": {
|
||||
"integrity": "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==",
|
||||
"os": ["android"],
|
||||
"cpu": ["arm"]
|
||||
},
|
||||
"@rollup/rollup-android-arm64@4.52.5": {
|
||||
"integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==",
|
||||
"@rollup/rollup-android-arm64@4.53.2": {
|
||||
"integrity": "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==",
|
||||
"os": ["android"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@rollup/rollup-darwin-arm64@4.52.5": {
|
||||
"integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==",
|
||||
"@rollup/rollup-darwin-arm64@4.53.2": {
|
||||
"integrity": "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==",
|
||||
"os": ["darwin"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@rollup/rollup-darwin-x64@4.52.5": {
|
||||
"integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==",
|
||||
"@rollup/rollup-darwin-x64@4.53.2": {
|
||||
"integrity": "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==",
|
||||
"os": ["darwin"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@rollup/rollup-freebsd-arm64@4.52.5": {
|
||||
"integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==",
|
||||
"@rollup/rollup-freebsd-arm64@4.53.2": {
|
||||
"integrity": "sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==",
|
||||
"os": ["freebsd"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@rollup/rollup-freebsd-x64@4.52.5": {
|
||||
"integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==",
|
||||
"@rollup/rollup-freebsd-x64@4.53.2": {
|
||||
"integrity": "sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==",
|
||||
"os": ["freebsd"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.52.5": {
|
||||
"integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==",
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.53.2": {
|
||||
"integrity": "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["arm"]
|
||||
},
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.52.5": {
|
||||
"integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==",
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.53.2": {
|
||||
"integrity": "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["arm"]
|
||||
},
|
||||
"@rollup/rollup-linux-arm64-gnu@4.52.5": {
|
||||
"integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==",
|
||||
"@rollup/rollup-linux-arm64-gnu@4.53.2": {
|
||||
"integrity": "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@rollup/rollup-linux-arm64-musl@4.52.5": {
|
||||
"integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==",
|
||||
"@rollup/rollup-linux-arm64-musl@4.53.2": {
|
||||
"integrity": "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@rollup/rollup-linux-loong64-gnu@4.52.5": {
|
||||
"integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==",
|
||||
"@rollup/rollup-linux-loong64-gnu@4.53.2": {
|
||||
"integrity": "sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["loong64"]
|
||||
},
|
||||
"@rollup/rollup-linux-ppc64-gnu@4.52.5": {
|
||||
"integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==",
|
||||
"@rollup/rollup-linux-ppc64-gnu@4.53.2": {
|
||||
"integrity": "sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["ppc64"]
|
||||
},
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.52.5": {
|
||||
"integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==",
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.53.2": {
|
||||
"integrity": "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["riscv64"]
|
||||
},
|
||||
"@rollup/rollup-linux-riscv64-musl@4.52.5": {
|
||||
"integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==",
|
||||
"@rollup/rollup-linux-riscv64-musl@4.53.2": {
|
||||
"integrity": "sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["riscv64"]
|
||||
},
|
||||
"@rollup/rollup-linux-s390x-gnu@4.52.5": {
|
||||
"integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==",
|
||||
"@rollup/rollup-linux-s390x-gnu@4.53.2": {
|
||||
"integrity": "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["s390x"]
|
||||
},
|
||||
"@rollup/rollup-linux-x64-gnu@4.52.5": {
|
||||
"integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==",
|
||||
"@rollup/rollup-linux-x64-gnu@4.53.2": {
|
||||
"integrity": "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@rollup/rollup-linux-x64-musl@4.52.5": {
|
||||
"integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==",
|
||||
"@rollup/rollup-linux-x64-musl@4.53.2": {
|
||||
"integrity": "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@rollup/rollup-openharmony-arm64@4.52.5": {
|
||||
"integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==",
|
||||
"@rollup/rollup-openharmony-arm64@4.53.2": {
|
||||
"integrity": "sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==",
|
||||
"os": ["openharmony"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@rollup/rollup-win32-arm64-msvc@4.52.5": {
|
||||
"integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==",
|
||||
"@rollup/rollup-win32-arm64-msvc@4.53.2": {
|
||||
"integrity": "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==",
|
||||
"os": ["win32"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@rollup/rollup-win32-ia32-msvc@4.52.5": {
|
||||
"integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==",
|
||||
"@rollup/rollup-win32-ia32-msvc@4.53.2": {
|
||||
"integrity": "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==",
|
||||
"os": ["win32"],
|
||||
"cpu": ["ia32"]
|
||||
},
|
||||
"@rollup/rollup-win32-x64-gnu@4.52.5": {
|
||||
"integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==",
|
||||
"@rollup/rollup-win32-x64-gnu@4.53.2": {
|
||||
"integrity": "sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==",
|
||||
"os": ["win32"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@rollup/rollup-win32-x64-msvc@4.52.5": {
|
||||
"integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==",
|
||||
"@rollup/rollup-win32-x64-msvc@4.53.2": {
|
||||
"integrity": "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==",
|
||||
"os": ["win32"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
|
|
@ -825,12 +825,12 @@
|
|||
"await-lock@2.2.2": {
|
||||
"integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw=="
|
||||
},
|
||||
"baseline-browser-mapping@2.8.25": {
|
||||
"integrity": "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==",
|
||||
"baseline-browser-mapping@2.8.27": {
|
||||
"integrity": "sha512-2CXFpkjVnY2FT+B6GrSYxzYf65BJWEqz5tIRHCvNsZZ2F3CmsCB37h8SpYgKG7y9C4YAeTipIPWG7EmFmhAeXA==",
|
||||
"bin": true
|
||||
},
|
||||
"browserslist@4.27.0": {
|
||||
"integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==",
|
||||
"browserslist@4.28.0": {
|
||||
"integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==",
|
||||
"dependencies": [
|
||||
"baseline-browser-mapping",
|
||||
"caniuse-lite",
|
||||
|
|
@ -852,8 +852,8 @@
|
|||
"ms"
|
||||
]
|
||||
},
|
||||
"electron-to-chromium@1.5.246": {
|
||||
"integrity": "sha512-CKp2enkTcw94o8p7P+nb3in3yILO7jAIoERSmkIhGazMuK2eLnPSVUH/dxUveGN8ulJJDjYUv0vV7y2e2AZ0nA=="
|
||||
"electron-to-chromium@1.5.250": {
|
||||
"integrity": "sha512-/5UMj9IiGDMOFBnN4i7/Ry5onJrAGSbOGo3s9FEKmwobGq6xw832ccET0CE3CkkMBZ8GJSlUIesZofpyurqDXw=="
|
||||
},
|
||||
"esbuild-wasm@0.25.12": {
|
||||
"integrity": "sha512-rZqkjL3Y6FwLpSHzLnaEy8Ps6veCNo1kZa9EOfJvmWtBq5dJH4iVjfmOO6Mlkv9B0tt9WFPFmb/VxlgJOnueNg==",
|
||||
|
|
@ -1010,8 +1010,8 @@
|
|||
"preact@10.27.2": {
|
||||
"integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg=="
|
||||
},
|
||||
"rollup@4.52.5": {
|
||||
"integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==",
|
||||
"rollup@4.53.2": {
|
||||
"integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==",
|
||||
"dependencies": [
|
||||
"@types/estree"
|
||||
],
|
||||
|
|
@ -1066,7 +1066,7 @@
|
|||
"multiformats"
|
||||
]
|
||||
},
|
||||
"update-browserslist-db@1.1.4_browserslist@4.27.0": {
|
||||
"update-browserslist-db@1.1.4_browserslist@4.28.0": {
|
||||
"integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==",
|
||||
"dependencies": [
|
||||
"browserslist",
|
||||
|
|
@ -1075,8 +1075,8 @@
|
|||
],
|
||||
"bin": true
|
||||
},
|
||||
"vite@7.2.1_picomatch@4.0.3": {
|
||||
"integrity": "sha512-qTl3VF7BvOupTR85Zc561sPEgxyUSNSvTQ9fit7DEMP7yPgvvIGm5Zfa1dOM+kOwWGNviK9uFM9ra77+OjK7lQ==",
|
||||
"vite@7.2.2_picomatch@4.0.3": {
|
||||
"integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
|
||||
"dependencies": [
|
||||
"esbuild@0.25.12",
|
||||
"fdir",
|
||||
|
|
@ -1530,9 +1530,9 @@
|
|||
"jsr:@fresh/plugin-vite@^1.0.7",
|
||||
"npm:@atproto/api@0.18",
|
||||
"npm:@musicorum/lastfm@0.4",
|
||||
"npm:@preact/signals@^2.4.0",
|
||||
"npm:@preact/signals@^2.5.0",
|
||||
"npm:preact@^10.27.2",
|
||||
"npm:vite@^7.2.1"
|
||||
"npm:vite@^7.2.2"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -10,12 +10,12 @@ export default function Meow() {
|
|||
id="muxiepuff"
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(
|
||||
'<a href="https://acpi.at"><img src="https://acpi.at/88x31.gif" title="favewa" alt="acpi.at" /></a>',
|
||||
'<a href="https://acpi.at"><img src="https://acpi.at/88x31.gif" title="miwa" alt="acpi.at" /></a>',
|
||||
)}
|
||||
>
|
||||
<img
|
||||
src="/88x31.gif"
|
||||
title="favewa (Click to copy to clipboard!)"
|
||||
title="miwa (Click to copy to clipboard!)"
|
||||
alt="acpi.at"
|
||||
/>
|
||||
</button>
|
||||
|
|
|
|||
2
main.ts
2
main.ts
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -19,13 +19,30 @@ export default function About() {
|
|||
<section id="about">
|
||||
<h2>About</h2>
|
||||
<p>
|
||||
Hi! I'm Lívia, a 18-year-old girl from Brazil passionate about open
|
||||
I'm an aspiring electrical engineer with a keen interest in open
|
||||
access to information and knowledge. My technical work centers on
|
||||
functional programming, C99, and writing quirky TypeScript code that
|
||||
explores its more obscure corners and unconventional patterns. I'm
|
||||
drawn to atypical low-level technologies and have a particular
|
||||
interest in the x86 and RISC-V ISAs.
|
||||
</p>
|
||||
<p>
|
||||
<i>In a more personal tone...</i>{" "}
|
||||
Hewwo! I'm Lívia, a 18-year-old girl from Brazil passionate about open
|
||||
access to information, technology, linguistics, functional
|
||||
programming, and pretty much anything that involves understanding
|
||||
technology, human language, or philosophical frameworks. I hope you
|
||||
find something interesting here, and don't hesitate to reach out if
|
||||
you feel like it. <span class="highlight">:3</span>
|
||||
</p>
|
||||
<p>
|
||||
When I'm not studying circuits or coding, it's likely that I'm either
|
||||
exploring linguistics or listening to music. My tastes shift
|
||||
constantly with my hyperfocus, ranging from indie, shoegaze, and J-Pop
|
||||
to speedcore and various metal derivatives. I run a FreeBSD server
|
||||
that hosts this site and various services, serving as my hands-on lab
|
||||
for systems administration. <span class="highlight">^-^</span>
|
||||
</p>
|
||||
<p>
|
||||
Beyond quirky technology, I <i>really</i>{" "}
|
||||
like linguistics and philosophy enthusiast. I'm also autistic n' ADHD,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -25,17 +25,8 @@ export default function Home() {
|
|||
functional programming, C99, and writing quirky TypeScript code that
|
||||
explores its more obscure corners and unconventional patterns. I'm
|
||||
drawn to atypical low-level technologies and have a particular
|
||||
interest in the x86 and RISC-V ISAs.
|
||||
interest in the x86 and RISC-V ISAs. <a href="/about">Read more</a>
|
||||
</p>
|
||||
<p>
|
||||
When I'm not studying circuits or coding, it's likely that I'm either
|
||||
exploring linguistics or listening to music. My tastes shift
|
||||
constantly with my hyperfocus, ranging from indie, shoegaze, and J-Pop
|
||||
to speedcore and various metal derivatives. I run a FreeBSD server
|
||||
that hosts this site and various services, serving as my hands-on lab
|
||||
for systems administration. <span class="highlight">^-^</span>
|
||||
</p>
|
||||
<a href="/about">→ Extended version</a>
|
||||
</section>
|
||||
<section id="links">
|
||||
<h2>Links</h2>
|
||||
|
|
@ -65,12 +56,12 @@ export default function Home() {
|
|||
title="Discord"
|
||||
href="https://discord.com/users/797566974024351745"
|
||||
>
|
||||
@favewa on Discord
|
||||
@rumiwa on Discord
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Telegram" href="https://t.me/favewa">
|
||||
@favewa on Telegram
|
||||
<a title="Telegram" href="https://t.me/lauwawa">
|
||||
@lauwawa on Telegram
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -79,8 +70,8 @@ export default function Home() {
|
|||
<h3>Code</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a title="GitHub" href="https://github.com/misties">
|
||||
misties on GitHub
|
||||
<a title="GitHub" href="https://github.com/fukkai">
|
||||
fukkai on GitHub
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
|
|
@ -108,15 +99,26 @@ export default function Home() {
|
|||
<ul>
|
||||
<li>
|
||||
<ProjectCard
|
||||
author="favewa"
|
||||
author="fukkai"
|
||||
name="cobweb"
|
||||
description="a lightweight, tiny web framework for deno tailored for dynamic no-js applications"
|
||||
url="http://github.com/misties/cobweb"
|
||||
url="http://github.com/fukkai/cobweb"
|
||||
languageColor="#3178c6"
|
||||
languageName="TypeScript"
|
||||
license="BSD-3-Clause"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ProjectCard
|
||||
author="fukkai"
|
||||
name="ratazana"
|
||||
description="minimal implementation of logitech and razer mouse firmware, repurposing their onboard memory as a covert channel for arbitrary data"
|
||||
url="http://github.com/fukkai/ratazana"
|
||||
languageColor="#555"
|
||||
languageName="C"
|
||||
license="BSD-3-Clause"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ProjectCard
|
||||
author="w"
|
||||
|
|
@ -144,7 +146,7 @@ export default function Home() {
|
|||
<span class="key">WEB</span>
|
||||
<code class="value">
|
||||
<a href="https://ko-fi.com/west">west@ko-fi</a>
|
||||
<a href="https://github.com/sponsors/misties">misties@github</a>
|
||||
<a href="https://github.com/sponsors/fukkai">fukkai@github</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -7,11 +7,13 @@ import { PageProps } from "fresh";
|
|||
import { getCachedReports } from "@/utils/atproto.ts";
|
||||
import Empty from "@/components/Empty.tsx";
|
||||
import "@/assets/report.css";
|
||||
import { formatReadingTime } from "../../utils/blog.ts";
|
||||
import { Head } from "fresh/runtime";
|
||||
|
||||
export default function PostPage(props: PageProps) {
|
||||
const { rkey } = props.params;
|
||||
const post = getCachedReports().find((rep) =>
|
||||
rep.rkey === rkey.toLowerCase()
|
||||
const post = getCachedReports().find(
|
||||
(rep) => rep.rkey === rkey.toLowerCase(),
|
||||
);
|
||||
|
||||
if (!post) {
|
||||
|
|
@ -20,17 +22,57 @@ export default function PostPage(props: PageProps) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{post.title} - acpi.at</title>
|
||||
<meta name="title" content={`${post.title} - acpi.at`} />
|
||||
<meta name="description" content={post.excerpt} />
|
||||
<meta name="author" content="acpi.at" />
|
||||
{post.tags && <meta name="keywords" content={post.tags.join(", ")} />}
|
||||
<meta name="theme-color" content="#a0bdfc" />
|
||||
<meta
|
||||
name="theme-color"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
content="#1a1a2e"
|
||||
/>
|
||||
<meta property="og:type" content="article" />
|
||||
<link rel="canonical" href={`https://acpi.at/reports/${post.rkey}`} />
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="acpi.at" />
|
||||
<meta property="og:title" content={post.title} />
|
||||
<meta property="og:description" content={post.excerpt} />
|
||||
<meta property="og:image" content="" />
|
||||
<meta
|
||||
property="og:url"
|
||||
content={`https://acpi.at/reports/${post.rkey}`}
|
||||
/>
|
||||
<meta property="article:published_time" content={post.createdAt} />
|
||||
<meta property="article:author" content="acpi.at" />
|
||||
{post.tags &&
|
||||
post.tags.map((tag) => (
|
||||
<meta key={tag} property="article:tag" content={tag} />
|
||||
))}
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:title" content={post.title} />
|
||||
<meta name="twitter:description" content={post.excerpt} />
|
||||
<meta name="twitter:image" content="" />
|
||||
</Head>
|
||||
<a href="/reports">← exit this report</a>
|
||||
|
||||
<br />
|
||||
<article>
|
||||
<header>
|
||||
<div class="meta">
|
||||
<time datetime={post?.createdAt}>{post?.createdAt}</time>
|
||||
</div>
|
||||
<h1>{post.title}</h1>
|
||||
<div class="meta">
|
||||
<time datetime={post.createdAt}>{post.createdAt}</time> ·{" "}
|
||||
{formatReadingTime(post.readingTime)}
|
||||
</div>
|
||||
{post.tags && (
|
||||
<div class="tags">
|
||||
{post.tags.map((tag) => <span key={tag} class="tag">{tag}</span>)}
|
||||
{post.tags.map((tag) => (
|
||||
<span key={tag} class="tag">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
|
|
@ -38,13 +80,13 @@ export default function PostPage(props: PageProps) {
|
|||
class="content typewriting"
|
||||
dangerouslySetInnerHTML={{ __html: post.content }}
|
||||
/>
|
||||
<footer>
|
||||
<a href="/">
|
||||
← You reached the end of the page. It is now safe to turn off your
|
||||
computer.
|
||||
</a>
|
||||
</footer>
|
||||
</article>
|
||||
<footer>
|
||||
<a href="/" style="color: var(--theme-foreground-alt)">
|
||||
← You reached the end of the page. It is now safe to turn off your
|
||||
computer.
|
||||
</a>
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
@ -7,10 +7,51 @@ import Reports from "@/components/Reports.tsx";
|
|||
import Links from "@/components/Links.tsx";
|
||||
import { getCachedReports } from "@/utils/atproto.ts";
|
||||
import "@/assets/report.css";
|
||||
import { Head } from "fresh/runtime";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>$reports - acpi.at</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Thoughts, ramblings, and occasional coherence. A collection of personal essays on stuff that randomly come across my mind."
|
||||
/>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="personal blog, essays, mental health, philosophy, linguistics, life writing, reflections"
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="$reports - acpi.at" />
|
||||
<meta
|
||||
name="og:description"
|
||||
content="Thoughts, ramblings, and occasional coherence. A collection of personal essays on stuff that randomly come across my mind."
|
||||
/>
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Thoughts, ramblings, and occasional coherence. A collection of personal essays on stuff that randomly come across my mind."
|
||||
/>
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:title" content="$reports - acpi.at" />
|
||||
<meta property="og:image" content="https://acpi.at/bnuy.webp" />
|
||||
<meta property="og:url" content="https://acpi.at/reports" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta name="theme-color" content="#a0bdfc" />
|
||||
<meta
|
||||
name="theme-color"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
content="#1a1a2e"
|
||||
/>
|
||||
<link rel="canonical" href="https://acpi.at/reports" />
|
||||
<meta name="robots" content="index, follow" />
|
||||
<link
|
||||
rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="acpi.at - $reports"
|
||||
href="https://acpi.at/rss.xml"
|
||||
/>
|
||||
</Head>
|
||||
<Links selected="reports" />
|
||||
<Reports reports={getCachedReports()} />
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#!/usr/bin/env -S deno run --allow-read --allow-write
|
||||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { walk } from "https://deno.land/std/fs/walk.ts";
|
||||
|
||||
const copyrightHeader = `/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
`;
|
||||
|
|
|
|||
66
scripts/generate-rss.ts
Executable file
66
scripts/generate-rss.ts
Executable file
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#!/usr/bin/env -S deno run --allow-net --allow-write
|
||||
/**
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { getPosts, type Report } from "../utils/atproto.ts";
|
||||
|
||||
function escapeXml(unsafe: string): string {
|
||||
return unsafe
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function stripHtml(html: string): string {
|
||||
return html
|
||||
.replace(/<[^>]+>/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
function generateRSSItem(report: Report): string {
|
||||
const link = `https://acpi.at/reports/${report.rkey}`;
|
||||
const description = report.excerpt ||
|
||||
stripHtml(report.content).substring(0, 200);
|
||||
|
||||
return [
|
||||
` <item>`,
|
||||
` <title>${escapeXml(report.title)}</title>`,
|
||||
` <link>${link}</link>`,
|
||||
` <guid>${link}</guid>`,
|
||||
` <pubDate>${report.date.toUTCString()}</pubDate>`,
|
||||
` <description>${escapeXml(description)}</description>`,
|
||||
` </item>`,
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
async function generateRSS() {
|
||||
const reports = await getPosts();
|
||||
const items = reports.map(generateRSSItem);
|
||||
const xml = [
|
||||
`<?xml version="1.0" encoding="UTF-8"?>`,
|
||||
`<rss version="2.0">`,
|
||||
` <channel>`,
|
||||
` <title>$reports - acpi.at</title>`,
|
||||
` <link>https://acpi.at/reports</link>`,
|
||||
` <description>thoughts, ramblings, and occasional coherence</description>`,
|
||||
items.join("\n"),
|
||||
` </channel>`,
|
||||
`</rss>`,
|
||||
].join("\n");
|
||||
await Deno.writeTextFile("./static/rss.xml", xml);
|
||||
console.log("done");
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
await generateRSS();
|
||||
}
|
||||
29
static/rss.xml
Normal file
29
static/rss.xml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>$reports - acpi.at</title>
|
||||
<link>https://acpi.at/reports</link>
|
||||
<description>thoughts, ramblings, and occasional coherence</description>
|
||||
<item>
|
||||
<title>When awareness feels like a burden</title>
|
||||
<link>https://acpi.at/reports/3m4yhdcgqr425</link>
|
||||
<guid>https://acpi.at/reports/3m4yhdcgqr425</guid>
|
||||
<pubDate>Thu, 06 Nov 2025 23:54:23 GMT</pubDate>
|
||||
<description>The worst days of my life happen to be the ones where I am overly aware about my surroundings and problems.</description>
|
||||
</item>
|
||||
<item>
|
||||
<title>Why Brazilian Portuguese speakers struggle to understand European Portuguese</title>
|
||||
<link>https://acpi.at/reports/3m4yszxlivv25</link>
|
||||
<guid>https://acpi.at/reports/3m4yszxlivv25</guid>
|
||||
<pubDate>Sat, 16 Aug 2025 00:38:02 GMT</pubDate>
|
||||
<description>EP speakers lowkey be like: 'ixtou a apnhr murangjs pah'</description>
|
||||
</item>
|
||||
<item>
|
||||
<title>Echoes of thought in a world wired to produce</title>
|
||||
<link>https://acpi.at/reports/3m4yrn7md2k25</link>
|
||||
<guid>https://acpi.at/reports/3m4yrn7md2k25</guid>
|
||||
<pubDate>Tue, 20 May 2025 00:02:53 GMT</pubDate>
|
||||
<description>For the first time in a few months, I had some time alone to process my thoughts.</description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { calculateReadingTime, ReadingTimeResult } from "./blog.ts";
|
||||
import { withInterval } from "./temp.ts";
|
||||
|
||||
export interface Report {
|
||||
|
|
@ -14,6 +15,7 @@ export interface Report {
|
|||
createdAt: string;
|
||||
tags?: string[];
|
||||
visibility: string;
|
||||
readingTime: ReadingTimeResult;
|
||||
date: Date;
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +61,7 @@ export async function getPosts(cursor?: string): Promise<Report[]> {
|
|||
...value,
|
||||
rkey: rkey(uri),
|
||||
date: new Date(value.createdAt),
|
||||
readingTime: value.content ? calculateReadingTime(value.content) : 1,
|
||||
createdAt: new Date(value.createdAt).toISOString().slice(0, 10).replace(
|
||||
/-/g,
|
||||
".",
|
||||
|
|
@ -82,6 +85,9 @@ export async function retrieveReport(rkey: string): Promise<Report | null> {
|
|||
|
||||
return {
|
||||
...response.value,
|
||||
readingTime: response.value.content
|
||||
? calculateReadingTime(response.value.content)
|
||||
: 1,
|
||||
cid: response.cid,
|
||||
rkey,
|
||||
} as Report;
|
||||
|
|
|
|||
68
utils/blog.ts
Normal file
68
utils/blog.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export interface ReadingTimeOptions {
|
||||
wordsPerMinute?: number;
|
||||
imageTime?: number;
|
||||
codeBlockTime?: number;
|
||||
chineseKoreanReadingSpeed?: number;
|
||||
}
|
||||
|
||||
export interface ReadingTimeResult {
|
||||
minutes: number;
|
||||
words: number;
|
||||
images: number;
|
||||
codeBlocks: number;
|
||||
}
|
||||
|
||||
export function formatReadingTime(input: ReadingTimeResult) {
|
||||
return `${input.words} words · ${
|
||||
input.images ? `${input.images} images · ` : ""
|
||||
}${
|
||||
input.codeBlocks ? `${input.codeBlocks} code blocks · ` : ""
|
||||
}${input.minutes} minutes`;
|
||||
}
|
||||
|
||||
export function calculateReadingTime(
|
||||
input: string,
|
||||
options: ReadingTimeOptions = {},
|
||||
): ReadingTimeResult {
|
||||
const {
|
||||
wordsPerMinute = 200,
|
||||
imageTime = 12,
|
||||
codeBlockTime = 15,
|
||||
chineseKoreanReadingSpeed = 260,
|
||||
} = options;
|
||||
|
||||
let images = 0, preBlocks = 0, codeBlocks = 0;
|
||||
|
||||
const text = input
|
||||
.replace(/<img[^>]*>/gi, () => (images++, ""))
|
||||
.replace(/<pre[^>]*>[\s\S]*?<\/pre>/gi, () => (preBlocks++, ""))
|
||||
.replace(/<code[^>]*>[\s\S]*?<\/code>/gi, () => (codeBlocks++, ""));
|
||||
|
||||
const cjkRegex = /[\u4E00-\u9FFF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF]/g;
|
||||
const cjkMatches = text.match(cjkRegex);
|
||||
const cjkCharacters = cjkMatches?.length ?? 0;
|
||||
|
||||
const textWithoutCJK = cjkCharacters ? text.replace(cjkRegex, " ") : text;
|
||||
const words = textWithoutCJK.trim().split(/\s+/).reduce(
|
||||
(n, w) => n + (w && /\w/.test(w) ? 1 : 0),
|
||||
0,
|
||||
);
|
||||
|
||||
const totalMinutes = Math.ceil(
|
||||
words / wordsPerMinute +
|
||||
cjkCharacters / chineseKoreanReadingSpeed +
|
||||
(images * imageTime + (preBlocks + codeBlocks) * codeBlockTime) / 60,
|
||||
);
|
||||
|
||||
return {
|
||||
minutes: Math.max(totalMinutes || 2, 2),
|
||||
words: words + cjkCharacters,
|
||||
images,
|
||||
codeBlocks: preBlocks + codeBlocks,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue