Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ k8s-context
*.sqlite3*
tsconfig.tsbuildinfo
.react-router
tailwind.css
userInfoCache.json
*timestamp*
vite.config.ts*
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ RUN apk add --no-cache python3 make g++
COPY package.json package-lock.json ./
RUN npm install

COPY vite.config.ts tailwind.config.js kysely.config.ts tsconfig.json .eslint* .prettierignore ./
COPY vite.config.ts kysely.config.ts tsconfig.json .eslint* .prettierignore ./
COPY app ./app

RUN npm run build
Expand Down
65 changes: 65 additions & 0 deletions aesthetic/courts.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions aesthetic/eunomia.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Eunomia: Greek Goddess of Good Order

Eunomia is a goddess of the ancient Greek pantheon, born of two of the most powerful figures in the divine hierarchy: Zeus, king of the Olympian gods, and Themis, the Titaness of divine law and cosmic order. Her genealogy is recorded in Hesiod's Theogony, composed around the late eighth or early seventh century BCE, which establishes her as one of the second generation of the Horae -- goddesses who governed both the rhythms of the natural seasons and the moral order of human civilization. That her mother was Themis is significant: Themis represented the foundational, eternal principles of right and wrong, and her daughters were understood as the practical expressions of those principles in the world of mortals. The Horae were also described as keepers of the gates of heaven on Olympus, granting them a liminal role between the divine and human realms. Additionally, the Horae shared a familial connection with the three Moirai (the Fates), who were also daughters of Zeus and Themis, linking the concepts of order, justice, and destiny within a single divine family.

Eunomia's name translates directly as "good order" or "governance according to good laws," from the Greek roots eu (good) and nomos (law, custom, or order). She personified the internal stability of a well-governed state: the enactment of just legislation, the maintenance of civil harmony, and the proper conduct of citizens within a political community. Her domain was not the enforcement of justice through punishment, but rather the underlying condition that makes justice possible -- the presence of sound institutions, fair customs, and a citizenry oriented toward the common good. Her conceptual opposite was the daimon Dysnomia, the spirit of lawlessness and disorder, against whom Eunomia stood as a counterbalancing force. Beyond the civic sphere, she also carried associations with the natural world, particularly the orderly arrival of spring and the greening of pastures, reflecting the Greek understanding that the same principle of harmonious arrangement governed both nature and the polis. The Athenian statesman Solon, in his famous poems of the sixth century BCE, invoked the concept of eunomia as the ideal political condition, arguing that good order restrains hubris and fosters collective well-being, while dysnomia breeds conflict and ruin.

Eunomia formed an inseparable triad with her two sisters, Dike (Justice) and Eirene (Peace), and the three were understood not as independent forces but as deeply interdependent aspects of a flourishing society. Each Hora governed a specific dimension of civilized life: Eunomia established the constitutional and legislative framework of the city-state; Dike safeguarded fairness and moral accountability in human dealings; and Eirene nurtured the tranquility and prosperity that followed when order and justice were maintained. The Greeks recognized an implicit causal logic in this arrangement -- good laws produce justice, and justice produces peace -- making the three sisters a kind of philosophical sequence as much as a mythological family. The poet Pindar praised cities "governed by Eunomia," invoking not merely a goddess but an entire political philosophy in which beauty, prosperity, and righteousness could flourish only where chaos had been contained. Together, the three Horae were worshipped primarily in the cities of Athens, Argos, and Olympia, where civic order was a matter of both political necessity and religious devotion.

In ancient art, Eunomia was frequently depicted in Athenian vase painting as one of the companions of Aphrodite, where she represented the lawful and orderly conduct expected of women within the institution of marriage -- an extension of her domain of good order into the domestic sphere. She was sometimes shown holding a staff or scepter as a symbol of authority, or scales representing fairness, and occasionally depicted with flowers connecting her to the seasonal aspects of the Horae. Though she never commanded the dramatic mythological narratives of gods like Athena or Apollo, her influence was arguably more pervasive: the concept she embodied became foundational to Greek political thought and, through it, to the Western tradition of governance and law. Solon built his reforms around the ideal of eunomia; Plato and Aristotle grappled with the same questions of order and justice that she personified. Her legacy persists not in temples or active worship, but in the enduring conviction -- inherited from the Greeks and still operative today -- that a good society requires not merely power or freedom, but the disciplined architecture of fair laws and shared civic norms.

