recreate maplestory guild bbs layout

This commit is contained in:
haetae 2025-01-27 02:12:04 -05:00
parent cfb3379ef0
commit 815650efef
62 changed files with 461 additions and 72 deletions

View File

@ -2,10 +2,14 @@
import { defineConfig } from 'astro/config';
import db from '@astrojs/db';
import node from '@astrojs/node';
import { modifiedTime } from './last-modified.mjs';
// https://astro.build/config
export default defineConfig({
site: "https://haetae.gay",
markdown: {
remarkPlugins: [modifiedTime],
},
integrations: [db()],
adapter: node({
mode: 'standalone'

BIN
bun.lockb

Binary file not shown.

9
last-modified.mjs Normal file
View File

@ -0,0 +1,9 @@
import { statSync } from "fs";
export function modifiedTime() {
return function (tree, file) {
const path = file.history[0];
const result = statSync(path);
file.data.astro.frontmatter.lastModified = result.mtime;
}
}

View File

@ -14,6 +14,7 @@
"@astrojs/rss": "^4.0.11",
"astro": "^5.1.7",
"astro-breadcrumbs": "^3.3.1",
"dayjs": "^1.11.13",
"markdown-it": "^14.1.0",
"sanitize-html": "^2.14.0"
},

BIN
public/fonts/PIXEAB.woff2 Normal file

Binary file not shown.

BIN
public/fonts/PIXEAR.woff2 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

View File

Before

Width:  |  Height:  |  Size: 689 B

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

BIN
src/assets/moods/angry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

BIN
src/assets/moods/blah.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 790 B

BIN
src/assets/moods/flirty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

BIN
src/assets/moods/full.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/assets/moods/giggly.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 948 B

BIN
src/assets/moods/happy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

BIN
src/assets/moods/horny.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

BIN
src/assets/moods/hot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
src/assets/moods/hurt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

BIN
src/assets/moods/irate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

BIN
src/assets/moods/lazy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

BIN
src/assets/moods/loved.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
src/assets/moods/sad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

BIN
src/assets/moods/scared.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

BIN
src/assets/moods/sick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 B

BIN
src/assets/moods/silly.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

BIN
src/assets/moods/sleepy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

BIN
src/assets/moods/smooch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

View File

@ -6,6 +6,8 @@
--title-font: "Kiwi Soda", Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
--mono-font: "Departure Mono", ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
--serif-font: "Redaction 35", 'Iowan Old Style', 'Palatino Linotype', 'URW Palladio L', P052, serif;
--sans-font: "MLSS", 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
--arial-font: "Arial Pixel", Arial, Helvetica, sans-serif;
}
body {

View File

@ -1,3 +1,15 @@
@font-face {
font-family: "Arial Pixel";
src: url("/fonts/PIXEAR.woff2") format("woff2");
font-weight: normal;
}
@font-face {
font-family: "Arial Pixel";
src: url("/fonts/PIXEAB.woff2") format("woff2");
font-weight: bold;
}
@font-face {
font-family: "Departure Mono";
src: url("/fonts/DepartureMono-Regular.woff2") format("woff2");
@ -10,6 +22,12 @@
font-weight: normal;
}
@font-face {
font-family: "MLSS";
src: url("/fonts/mario-luigi-rpg-speech-text.woff2") format("woff2");
font-weight: normal;
}
@font-face {
font-family: "Redaction 35";
src: url("/fonts/Redaction_35-Regular.woff2") format("woff2");

View File

@ -5,13 +5,14 @@ interface Props {
imagePath: string;
alt: string;
caption?: string;
className?: string[] | string;
}
const { imagePath, alt, caption }: Props = Astro.props;
const { imagePath, alt, caption, className }: Props = Astro.props;
const images = import.meta.glob<{ default: ImageMetadata }>("/src/assets/**/*.{jpeg,jpg,png,webp,gif}");
if (!images[imagePath]) throw new Error(`"${imagePath}" does not exist in glob: "src/assets/**/*.{jpeg,jpg,png,webp,gif}"`);
---
<figure>
<figure class:list={className}>
<Image src={images[imagePath]()} {alt} />
<figcaption>{caption ?? alt}</figcaption>
{caption && <figcaption>{caption}</figcaption>}
</figure>

View File

@ -1,6 +1,11 @@
---
title: hey girl hey
pubDate: 2024-02-03
currently:
mood: happy
reading: hella
watching: stuff
playing: balatro
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pretium augue elit, eget interdum massa lobortis ut. Praesent facilisis ornare aliquam. Donec sit amet volutpat ipsum, id ultricies urna. Donec vestibulum sagittis felis, tempor fermentum urna posuere at. Vestibulum cursus mauris eget bibendum blandit. Aenean at augue porttitor, bibendum massa ut, laoreet lacus. Phasellus fermentum tincidunt lectus vel volutpat. Proin sagittis vel sem sit amet consequat. Vestibulum ac laoreet quam. Mauris eu purus sit amet odio maximus dictum. Mauris quam tellus, tempus eu faucibus in, mollis quis velit. Phasellus nisl mauris, congue vel magna a, rutrum aliquet ante. Proin in ante pharetra, vestibulum nisi vel, fringilla tortor. Etiam mattis, mauris et mattis sagittis, orci eros ornare risus, vitae consequat ligula nulla eget quam.

View File

@ -1,10 +1,19 @@
import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";
import { rssSchema } from "@astrojs/rss";
import moods from "@/utils/moods";
const blog = defineCollection({
loader: glob({ pattern: "*.md", base: "./src/content/blog" }),
schema: rssSchema,
schema: rssSchema.extend({
currently: z.object({
mood: z.enum(moods).optional(),
reading: z.ostring(),
watching: z.ostring(),
playing: z.ostring(),
listening: z.ostring(),
}).optional(),
}),
});
function generateFicSlug({ entry, data }: { entry: string, data: any }): string {

View File

@ -1,11 +1,63 @@
---
import type { MarkdownLayoutProps } from "astro";
import Navbar from "@/components/Navbar.astro";
import Figure from "@/components/Figure.astro";
import Layout from "./Layout.astro";
import border from "@/assets/images/border.png";
import frame from "@/assets/images/frame.png";
type Props = MarkdownLayoutProps<{
avatar?: string;
avatarText?: string;
}>;
const { frontmatter } = Astro.props;
---
<Layout>
<Navbar />
<main>
{frontmatter.avatar && frontmatter.avatarText && (
<Figure className="avatar" imagePath={frontmatter.avatar} alt={frontmatter.avatarText} />
)}
<article>
<slot />
</article>
</main>
</Layout>
<style define:vars={{ borderImage: `url(${border.src})`, frameImage: `url(${frame.src})` }}>
main {
margin: 3rem auto;
max-width: clamp(50ch, 80ch, 100%);
}
article {
padding: 1rem 1.5rem;
color: #f8f8f8;
text-shadow: 2px 2px #000;
background: #202020;
border-image: var(--frameImage) 6 9 / 12px 18px / 10px repeat;
image-rendering: pixelated;
h1, h2, h3 {
font-family: var(--body-font);
border-bottom: 2px solid #f8f8f8;
}
}
:global(.avatar) {
width: fit-content;
margin: 0 auto 2rem;
border-image: var(--borderImage) 5 4 / 10px 8px / 8px repeat;
image-rendering: pixelated;
img {
display: grid;
place-content: center;
width: 80px;
height: auto;
image-rendering: pixelated;
}
}
</style>

View File

@ -2,21 +2,32 @@
import { getCollection } from "astro:content";
import Layout from "./Layout.astro";
import Navbar from "@/components/Navbar.astro";
import moods from "@/utils/moods";
import outerBBS from "@/assets/images/guild-bbs.png";
import innerBBS from "@/assets/images/guild-bbs-content.png";
import { Image } from "astro:assets";
interface Props {
title: string;
date: Date;
currently?: {
mood?: string;
reading?: string;
listening?: string;
watching?: string;
playing?: string;
}
}
const blog = await getCollection("blog");
blog.length = Math.min(blog.length, 5);
blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
const { title, date } = Astro.props;
const { title, date, currently } = Astro.props;
---
<Layout>
<Navbar />
<section>
<main>
<nav id="blog-links">
<h1>recent posts</h1>
<ul>
@ -36,33 +47,80 @@ const { title, date } = Astro.props;
</ul>
</nav>
<main>
<section>
<article>
<div class="inner">
<header>
<h1>{title}</h1>
<hr />
<div class="info">
<time datetime={date.toISOString()}>
Posted on
{date.toLocaleDateString(undefined, { dateStyle: "long" })}
<span class="title">Date</span>
<span class="desc">{date.toLocaleDateString(undefined, { dateStyle: "long" })}</span>
</time>
</div>
</header>
<div class="content">
<slot />
</div>
{currently && (
<aside>
{currently?.mood && (
<dl>
<dt>Current mood</dt>
<dd>
<Image src={`/src/assets/moods/${moods.find(mood => mood === currently?.mood)}.png`} width="32" height="32" alt={currently.mood} />
</dd>
</dl>
)}
{currently.playing && (
<dl>
<dt>Currently playing</dt>
<dd>{currently.playing}</dd>
</dl>
)}
{currently.watching && (
<dl>
<dt>Currently watching</dt>
<dd>{currently.watching}</dd>
</dl>
)}
{currently.reading && (
<dl>
<dt>Currently reading</dt>
<dd>{currently.reading}</dd>
</dl>
)}
{currently.listening && (
<dl>
<dt>Currently listening</dt>
<dd>{currently.listening}</dd>
</dl>
)}
</aside>
)}
</div>
</article>
<slot name="pagination" />
</main>
</section>
</main>
</Layout>
<style>
section {
<style define:vars={{ outerBorder: `url(${outerBBS.src})`, innerBorder: `url(${innerBBS.src})` }}>
main {
display: grid;
grid-template-columns: repeat(2, auto);
justify-content: center;
gap: 1rem;
height: calc(100% - 2.5rem);
@media screen and (max-width: 1270px) {
grid-template-columns: 1fr;
margin: 0 1rem;
}
}
#blog-links {
@ -92,61 +150,127 @@ const { title, date } = Astro.props;
}
}
@media screen and (max-width: 1251px) {
@media screen and (max-width: 1270px) {
border-bottom: 2px solid black;
}
}
main {
section {
width: 75ch;
@media screen and (max-width: 950px) {
@media screen and (max-width: 1270px) {
width: 100%;
margin: 0 1rem;
}
}
article {
font: 1rem var(--arial-font);
letter-spacing: 1px;
border-image: var(--outerBorder) 26 11 12 13 fill / 52px 22px 24px 26px;
border-style: solid;
image-rendering: pixelated;
padding: calc(2rem + 2px) calc(1rem - 2px) calc(1rem - 4px) calc(1rem + 2px);
.inner {
border-image: var(--innerBorder) 4 3 3 fill / 8px 6px 6px;
border-style: solid;
image-rendering: pixelated;
margin: 14px 4px 8px;
padding: 2px 1px 1px;
}
header {
padding: 1rem;
padding-left: 2rem;
border-bottom: 2px solid #ccccdd;
time { padding-left: 3rem; }
h1 {
font: bold 1rem var(--arial-font);
text-align: center;
margin: 6px 2px;
padding: 2px 0;
background-color: #bbccdd;
}
@media screen and (max-width: 950px) {
padding: 0.25rem;
padding-left: 2rem;
.info {
display: flex;
gap: 2px;
border-style: solid;
border-width: 2px;
border-top-color: #eeeeff;
border-right-color: #eeeeff;
border-left-color: #eeffff;
border-bottom-color: #eeffff;
padding: 2px 4px;
time, .section {
display: flex;
width: 100%;
}
.title {
background-color: #eeeeff;
padding: 4px 6px;
}
.desc {
background-color: #ddddee;
padding: 4px 6px;
flex: 1;
}
}
hr {
background-color: #99bbcc;
border: none;
height: 2px;
}
}
.content {
position: relative;
background-image: linear-gradient(#d1d5db 2px, transparent 0px);
background-size: 100% 1em;
background-image: linear-gradient(to right, #fff 5px, transparent 2px), linear-gradient(#d1d5db 2px, transparent 2px);
background-size: 10px 2em;
background-position-y: 1.75rem;
margin: 0 2rem 2rem;
padding: 2rem;
font-size: 2rem;
line-height: 1em;
border: 2px solid black;
line-height: 2em;
margin-trim: block;
p { margin-block-end: 1em; }
&::before, &::after {
position: absolute;
bottom: 100%;
left: 30px;
content: "";
border: 20px solid transparent;
}
p { margin-block: 1lh; }
&::before { border-bottom: 20px solid black; }
&::after {
border-bottom: 20px solid white;
margin-bottom: -3px;
@supports not (margin-trim: block) {
:first-child { margin-block-start: 0; }
:last-child { margin-block-end: 0; }
}
@media screen and (max-width: 950px) {
background-position-y: 0.8rem;
padding: 1rem;
margin: 0.25rem 0;
}
}
aside {
border-top: 2px solid #88aabb;
dl {
display: flex;
align-items: center;
padding: 2px 6px;
border-bottom: 2px solid #88aabb;
dt {
background-color: #eeeeff;
padding: 4px 6px;
}
dd {
background-color: #ddddee;
padding: 4px 6px;
flex: 1;
}
&:first-child > dt ~ dd { padding: 0; }
&:last-child { border: none; }
}
}
}

View File

@ -1,14 +1,17 @@
---
import Layout from "./Layout.astro";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
interface Props {
title: string;
date: Date;
notes?: string;
lastModified?: string;
lastModified?: Date;
}
const { title, date, notes, lastModified }: Props = Astro.props;
dayjs.extend(utc);
---
<Layout>
<slot name="breadcrumbs" />
@ -16,13 +19,13 @@ const { title, date, notes, lastModified }: Props = Astro.props;
<main>
<header>
<h1>{title}</h1>
<time datetime={date.toISOString()}>
{date.toLocaleDateString(undefined, {
weekday: "long", year: "numeric", month: "long", day: "numeric",
})}
<time datetime={dayjs(date).utc(true).toISOString()}>
Published on {dayjs(date).utc(true).format("MMMM DD, YYYY")}
</time>
{lastModified && (
<time datetime={lastModified}>{lastModified}</time>
<time datetime={dayjs(lastModified).utc(true).toISOString()}>
Last edited on {dayjs(lastModified).utc(true).format("MMMM DD, YYYY")}
</time>
)}
{notes && (
<blockquote><Fragment set:html={notes.split("\n").join("<br />")} /></blockquote>
@ -45,6 +48,7 @@ const { title, date, notes, lastModified }: Props = Astro.props;
article, blockquote { font-family: var(--serif-font); }
header {
blockquote {
margin: 1rem;
font-size: 1.125rem;
@ -54,6 +58,8 @@ const { title, date, notes, lastModified }: Props = Astro.props;
content: "Authors Notes:";
font-weight: bold;
line-height: 1;
alt: "Author's Notes:";
}
}
}
@ -61,7 +67,12 @@ const { title, date, notes, lastModified }: Props = Astro.props;
margin: 1rem 0;
font-size: 1.25rem;
line-height: 1.5;
margin-trim: block;
p { margin-block-end: 1rem; }
p { margin-block: 1lh; }
@supports not (margin-trim: block) {
:first-child { margin-block-start: 0; }
:last-child { margin-block-end: 0; }
}
}
</style>

View File

@ -16,6 +16,7 @@ const { title = "haetae" }: Props = Astro.props;
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<meta name="pinterest" content="nopin nohover" />
<slot name="header" />
<title>{title}</title>
</head>
<body>

View File

@ -1,6 +1,8 @@
---
title: about me
layout: ../layouts/About.astro
avatar: /src/assets/images/portrait-0025.png
avatarText: pikachu from pokemon mystery dungeon
---
# hello!

View File

@ -20,7 +20,7 @@ const current = blog.findIndex(entry => entry.id === Astro.params.id);
const previous = current + 1 === blog.length ? undefined : blog[current + 1];
const next = current === 0 ? undefined : blog[current - 1];
---
<Blog title={entry.data.title!} date={entry.data.pubDate!}>
<Blog title={entry.data.title!} date={entry.data.pubDate!} currently={entry.data.currently}>
<Content />
{(previous || next) && (

View File

@ -13,6 +13,7 @@ const getMonth = (id: number) => {
}
---
<Layout>
<Fragment slot="header" set:html={`<link rel="alternate" type="application/rss+xml" title="haetae's blog" href=${new URL("/blog/rss.xml", Astro.site)} />`} />
<h1>blog</h1>
<ul>
{Object.entries(sorted).map(entry => (
@ -31,4 +32,5 @@ const getMonth = (id: number) => {
</li>
))}
</ul>
<a href="/blog/rss.xml">rss feed</a>
</Layout>

View File

@ -3,6 +3,10 @@ import Chapter from "@/layouts/Chapter.astro";
import type { GetStaticPaths } from "astro";
import { getCollection, render } from "astro:content";
import { Breadcrumbs } from "astro-breadcrumbs";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
dayjs.extend(utc);
export const getStaticPaths = (async () => {
const chapters = await getCollection("chapters");
@ -17,7 +21,7 @@ export const getStaticPaths = (async () => {
const { ficId, chapterId } = Astro.params;
const { chapter } = Astro.props;
const { Content } = await render(chapter);
const { Content, remarkPluginFrontmatter } = await render(chapter);
const chapters = await getCollection("chapters", ({ id }) => {
return id.split("/")[0] === ficId;
@ -29,14 +33,14 @@ chapters.sort((a, b) => a.data.sortOrder - b.data.sortOrder);
const current = chapters.findIndex(chapter => chapter.id === `${ficId}/${chapterId}`);
const next = current + 1 === chapters.length ? undefined : chapters[current + 1];
const previous = current === 0 ? undefined : chapters[current - 1];
// lastmodified
const lastModified = new Date(remarkPluginFrontmatter.lastModified);
const links = [
{ index: "last", text: chapter.data.title },
{ index: 2, text: fic[0].data.title },
];
---
<Chapter title={chapter.data.title} date={chapter.data.publishedAt} notes={chapter.data.notes}>
<Chapter title={chapter.data.title} date={chapter.data.publishedAt} {lastModified} notes={chapter.data.notes}>
<Fragment slot="breadcrumbs">
<Breadcrumbs id="breadcrumbs" customizeLinks={links} linkTextFormat="capitalized">
<Fragment slot="separator" set:text="/" />
@ -99,6 +103,13 @@ const links = [
justify-self: center;
}
#chapter-select {
background-color: black;
color: white;
border: none;
padding: 0.25rem 0.5rem;
}
#previous {
grid-area: 2 / 1 / 2 / 1;
justify-self: left;

View File

@ -19,6 +19,7 @@ chapters.length = Math.min(chapters.length, 5);
chapters.sort((a, b) => a.data.sortOrder - b.data.sortOrder);
---
<Layout>
<Fragment slot="header" set:html={`<link rel="alternate" type="application/rss+xml" title="${fic.data.title}" href=${new URL(`/fics/${Astro.params.ficId}/rss.xml`, Astro.site)} />`} />
<section>
<h1>{fic.data.title}</h1>
<header class="info">

View File

@ -18,7 +18,9 @@ chapters.sort((a, b) => a.data.publishedAt.valueOf() - b.data.publishedAt.valueO
{post.data.publishedAt.toLocaleDateString(undefined, { dateStyle: "medium" })}
</time>
<a href={`/fics/${post.id}`}>{post.data.title}</a> in
<a href={`/fics/${post.id.split("/")[0]}`}>{fics.find(({ id }) => post.id.startsWith(id))?.data.title}</a>
<a href={`/fics/${post.id.split("/")[0]}`}>
{fics.find(({ id }) => post.id.startsWith(id))?.data.title}
</a>
</li>
))}
</ul>

134
src/utils/moods.ts Normal file
View File

@ -0,0 +1,134 @@
export default [
"accomplished",
"aggravated",
"amused",
"angry",
"annoyed",
"anxious",
"apathetic",
"artistic",
"awake",
"bitchy",
"blah",
"blank",
"bored",
"bouncy",
"busy",
"calm",
"cheerful",
"chipper",
"cold",
"complacent",
"confused",
"contemplative",
"content",
"cranky",
"crappy",
"crazy",
"creative",
"crushed",
"curious",
"cynical",
"depressed",
"determined",
"devious",
"dirty",
"disappointed",
"discontent",
"distressed",
"ditzy",
"dorky",
"drained",
"drunk",
"ecstatic",
"embarrassed",
"energetic",
"enraged",
"enthralled",
"envious",
"exanimate",
"excited",
"exhausted",
"flirty",
"frustrated",
"full",
"geeky",
"giddy",
"giggly",
"gloomy",
"good",
"grateful",
"groggy",
"grumpy",
"guilty",
"happy",
"high",
"hopeful",
"horny",
"hot",
"hungry",
"hyper",
"impressed",
"indescribable",
"indifferent",
"infuriated",
"intimidated",
"irate",
"irritated",
"jealous",
"jubilant",
"lazy",
"lethargic",
"listless",
"lonely",
"loved",
"melancholy",
"mellow",
"mischievous",
"moody",
"morose",
"naughty",
"nauseated",
"nerdy",
"nervous",
"nostalgic",
"numb",
"okay",
"optimistic",
"peaceful",
"pensive",
"pessimistic",
"pissed off",
"pleased",
"predatory",
"productive",
"quixotic",
"recumbent",
"refreshed",
"rejected",
"rejuvenated",
"relaxed",
"relieved",
"restless",
"rushed",
"sad",
"satisfied",
"scared",
"shocked",
"sick",
"silly",
"sleepy",
"sore",
"stressed",
"surprised",
"sympathetic",
"thankful",
"thirsty",
"thoughtful",
"tired",
"touched",
"uncomfortable",
"weird",
"working",
"worried",
] as const;