Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c359eb2
Upgrade all packages to latest minor/patch version (retain major)
Alexandre2006 Sep 30, 2025
e2c543f
Updated @hookform/resolvers from v3.10.0 to v5.2.2
Alexandre2006 Sep 30, 2025
2466ddf
Upgraded @icons-pack/react-simple-icons from v10.2.0 to v13.8.0
Alexandre2006 Sep 30, 2025
846c4fc
Upgraded eslint (and related plugins) from 8.52.0 to 9.36.0
Alexandre2006 Oct 1, 2025
a317b12
Upgaded Zod from v3.25.75 to v4.1.11
Alexandre2006 Oct 1, 2025
76e8f95
Upgraded sonner from v1.7.4 to v2.0.7
Alexandre2006 Oct 1, 2025
5e7712d
Upgraded sharp-cli from v4.2.0 to v5.2.0
Alexandre2006 Oct 1, 2025
6b5db7a
Upgraded p-limit from v6.2.0 to v7.1.1
Alexandre2006 Oct 1, 2025
9eb08bd
Upgraded lucide-react from v0.288.0 to v0.554.0
Alexandre2006 Oct 1, 2025
f89d1fe
Upgraded jest from v29.7.0 to v30.2.0, and @types/jest from v29.5.14 …
Alexandre2006 Oct 1, 2025
1836f6f
Upgraded cmdk from v0.2.1 to v1.1.1
Alexandre2006 Oct 1, 2025
2461c88
Upgraded bcrypt-ts from v5.0.3 to v7.1.0
Alexandre2006 Oct 1, 2025
6b9b038
Upgraded ajv-formats from v2.1.1 to v3.0.1
Alexandre2006 Oct 1, 2025
1eaf592
Upgraded @uppy/core to v5.0.2 (@uppy/aws-s3 v5.0.1, @uppy/dashboard v…
Alexandre2006 Oct 1, 2025
717ad16
Upgrade @types/node from v20.8.7 to v24.6.0
Alexandre2006 Oct 1, 2025
efac3c2
Upgraded @sentry/nextjs from v7.120.4 to v10.17.0
Alexandre2006 Oct 1, 2025
960f761
Fixed sentry instrumentation
Alexandre2006 Oct 1, 2025
9707353
Upgraded from Nextra v2 to v3 (not fully tested)
Alexandre2006 Oct 9, 2025
cb79b30
Merge branch 'WATonomous:master' into master
Alexandre2006 Oct 9, 2025
28422ae
Switched from `next lint` to `eslint` and fixed errors
Alexandre2006 Oct 12, 2025
99cd635
Updated tsconfig and fixed type-check errors
Alexandre2006 Oct 12, 2025
ba3cd51
Revert "Upgraded cmdk from v0.2.1 to v1.1.1"
Alexandre2006 Oct 13, 2025
89a756f
CSS fixes for interactivity, code blocks, and inputs
Alexandre2006 Oct 13, 2025
0db5401
Upgraded cmdk from v0.2.1 to v1.1.1
Alexandre2006 Oct 13, 2025
5842cd0
Update Node.js version requirement
Alexandre2006 Oct 13, 2025
e4727c8
Fixed linter errors
Alexandre2006 Oct 13, 2025
725c45d
Fixed scrolling on blog page
Alexandre2006 Oct 13, 2025
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
16 changes: 16 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Run ESLint",
"type": "shell",
"command": "npm run lint",
"args": [],
"isBackground": false,
"problemMatcher": [
"$eslint-stylish"
],
"group": "build"
}
]
}
4 changes: 2 additions & 2 deletions components/affiliation-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function AffiliationList({
.map((a) => (
<CommandItem
key={a.name}
className="aria-selected:bg-inherit aria-selected:text-accent-inherit"
className="aria-[selected=true]:bg-inherit aria-[selected=true]:text-accent-inherit"
>
{a.name}
</CommandItem>
Expand All @@ -38,7 +38,7 @@ export function AffiliationList({
.filter((a) => a.is_legacy)
.map((a) => (
<CommandItem
className="aria-selected:bg-inherit aria-selected:text-accent-inherit"
className="aria-[selected=true]:bg-inherit aria-[selected=true]:text-accent-inherit"
key={a.name}
>
{a.name}
Expand Down
50 changes: 30 additions & 20 deletions components/assets.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Uppy from '@uppy/core';
import type { UppyFile, SuccessResponse } from '@uppy/core'
import type { UppyFile, Meta, Body as UppyBody } from '@uppy/core'
import SuccessResponse from '@uppy/core'
import { Dashboard } from '@uppy/react';
import AwsS3 from '@uppy/aws-s3';
import { useEffect, useState } from 'react';
Expand All @@ -21,8 +22,8 @@ import {
FormMessage,
} from "@/components/ui/form";

import '@uppy/core/dist/style.min.css';
import '@uppy/dashboard/dist/style.min.css';
import '@uppy/core/css/style.min.css';
import '@uppy/dashboard/css/style.min.css';
import { Textarea } from './ui/textarea';
import { Separator } from "@/components/ui/separator";

Expand Down Expand Up @@ -158,21 +159,21 @@ export function AssetInspector() {
<div key={res.uri}>
{i !== 0 && (<Separator className="my-6" />)}
<span className="text-sm text-gray-500">URI</span>
<Pre hasCopyCode className="-mt-5"><Code>{res.uri}</Code></Pre>
<Pre className="-mt-5"><Code>{res.uri}</Code></Pre>
{'result' in res && (
<>
<span className="text-sm text-gray-500">Resolved</span>
<Pre hasCopyCode className="-mt-5"><Code>{res.result.url}</Code></Pre>
<Pre className="-mt-5"><Code>{res.result.url}</Code></Pre>
{res.result.lastModified && (
<>
<span className="text-sm text-gray-500 block">Last Modified</span>
<Pre hasCopyCode className="-mt-5"><Code>{dayjs().to(res.result.lastModified)} ({res.result.lastModified.toISOString()})</Code></Pre>
<Pre className="-mt-5"><Code>{dayjs().to(res.result.lastModified)} ({res.result.lastModified.toISOString()})</Code></Pre>
</>

)}
<>
<span className="text-sm text-gray-500 block">Expires</span>
<Pre hasCopyCode className="-mt-5"><Code>{
<Pre className="-mt-5"><Code>{
res.result.expiresAt ?
`${dayjs().to(res.result.expiresAt)} (${res.result.expiresAt.toISOString()})` :
'Never'
Expand All @@ -181,7 +182,7 @@ export function AssetInspector() {
{res.result.headers && (
<>
<span className="text-sm text-gray-500 block">Raw Headers</span>
<Pre hasCopyCode className="-mt-5"><Code>{JSON.stringify(Object.fromEntries(res.result.headers), null, 2)}</Code></Pre>
<Pre className="-mt-5"><Code>{JSON.stringify(Object.fromEntries(res.result.headers), null, 2)}</Code></Pre>
</>
)}
</>
Expand Down Expand Up @@ -242,21 +243,30 @@ export function AssetUploader() {
function handleUpload() {
setErrorMessages([]);
}
async function handleUploadSuccess(file: UppyFile | undefined, response: SuccessResponse) {
if (!file) {
console.warn('Got upload success event without a file:', response)
return;
}
const hash = sha256Cache.get(file.id) || sha256(await file.data.arrayBuffer());
const watcloudURI = `watcloud://v1/sha256:${hash}?name=${encodeURIComponent(file.name)}`;
async function handleUploadSuccess(
file: UppyFile<Meta, UppyBody> | undefined,
response: { body?: Record<string, never>; status: number; bytesUploaded?: number; uploadURL?: string }
) {
if (!file) {
console.warn('Got upload success event without a file:', response)
return;
}
// Since this function can't be async, use then/catch for async operations
const getHash = sha256Cache.get(file.id)
? Promise.resolve(sha256Cache.get(file.id) as string)
: file.data.arrayBuffer().then((buf) => sha256(buf));
getHash.then((hash) => {
const fileName = file.name ?? 'unnamed';
const watcloudURI = `watcloud://v1/sha256:${hash}?name=${encodeURIComponent(fileName)}`;
console.log('Uploaded file:', file, 'Response:', response, 'watcloud URI:', watcloudURI);

setSuccessfulUploads((prev) => [{
name: file.name,
name: fileName,
uri: watcloudURI,
}, ...prev]);
}
function handleUppyError(file: UppyFile | undefined, error: any) {
});
}
function handleUppyError(file: UppyFile<Meta, UppyBody> | undefined, error: any) {
console.error('Failed upload:', file, "Error:", error, "Response status:", error.source?.status);
setErrorMessages((prev) => [`Failed to upload ${file?.name}: "${error.message}", response status: "${error.source?.status}", response body: "${error.source?.responseText}"`, ...prev]);
}
Expand All @@ -279,13 +289,13 @@ export function AssetUploader() {
note={`Maximum file size: ${bytesToSize(UPLOADER_MAX_FILE_SIZE, 0)}`}
width="100%"
theme={uppyTheme}
showProgressDetails={true}
hideProgressDetails={false}
/>
<h4 className="mt-8 mb-4 text-md">Successful Uploads</h4>
{successfulUploads.map(({name, uri}) => (
<div key={uri}>
<span className="text-sm text-gray-500">{name}</span>
<Pre hasCopyCode className="-mt-5"><Code>{uri}</Code></Pre>
<Pre className="-mt-5"><Code>{uri}</Code></Pre>
</div>
))}
{successfulUploads.length === 0 && (
Expand Down
68 changes: 43 additions & 25 deletions components/blog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { useRouter } from 'next/router';
import { MdxFile } from "nextra";
import { Link } from "nextra-theme-docs";
import { getPagesUnderRoute } from "nextra/context";
import { useState, useEffect } from "react";
import { useState, useEffect, useMemo, useRef } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import Picture from "./picture";
Expand All @@ -48,25 +48,38 @@ export function BlogIndex() {
const router = useRouter();
const locale = router.locale || websiteConfig.default_locale;
const activeTag = (router.query.tag as string | undefined)?.trim();
let tagCounts: Record<string, number> = {};
const hasRedirectedEmptyTag = useRef(false);
const hasRedirectedInvalidTag = useRef(false);
const lastActiveTag = useRef(activeTag);

// Get all posts from route
const allPosts = getPagesUnderRoute("/blog").filter((page) => {
const frontMatter = (page as MdxFile).frontMatter || {};
// Get tag counts for the tag bar
if (frontMatter.tags && Array.isArray(frontMatter.tags)) {
frontMatter.tags.forEach((tag: string) => {
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
});
}
if (frontMatter.hidden) {return null}
return frontMatter;
});
// Get all posts from route and calculate tag counts
const { allPosts, tagCounts } = useMemo(() => {
const tagCounts: Record<string, number> = {};
const allPosts = getPagesUnderRoute("/blog").filter((page) => {
const frontMatter = (page as MdxFile).frontMatter || {};
// Get tag counts for the tag bar
if (frontMatter.tags && Array.isArray(frontMatter.tags)) {
frontMatter.tags.forEach((tag: string) => {
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
});
}
if (frontMatter.hidden) {return null}
return frontMatter;
});
return { allPosts, tagCounts };
}, []);

// Redirect to main blog page if no tag specified or empty tag
// (but only after router is ready and we've attempted to parse the tag)
useEffect(() => {
// Reset redirect flag when activeTag changes
if (activeTag !== lastActiveTag.current) {
hasRedirectedEmptyTag.current = false;
lastActiveTag.current = activeTag;
}

if (router.isReady && !activeTag &&
!hasRedirectedEmptyTag.current &&
(
!router.query.tag ||
(typeof router.query.tag === 'string' && router.query.tag.trim() === '') ||
Expand All @@ -75,18 +88,23 @@ export function BlogIndex() {
router.asPath.endsWith('?tag=')
)
) {
router.push('/blog')
} // eslint-disable-next-line react-hooks/exhaustive-deps
}, [router.isReady, activeTag, router.query.tag, router.asPath])
// excluding router object from deps to prevent infinite loop (it changes on every navigation)
hasRedirectedEmptyTag.current = true;
router.push('/blog');
}
}, [router, activeTag])

// Redirect if tag has no posts
useEffect(() => {
if (router.isReady && activeTag && (!tagCounts[activeTag] || tagCounts[activeTag] === 0)) {
router.push('/blog')
} // eslint-disable-next-line react-hooks/exhaustive-deps
}, [router.isReady, activeTag])
// excluding router object from deps to prevent infinite loop (it changes on every navigation)
// Reset redirect flag when activeTag changes to a valid tag
if (activeTag && tagCounts[activeTag] && tagCounts[activeTag] > 0) {
hasRedirectedInvalidTag.current = false;
}

if (router.isReady && activeTag && !hasRedirectedInvalidTag.current && (!tagCounts[activeTag] || tagCounts[activeTag] === 0)) {
hasRedirectedInvalidTag.current = true;
router.push('/blog');
}
}, [router, activeTag, tagCounts])

// Filter blogs by tag
const filteredPosts = allPosts.filter((page) => {
Expand Down Expand Up @@ -219,8 +237,8 @@ export function BlogIndex() {
}

const subscribeFormSchema = z.object({
email: z.string().email({
message: "Please enter a valid email.",
email: z.email({
error: "Please enter a valid email.",
}),
});

Expand Down
6 changes: 3 additions & 3 deletions components/github.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useState } from "react";
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { Input } from "./ui/input";
import { useMDXComponents } from "nextra-theme-docs";
import { useMDXComponents } from "nextra/mdx";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
import { Link } from "nextra-theme-docs"
Expand Down Expand Up @@ -217,7 +217,7 @@ export function UsernameToID() {
{globalNodeID && (
<div className="mt-8">
<h2 className="text-xl font-bold">Global Node ID</h2>
<Pre hasCopyCode><Code>{globalNodeID}</Code></Pre>
<Pre><Code>{globalNodeID}</Code></Pre>
</div>
)}
{rawData && (
Expand All @@ -228,7 +228,7 @@ export function UsernameToID() {
<Details>
<Summary>Raw data</Summary>
<div className="mt-2">
<Pre hasCopyCode><Code>{JSON.stringify(rawData, null, 2)}</Code></Pre>
<Pre><Code>{JSON.stringify(rawData, null, 2)}</Code></Pre>
</div>
</Details>
</div>
Expand Down
Loading