Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ jobs:

- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm test:run
- run: pnpm test
- run: pnpm build
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"oxc.enable": true
"oxc.enable": true,
"oxc.configPath": "oxlint.config.ts",
"typescript.tsdk": "node_modules/typescript/lib"
}
1 change: 1 addition & 0 deletions eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default defineConfig([
js.configs.recommended,
...tseslint.configs.recommended,
...astro.configs.recommended,

...oxlint.configs["flat/recommended"],

prettierConfig,
Expand Down
7 changes: 7 additions & 0 deletions oxlint.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from "oxlint";

export default defineConfig({
rules: {
"no-unused-expressions": "off",
},
});
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"lint:eslint": "eslint . --fix",
"lint:oxlint": "oxlint . --fix",
"lint": "pnpm lint:eslint && pnpm lint:oxlint",
"test": "vitest",
"test:run": "vitest run",
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "astro check",
"test:coverage": "vitest run --coverage",
"format": "prettier . --write",
Expand All @@ -29,6 +29,7 @@
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"astro": "^6.4.4",
"gsap": "^3.15.0",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"tailwindcss": "^4.3.0",
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createTestContainer } from "@test/createTestContainer";
import { describe, expect, it } from "vitest";
import { createTestContainer } from "../../test/createTestContainer";
import DiscordCTA from "./DiscordCTA.astro";

describe("DiscordCTA", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
countMembersByStatus,
formatPresenceCount,
sortMembersByStatus,
} from "../../lib/discordWidget";
import type { DiscordWidgetData } from "../../schemas/discordWidget";
} from "@lib/discordWidget";
import type { DiscordWidgetData } from "@schemas/discordWidget";
import DiscordCTA from "./DiscordCTA.astro";