---

Sources:

- Theoi Project: Eunomia
- Theoi Project: Horae
- Britannica: Hora (Greek Mythology)
- Wikipedia: Eunomia
- Wikipedia: Horae
- World History Encyclopedia: Horae
- Greece High Definition: Eunomia - The Deeper Meaning Behind an Ancient Greek Word
- History Cooperative: Eirene - Greek Goddess of Peace
2 changes: 1 addition & 1 deletion app/basics/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function Login({
<Form method="post" className="space-y-6" action="/auth">
<input type="hidden" name="redirectTo" value={redirectTo} />
<button
className="w-full rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600 focus:bg-blue-400"
className="bg-accent-strong w-full rounded px-4 py-2 text-white hover:bg-amber-700 focus:bg-amber-500"
{...props}
type="submit"
>
Expand Down
2 changes: 1 addition & 1 deletion app/basics/logout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function Logout({ children = "Log out", ...props }: LoginProps) {
<button
type="submit"
{...props}
className="w-full rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600 focus:bg-blue-400"
className="bg-accent-strong w-full rounded px-4 py-2 text-white hover:bg-amber-700 focus:bg-amber-500"
>
{children}
</button>
Expand Down
2 changes: 1 addition & 1 deletion app/basics/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { PropsWithChildren } from "react";
export function Page({ children }: PropsWithChildren) {
return (
<div className="px-2 py-3">
<div className="border-1 h-full max-h-[108rem] max-w-[70rem] space-y-6 rounded-md border-gray-500 bg-gray-700 px-6 pb-8 pt-4 shadow-md shadow-gray-600 sm:w-full">
<div className="bg-surface-overlay h-full max-h-[108rem] max-w-[70rem] space-y-6 rounded-md border border-stone-600 px-6 pt-4 pb-8 shadow-md shadow-stone-900/30 sm:w-full">
{children}
</div>
</div>
Expand Down
37 changes: 37 additions & 0 deletions app/components/AddEunoCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
interface AddEunoCardProps {
id: string;
name: string;
icon: string | null;
}

const INVITE_BASE =
"https://discord.com/oauth2/authorize?client_id=984212151608705054&permissions=8&scope=applications.commands%20bot";

export function AddEunoCard({ id, name, icon }: AddEunoCardProps) {
return (
<div className="flex items-center gap-3">
{icon ? (
<img
src={`https://cdn.discordapp.com/icons/${id}/${icon}.png?size=64`}
alt={name}
className="h-8 w-8 rounded-lg grayscale-[50%]"
/>
) : (
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-stone-700 text-sm text-stone-400">
{name.charAt(0).toUpperCase()}
</div>
)}
<span className="min-w-0 flex-1 truncate text-sm text-stone-400">
{name}
</span>
<a
href={`${INVITE_BASE}&guild_id=${id}`}
target="_blank"
rel="noopener noreferrer"
className="shrink-0 rounded-md px-3 py-1 text-xs text-stone-500 transition-colors hover:text-amber-400"
>
Add Euno
</a>
</div>
);
}
88 changes: 50 additions & 38 deletions app/components/DiscordLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ export function DiscordLayout({
};

return (
<div className="flex h-screen bg-gray-800 text-white">
<div className="bg-surface-deep flex h-screen text-stone-100">
{/* Server Selector Column */}
<div className="flex w-16 flex-col border-r border-gray-800 bg-gray-900">
<div className="bg-surface-deep flex w-16 flex-col border-r border-stone-800">
{/* Home/Euno Icon */}
<div className="flex h-16 items-center justify-center border-b border-gray-800">
<div className="flex h-16 items-center justify-center border-b border-stone-800">
<Link
to="/app"
className={`flex h-12 w-12 items-center justify-center rounded-2xl transition-all duration-200 hover:rounded-xl ${
isActive("/app", true)
? "rounded-xl bg-indigo-600"
: "bg-gray-800 hover:bg-gray-600"
? "bg-accent-strong rounded-xl"
: "bg-surface-raised hover:bg-surface-overlay"
}`}
>
E
Expand All @@ -66,11 +66,11 @@ export function DiscordLayout({
{manageableGuilds.map((guild) => (
<div key={guild.id} className="flex justify-center">
<Link
to={`/app/${guild.id}/settings`}
to={`/app/${guild.id}`}
className={`flex h-12 w-12 items-center justify-center rounded-2xl transition-all duration-200 hover:rounded-xl ${
isActive(`/app/${guild.id}`)
? "rounded-xl bg-indigo-600"
: "bg-gray-800 hover:bg-gray-600"
? "bg-accent-strong rounded-xl"
: "bg-surface-raised hover:bg-surface-overlay"
}`}
title={guild.name}
>
Expand All @@ -81,7 +81,7 @@ export function DiscordLayout({
className="h-10 w-10 rounded-xl"
/>
) : (
<span className="font-semibold text-white">
<span className="font-semibold text-stone-100">
{guild.name.charAt(0).toUpperCase()}
</span>
)}
Expand All @@ -94,10 +94,10 @@ export function DiscordLayout({
to={
"https://discord.com/oauth2/authorize?client_id=984212151608705054&scope=applications.commands%20bot"
}
className={`flex h-12 w-12 items-center justify-center rounded-2xl bg-gray-700 transition-all duration-200 hover:rounded-xl hover:bg-gray-600`}
className={`bg-surface-overlay flex h-12 w-12 items-center justify-center rounded-2xl transition-all duration-200 hover:rounded-xl hover:bg-stone-600`}
title={"Add to server"}
>
<span className="font-semibold text-white">+</span>
<span className="font-semibold text-stone-100">+</span>
</Link>
</div>
</div>
Expand All @@ -118,10 +118,12 @@ export function DiscordLayout({
</div>

{/* Channel Sidebar */}
<div className="flex w-60 flex-col bg-gray-800">
<div className="bg-surface-base flex w-60 flex-col">
{/* Channel Header */}
<div className="flex h-16 items-center border-b border-gray-700 px-4">
<h2 className="text-lg font-semibold text-white">Euno Dashboard</h2>
<div className="flex h-16 items-center border-b border-stone-700 px-4">
<h2 className="font-serif text-lg font-semibold text-stone-100">
Euno Dashboard
</h2>
</div>

{/* Navigation */}
Expand All @@ -134,21 +136,31 @@ export function DiscordLayout({
to={`/app/${guildId}/sh`}
className={`group flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors ${
isActive(`/app/${guildId}/sh`)
? "bg-gray-600 text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white"
? "bg-surface-overlay text-stone-100"
: "hover:bg-surface-overlay text-stone-400 hover:text-stone-100"
}`}
>
🌟 Star Hunter
</Link>
<hr className="" />
<hr className="border-stone-700" />
</>
)}
<Link
to={`/app/${guildId}`}
className={`group flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors ${
isActive(`/app/${guildId}`, true)
? "bg-surface-overlay text-stone-100"
: "hover:bg-surface-overlay text-stone-400 hover:text-stone-100"
}`}
>
📊 Overview
</Link>
<Link
to={`/app/${guildId}/settings`}
className={`group flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors ${
isActive(`/app/${guildId}/settings`)
? "bg-gray-600 text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white"
? "bg-surface-overlay text-stone-100"
: "hover:bg-surface-overlay text-stone-400 hover:text-stone-100"
}`}
>
⚙️ Settings
Expand All @@ -157,8 +169,8 @@ export function DiscordLayout({
to={`/app/${guildId}/onboard`}
className={`group flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors ${
isActive(`/app/${guildId}/onboard`)
? "bg-gray-600 text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white"
? "bg-surface-overlay text-stone-100"
: "hover:bg-surface-overlay text-stone-400 hover:text-stone-100"
}`}
>
🆕 Onboarding flow
Expand All @@ -169,45 +181,45 @@ export function DiscordLayout({

{/* Expanded Account Menu */}
{accountExpanded && (
<div className="border-t border-gray-700 bg-gray-700">
<div className="bg-surface-overlay border-t border-stone-700">
<div className="px-3 py-2">
<p className="mb-2 text-xs text-gray-400">Account</p>
<p className="mb-2 text-xs text-stone-500">Account</p>
<div className="space-y-1">
{/* <Link
to="/profile"
className="block rounded px-2 py-1 text-sm text-gray-300 hover:bg-gray-600 hover:text-white"
className="block rounded px-2 py-1 text-sm text-stone-400 hover:bg-stone-600 hover:text-stone-100"
>
Profile
</Link> */}
<Link
to="/profile"
className="block rounded px-2 py-1 text-sm text-gray-300 hover:bg-gray-600 hover:text-white"
className="block rounded px-2 py-1 text-sm text-stone-400 hover:bg-stone-600 hover:text-stone-100"
>
Profile
</Link>

<Link
to="/terms"
className="block rounded px-2 py-1 text-sm text-gray-300 hover:bg-gray-600 hover:text-white"
className="block rounded px-2 py-1 text-sm text-stone-400 hover:bg-stone-600 hover:text-stone-100"
>
Terms of Service
</Link>
<Link
to="/privacy"
className="block rounded px-2 py-1 text-sm text-gray-300 hover:bg-gray-600 hover:text-white"
className="block rounded px-2 py-1 text-sm text-stone-400 hover:bg-stone-600 hover:text-stone-100"
>
Privacy Policy
</Link>
<Link
to="mailto:support@euno.reactiflux.com"
className="block rounded px-2 py-1 text-sm text-gray-300 hover:bg-gray-600 hover:text-white"
className="block rounded px-2 py-1 text-sm text-stone-400 hover:bg-stone-600 hover:text-stone-100"
>
Contact Support
</Link>

<hr />
<hr className="border-stone-700" />

<div className="rounded px-2 py-1 text-sm text-gray-300 hover:bg-gray-600 hover:text-white">
<div className="rounded px-2 py-1 text-sm text-stone-400 hover:bg-stone-600 hover:text-stone-100">
<Logout>Log Out</Logout>
</div>
</div>
Expand All @@ -216,22 +228,22 @@ export function DiscordLayout({
)}

{/* Account Section */}
<div className="border-t border-gray-700 bg-gray-800">
<div className="bg-surface-base border-t border-stone-700">
<button
onClick={() => setAccountExpanded(!accountExpanded)}
className="flex w-full items-center px-3 py-3 text-left text-sm transition-colors hover:bg-gray-700"
className="hover:bg-surface-overlay flex w-full items-center px-3 py-3 text-left text-sm transition-colors"
>
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-indigo-600 text-white">
<div className="bg-accent-strong flex h-8 w-8 items-center justify-center rounded-full text-stone-100">
{user.email?.charAt(0).toUpperCase()}
</div>
<div className="ml-3 min-w-0 flex-1">
<p className="truncate text-sm font-medium text-white">
<p className="truncate text-sm font-medium text-stone-100">
{user.email?.split("@")[0]}
</p>
<p className="truncate text-xs text-gray-400">Online</p>
<p className="truncate text-xs text-stone-500">Online</p>
</div>
<svg
className={`h-4 w-4 text-gray-400 transition-transform ${
className={`h-4 w-4 text-stone-500 transition-transform ${
accountExpanded ? "rotate-180" : ""
}`}
fill="none"
Expand All @@ -250,15 +262,15 @@ export function DiscordLayout({
</div>

{/* Main Content Area */}
<div className="flex flex-1 overflow-hidden bg-gray-600">
<div className="bg-surface-raised flex flex-1 overflow-hidden">
{/* Main Content */}
<main className={`flex-1 overflow-auto ${rightPanel ? "pr-0" : ""}`}>
{children}
</main>

{/* Right Panel (conditional) */}
{rightPanel && (
<aside className="w-80 overflow-auto border-l border-gray-600 bg-gray-800">
<aside className="bg-surface-base w-80 overflow-auto border-l border-stone-700">
{rightPanel}
</aside>
)}
Expand Down
Loading