summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-03-10 14:14:58 +0530
committerBobby <[email protected]>2026-03-10 14:14:58 +0530
commit6f2f3c013d88df6a2b37d0978194c7cb0bf1274c (patch)
tree99746e2afbd5379c46401440e85964658bf26f25
parent03a9b16a0fd7cc5a293a1289646817e21663f4bd (diff)
downloadpagoda-6f2f3c013d88df6a2b37d0978194c7cb0bf1274c.tar.xz
pagoda-6f2f3c013d88df6a2b37d0978194c7cb0bf1274c.zip
feat: add TypeScript support and improve type definitions across components
-rw-r--r--garden/package-lock.json15
-rw-r--r--garden/package.json1
-rw-r--r--garden/src/app.tsx5
-rw-r--r--garden/src/components/DatePicker.tsx6
-rw-r--r--garden/src/components/Editor.tsx4
-rw-r--r--garden/src/components/Layout.tsx6
-rw-r--r--garden/src/index.tsx2
-rw-r--r--garden/src/pages/council/bannedips.tsx4
-rw-r--r--garden/src/pages/council/user.tsx14
-rw-r--r--garden/src/pages/council/users.tsx2
-rw-r--r--garden/src/types/custom-elements.d.ts4
-rw-r--r--garden/tsconfig.json1
12 files changed, 43 insertions, 21 deletions
diff --git a/garden/package-lock.json b/garden/package-lock.json
index 519bdf6..6dedc78 100644
--- a/garden/package-lock.json
+++ b/garden/package-lock.json
@@ -24,6 +24,7 @@
"devDependencies": {
"@types/node": "^25.3.2",
"solid-devtools": "^0.34.3",
+ "typescript": "^5.9.3",
"vite": "^7.1.4",
"vite-plugin-solid": "^2.11.8"
}
@@ -2189,6 +2190,20 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/undici-types": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
diff --git a/garden/package.json b/garden/package.json
index 1072066..3435342 100644
--- a/garden/package.json
+++ b/garden/package.json
@@ -13,6 +13,7 @@
"devDependencies": {
"@types/node": "^25.3.2",
"solid-devtools": "^0.34.3",
+ "typescript": "^5.9.3",
"vite": "^7.1.4",
"vite-plugin-solid": "^2.11.8"
},
diff --git a/garden/src/app.tsx b/garden/src/app.tsx
index 2fb73fe..58be568 100644
--- a/garden/src/app.tsx
+++ b/garden/src/app.tsx
@@ -1,7 +1,8 @@
-import { Suspense, type Component } from "solid-js";
+import { Suspense } from "solid-js";
+import type { JSX } from "solid-js";
import Layout from "./components/Layout";
-const App: Component<{ children: Element }> = (props) => {
+const App = (props: { children?: JSX.Element }) => {
return (
<Layout>
<Suspense>{props.children}</Suspense>
diff --git a/garden/src/components/DatePicker.tsx b/garden/src/components/DatePicker.tsx
index 8e6410d..8c914ec 100644
--- a/garden/src/components/DatePicker.tsx
+++ b/garden/src/components/DatePicker.tsx
@@ -121,17 +121,17 @@ export default function DatePicker(props: DatePickerProps) {
</div>
<div class="datepicker-weekdays">
<For each={WEEKDAYS}>
- {(day) => <span class="datepicker-weekday">{day}</span>}
+ {(day: string) => <span class="datepicker-weekday">{day}</span>}
</For>
</div>
<div class="datepicker-grid">
<For each={calendarDays()}>
- {(day) => (
+ {(day: number | null) => (
<Show when={day !== null} fallback={<span class="datepicker-blank" />}>
<button
type="button"
class="datepicker-day"
- classList={{ "datepicker-day-selected": isSelected(day!) }}
+ classList={{ "datepicker-day-selected": isSelected(day!) ?? undefined }}
onClick={() => selectDay(day!)}
>
{day}
diff --git a/garden/src/components/Editor.tsx b/garden/src/components/Editor.tsx
index 5085032..9aa2e08 100644
--- a/garden/src/components/Editor.tsx
+++ b/garden/src/components/Editor.tsx
@@ -613,7 +613,7 @@ export default function Editor(props: EditorProps) {
<Show when={attachments().length > 0 || pendingUploads().length > 0}>
<div class="editor-attachments">
<For each={attachments()}>
- {(attachment) => (
+ {(attachment: AttachmentResult) => (
<div class="editor-attachment" title={attachment.file_name}>
<Show when={attachment.category === "image"} fallback={
<Show when={attachment.category === "video"} fallback={
@@ -637,7 +637,7 @@ export default function Editor(props: EditorProps) {
)}
</For>
<For each={pendingUploads()}>
- {(pending) => (
+ {(pending: PendingUpload) => (
<div class="editor-attachment editor-attachment-uploading" title={pending.name}>
<Show when={pending.type.startsWith("image/") && pending.preview} fallback={
<Show when={pending.type.startsWith("video/") && pending.preview} fallback={
diff --git a/garden/src/components/Layout.tsx b/garden/src/components/Layout.tsx
index 1580660..b3ac179 100644
--- a/garden/src/components/Layout.tsx
+++ b/garden/src/components/Layout.tsx
@@ -6,6 +6,8 @@ import NavSection from "./NavSection";
import { auth } from "../store/auth";
import { stats } from "../store/stats";
import { UserRole } from "../types/roles";
+import type { CitizenSummary } from "../types/stats";
+
interface LayoutProps {
children: JSX.Element;
@@ -147,7 +149,7 @@ export default function Layout(props: LayoutProps) {
<li class="placeholder">Be the first to join!</li>
}>
<For each={stats.data()?.newest_citizens}>
- {(citizen) => (
+ {(citizen: CitizenSummary) => (
<li class="citizen-item">
<A href={`/p/${citizen.username}`}>
<img src={citizen.avatar_url} alt="" class="citizen-avatar" />
@@ -165,7 +167,7 @@ export default function Layout(props: LayoutProps) {
<li class="placeholder">No one online.</li>
}>
<For each={stats.data()?.online_citizens}>
- {(citizen) => (
+ {(citizen: CitizenSummary) => (
<li class="citizen-item">
<A href={`/p/${citizen.username}`}>
<img src={citizen.avatar_url} alt="" class="citizen-avatar" />
diff --git a/garden/src/index.tsx b/garden/src/index.tsx
index 6237aa1..0bfe1b9 100644
--- a/garden/src/index.tsx
+++ b/garden/src/index.tsx
@@ -18,5 +18,5 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
render(
() => <Router root={(props) => <App>{props.children}</App>}>{routes}</Router>,
- root,
+ root!,
);
diff --git a/garden/src/pages/council/bannedips.tsx b/garden/src/pages/council/bannedips.tsx
index 3a94c91..f70b197 100644
--- a/garden/src/pages/council/bannedips.tsx
+++ b/garden/src/pages/council/bannedips.tsx
@@ -77,7 +77,7 @@ export default function BannedIPs() {
<div class="council-grid-empty">No banned IPs.</div>
}>
<For each={bans()}>
- {(ban) => (
+ {(ban: IPBan) => (
<div class="council-grid-row">
<span class="council-ip">{ban.IP}</span>
<span>{ban.Reason}</span>
@@ -100,7 +100,7 @@ export default function BannedIPs() {
</div>
</Show>
<Show when={confirmBan()}>
- {(ban) => (
+ {(ban: () => IPBan) => (
<Modal title="Lift IP Ban" onClose={() => setConfirmBan(null)}>
<p style={{ "font-size": "12px", margin: "0 0 12px" }}>Lift ban on <strong>{ban().IP}</strong>?</p>
<div class="modal-actions">
diff --git a/garden/src/pages/council/user.tsx b/garden/src/pages/council/user.tsx
index dc445b7..0bb0c91 100644
--- a/garden/src/pages/council/user.tsx
+++ b/garden/src/pages/council/user.tsx
@@ -87,11 +87,11 @@ export default function CouncilUser() {
}
function startEdit(field: string, value: string) {
- setEditing((prev) => ({ ...prev, [field]: value }));
+ setEditing((prev: Record<string, string>) => ({ ...prev, [field]: value }));
}
function cancelEdit(field: string) {
- setEditing((prev) => {
+ setEditing((prev: Record<string, string>) => {
const next = { ...prev };
delete next[field];
return next;
@@ -312,7 +312,7 @@ export default function CouncilUser() {
type="text"
class="council-detail-edit-input"
value={editing()[props.field]}
- onInput={(e) => setEditing((prev) => ({ ...prev, [props.field]: e.currentTarget.value }))}
+ onInput={(e) => setEditing((prev: Record<string, string>) => ({ ...prev, [props.field]: e.currentTarget.value }))}
onKeyDown={(e) => { if (e.key === "Enter") saveEdit(props.field); if (e.key === "Escape") cancelEdit(props.field); }}
/>
<button type="button" class="council-detail-edit-btn council-action-save" onClick={() => saveEdit(props.field)}>Save</button>
@@ -350,10 +350,10 @@ export default function CouncilUser() {
aria-label="Change role"
title="Change role"
value={editing()["role"]}
- onChange={(e) => setEditing((prev) => ({ ...prev, role: e.currentTarget.value }))}
+ onChange={(e) => setEditing((prev: Record<string, string>) => ({ ...prev, role: e.currentTarget.value }))}
>
<For each={availableRoles()}>
- {(role) => <option value={role}>{role}</option>}
+ {(role: UserRole) => <option value={role}>{role}</option>}
</For>
</select>
<button type="button" class="council-detail-edit-btn council-action-save" onClick={() => saveRole(editing()["role"])}>Save</button>
@@ -374,7 +374,7 @@ export default function CouncilUser() {
</Show>
<Show when={user()}>
- {(target) => (
+ {(target: () => AdminUser) => (
<>
<Show when={actionError()}>
<div class="form-error">{actionError()}</div>
@@ -432,7 +432,7 @@ export default function CouncilUser() {
type="text"
class="council-detail-edit-input"
value={editing()["website"]}
- onInput={(event) => setEditing((prev) => ({ ...prev, website: event.currentTarget.value }))}
+ onInput={(event) => setEditing((prev: Record<string, string>) => ({ ...prev, website: event.currentTarget.value }))}
onKeyDown={(e) => { if (e.key === "Enter") saveEdit("website"); if (e.key === "Escape") cancelEdit("website"); }}
/>
<button type="button" class="council-detail-edit-btn council-action-save" onClick={() => saveEdit("website")}>Save</button>
diff --git a/garden/src/pages/council/users.tsx b/garden/src/pages/council/users.tsx
index 317639e..1ec73db 100644
--- a/garden/src/pages/council/users.tsx
+++ b/garden/src/pages/council/users.tsx
@@ -66,7 +66,7 @@ export default function CouncilUsers() {
<div class="council-grid-empty">No users found.</div>
}>
<For each={council.users()}>
- {(user) => (
+ {(user: AdminUser) => (
<div class="council-grid-row" onClick={() => navigate(`/council/users/${user.username}`)}>
<span class="council-user-cell">
<img src={user.avatar_url} alt="" class="council-avatar" />
diff --git a/garden/src/types/custom-elements.d.ts b/garden/src/types/custom-elements.d.ts
index ceaf7bb..79a10f8 100644
--- a/garden/src/types/custom-elements.d.ts
+++ b/garden/src/types/custom-elements.d.ts
@@ -1,7 +1,9 @@
+import "solid-js";
+
declare module "solid-js" {
namespace JSX {
interface IntrinsicElements {
- "emoji-picker": HTMLAttributes<HTMLElement> & {
+ "emoji-picker": JSX.HTMLAttributes<HTMLElement> & {
class?: string;
"on:emoji-click"?: (event: CustomEvent) => void;
};
diff --git a/garden/tsconfig.json b/garden/tsconfig.json
index 271eb70..f7eba49 100644
--- a/garden/tsconfig.json
+++ b/garden/tsconfig.json
@@ -10,6 +10,7 @@
"moduleResolution": "bundler",
"noEmit": true,
"strict": true,
+ "skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"types": ["vite/client"]
},