interface Props {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
import DiscordCTA from "./DiscordCTA.astro";
import DiscordCTA from "@components/discord/DiscordCTA.astro";

interface Props {
siteName: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
import DiscordCTA from "./DiscordCTA.astro";
import ServerLogo from "./ServerLogo.astro";
import MobileNav from "../react/MobileNav";
import { navLinks } from "../../lib/nav";
import DiscordCTA from "@components/discord/DiscordCTA.astro";
import ServerLogo from "@components/icons/ServerLogo.astro";
import { navLinks } from "@lib/nav";
import MobileNav from "./MobileNav.astro";

interface Props {
siteName: string;
Expand Down Expand Up @@ -44,6 +44,6 @@ const { siteName, discordUrl } = Astro.props;
<DiscordCTA href={discordUrl} />
</div>

<MobileNav client:load navLinks={navLinks} discordUrl={discordUrl} />
<MobileNav navLinks={navLinks} discordUrl={discordUrl} />
</div>
</header>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createTestContainer } from "@test/createTestContainer";
import { describe, expect, it } from "vitest";
import { createTestContainer } from "../../test/createTestContainer";
import Header from "./Header.astro";

describe("Header", () => {
Expand Down
114 changes: 114 additions & 0 deletions src/components/header/MobileNav.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
import type { NavLink } from "@lib/nav";

interface Props {
navLinks: NavLink[];
discordUrl: string;
}

const { navLinks, discordUrl } = Astro.props;
const menuId = "mobile-nav-menu";
---

<mobile-nav class="md:hidden">
<button
type="button"
aria-expanded="false"
aria-controls={menuId}
class="border-border bg-surface-elevated text-ink hover:bg-surface-hover inline-flex items-center justify-center rounded-lg border px-3 py-2 text-sm font-medium"
>
Menu
</button>

<nav
id={menuId}
aria-label="Mobile navigation"
aria-hidden="true"
class="border-border bg-surface-elevated absolute top-full right-0 left-0 border-b px-4 py-4 shadow-md aria-hidden:hidden"
>
<ul class="flex flex-col gap-3">
{
navLinks.map((link) => (
<li>
<a
href={link.href}
class="text-ink-muted hover:text-brand-500 block text-sm font-medium"
>
{link.label}
</a>
</li>
))
}
<li>
<a
href={discordUrl}
target="_blank"
rel="noopener noreferrer"
class="bg-mod hover:bg-mod-700 inline-flex rounded-lg px-4 py-2 text-sm font-semibold text-white"
>
Join Discord
</a>
</li>
</ul>
</nav>
</mobile-nav>

<script>
import { defineCustomElement } from "@lib/custom-elements";

class MobileNav extends HTMLElement {
private button!: HTMLButtonElement;
private nav!: HTMLElement;
private firstLink!: HTMLAnchorElement | null;

#open = false;

connectedCallback() {
this.button = this.querySelector("button")!;
this.nav = this.querySelector("nav")!;
this.firstLink = this.nav.querySelector("a");

this.button.addEventListener("click", this.#toggle);
this.nav.addEventListener("click", this.#onNavClick);
document.addEventListener("keydown", this.#onKeyDown);
}

disconnectedCallback() {
this.button.removeEventListener("click", this.#toggle);
this.nav.removeEventListener("click", this.#onNavClick);
document.removeEventListener("keydown", this.#onKeyDown);
}

#toggle = () => {
this.#open ? this.#close() : this.#openMenu();
};

#openMenu() {
this.#open = true;
this.nav.removeAttribute("aria-hidden");
this.button.setAttribute("aria-expanded", "true");
this.button.textContent = "Close";
this.firstLink?.focus();
}

#close() {
this.#open = false;
this.nav.setAttribute("aria-hidden", "true");
this.button.setAttribute("aria-expanded", "false");
this.button.textContent = "Menu";
}

#onNavClick = (e: Event) => {
if ((e.target as HTMLElement).closest("a")) this.#close();
};

#onKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape" && this.#open) {
this.#close();
this.button.focus();
}
};
}

defineCustomElement("mobile-nav", MobileNav);
</script>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @vitest-environment jsdom
import { navLinks } from "@lib/nav";
import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { navLinks } from "../../lib/nav";
import MobileNav from "./MobileNav";

describe("MobileNav", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { NavLink } from "@lib/nav";
import { useEffect, useId, useRef, useState } from "react";
import type { NavLink } from "../../lib/nav";

interface MobileNavProps {
navLinks: NavLink[];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
---

---

<aside
class="border-border bg-surface-elevated border-b py-12 sm:py-16"
aria-labelledby="community-callout-heading"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createTestContainer } from "@test/createTestContainer";
import { describe, expect, it } from "vitest";
import { createTestContainer } from "../../test/createTestContainer";
import CommunityCallout from "./CommunityCallout.astro";

describe("CommunityCallout", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
import DiscordCTA from "./DiscordCTA.astro";
import ServerLogo from "./ServerLogo.astro";
import DiscordCTA from "@components/discord/DiscordCTA.astro";
import ServerLogo from "@components/icons/ServerLogo.astro";

interface Props {
name: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createTestContainer } from "@test/createTestContainer";
import { describe, expect, it } from "vitest";
import { createTestContainer } from "../../test/createTestContainer";
import Hero from "./Hero.astro";

describe("Hero", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createTestContainer } from "@test/createTestContainer";
import { describe, expect, it } from "vitest";
import { createTestContainer } from "../../test/createTestContainer";
import ValueCards from "./ValueCards.astro";

describe("ValueCards", () => {
Expand Down
8 changes: 4 additions & 4 deletions src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
import "../styles/global.css";
import Header from "../components/astro/Header.astro";
import Footer from "../components/astro/Footer.astro";
import site from "@/data/site.json";
import Footer from "@components/footer/Footer.astro";
import Header from "@components/header/Header.astro";
import { PUBLIC_DISCORD_INVITE_URL, PUBLIC_SITE_URL } from "astro:env/client";
import site from "../data/site.json";
import "../styles/global.css";

interface Props {
title?: string;
Expand Down
8 changes: 8 additions & 0 deletions src/lib/custom-elements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const defineCustomElement = (
name: string,
elementClass: CustomElementConstructor,
) => {
if (!customElements.get(name)) {
customElements.define(name, elementClass);
}
};
2 changes: 1 addition & 1 deletion src/pages/404.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
import BaseLayout from "@layouts/BaseLayout.astro";
---

<BaseLayout title="Page not found">
Expand Down
2 changes: 1 addition & 1 deletion src/pages/code-of-conduct.astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
import ContentLayout from "@layouts/ContentLayout.astro";
import { getEntry, render } from "astro:content";
import ContentLayout from "../layouts/ContentLayout.astro";

const entry = await getEntry("pages", "code-of-conduct");
if (!entry) {
Expand Down
14 changes: 7 additions & 7 deletions src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
import CommunityCallout from "../components/astro/CommunityCallout.astro";
import DiscordWidget from "../components/astro/DiscordWidget.astro";
import Hero from "../components/astro/Hero.astro";
import ValueCards from "../components/astro/ValueCards.astro";
import BaseLayout from "../layouts/BaseLayout.astro";
import { fetchDiscordWidget } from "../lib/discordWidget";
import site from "@/data/site.json";
import DiscordWidget from "@components/discord/DiscordWidget.astro";
import CommunityCallout from "@components/landing/CommunityCallout.astro";
import Hero from "@components/landing/Hero.astro";
import ValueCards from "@components/landing/ValueCards.astro";
import BaseLayout from "@layouts/BaseLayout.astro";
import { fetchDiscordWidget } from "@lib/discordWidget";
import { PUBLIC_DISCORD_INVITE_URL } from "astro:env/client";
import site from "../data/site.json";
const discordWidget = await fetchDiscordWidget(site.discordServerId);
---

Expand Down
8 changes: 4 additions & 4 deletions src/pages/learning/index.astro
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
import ResourceSearch from "@components/resources/ResourceSearch";
import BaseLayout from "@layouts/BaseLayout.astro";
import { sortFeaturedFirst } from "@lib/resources";
import type { Resource } from "@schemas/resource";
import { getCollection } from "astro:content";
import BaseLayout from "../../layouts/BaseLayout.astro";
import ResourceSearch from "../../components/react/ResourceSearch";
import { sortFeaturedFirst } from "../../lib/resources";
import type { Resource } from "../../schemas/resource";

const entries = await getCollection("resources");

Expand Down
5 changes: 5 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
}
],
"paths": {
"@components/*": ["./src/components/*"],
"@layouts/*": ["./src/layouts/*"],
"@lib/*": ["./src/lib/*"],
"@schemas/*": ["./src/schemas/*"],
"@test/*": ["./src/test/*"],
"@/*": ["./src/*"]
},
"jsx": "react-jsx",
Expand Down
Loading