locale !== currentLocale); - if (supportedLanguages.length === 0) { - return null; - } + if (!supportedLanguages.length) return null; return ( diff --git a/apps/documentation/app/[locale]/[project]/page.tsx b/apps/documentation/app/[locale]/[project]/page.tsx index 924382c8..ea4c6d18 100644 --- a/apps/documentation/app/[locale]/[project]/page.tsx +++ b/apps/documentation/app/[locale]/[project]/page.tsx @@ -17,9 +17,7 @@ export default async function Page({ params }: PageProps) { project, }); - if (document === null) { - notFound(); - } + if (document === null) notFound(); return ( cur === locale); - if (!isValidLocale) { - notFound(); - } + if (!isValidLocale) notFound(); // setting setRequestLocale to support next-intl for static rendering setRequestLocale(locale); @@ -65,12 +64,12 @@ export default async function MainLayout({ children, params: { locale } }: MainL } return ( - + - + {children} - + diff --git a/apps/documentation/app/icon.svg b/apps/documentation/app/icon.svg index 52f50a5b..f19819df 100644 --- a/apps/documentation/app/icon.svg +++ b/apps/documentation/app/icon.svg @@ -12,12 +12,12 @@ .st6{fill:#0FA3CF;} .st7{fill:#13B3E2;} - - - - - - - - + + + + + + + + diff --git a/apps/documentation/app/not-found.tsx b/apps/documentation/app/not-found.tsx index a6b7634a..67fbc611 100644 --- a/apps/documentation/app/not-found.tsx +++ b/apps/documentation/app/not-found.tsx @@ -13,7 +13,7 @@ const quicksand = Quicksand({ export default function NotFound() { return ( - + 404 - Not found diff --git a/apps/documentation/components/DocSearchComponent.tsx b/apps/documentation/components/DocSearchComponent.tsx index cb842c65..87de1f36 100644 --- a/apps/documentation/components/DocSearchComponent.tsx +++ b/apps/documentation/components/DocSearchComponent.tsx @@ -1,10 +1,10 @@ "use client"; -import { inputVariants } from "@codaco/ui"; -import "@docsearch/css"; import { DocSearch } from "@docsearch/react"; -import { Search } from "lucide-react"; import { useLocale, useTranslations } from "next-intl"; +import "@docsearch/css"; +import { inputVariants } from "@codaco/ui"; +import { Search } from "lucide-react"; import { env } from "~/env"; import { cn } from "~/lib/utils"; diff --git a/apps/documentation/components/Hero.tsx b/apps/documentation/components/Hero.tsx index 7ac9240a..27a4b6a7 100644 --- a/apps/documentation/components/Hero.tsx +++ b/apps/documentation/components/Hero.tsx @@ -58,7 +58,7 @@ export function Hero() { {t("Hero.title")} {t("Hero.tagline")} - + {resolvedTheme !== "dark" && ( diff --git a/apps/documentation/components/ProjectSwitcher.tsx b/apps/documentation/components/ProjectSwitcher.tsx index 94c8a9e1..e614c5d6 100644 --- a/apps/documentation/components/ProjectSwitcher.tsx +++ b/apps/documentation/components/ProjectSwitcher.tsx @@ -68,7 +68,7 @@ export default function ProjectSwitcher() { {projects.map((p) => ( - + ))} diff --git a/apps/documentation/components/SharedNav/Menu.tsx b/apps/documentation/components/SharedNav/Menu.tsx index c0be451d..b17b6c3e 100644 --- a/apps/documentation/components/SharedNav/Menu.tsx +++ b/apps/documentation/components/SharedNav/Menu.tsx @@ -54,7 +54,7 @@ export const NavigationMenuDemo = () => { const t = useTranslations("SharedNavigation"); return ( - + {links.map((link, i) => { @@ -62,13 +62,13 @@ export const NavigationMenuDemo = () => { return ( - {t(link.translationKey)} + {t(link.translationKey)} {link.menu.map((subLink, i) => ( - + { const t = useTranslations("SharedNavigation"); const [submenu, setSubmenu] = useState([]); - if (submenu.length === 0) { + if (!submenu.length) { return ( {links.map((link, i) => { diff --git a/apps/documentation/components/Sidebar.tsx b/apps/documentation/components/Sidebar.tsx index a48aa40c..5917dbb2 100644 --- a/apps/documentation/components/Sidebar.tsx +++ b/apps/documentation/components/Sidebar.tsx @@ -5,7 +5,7 @@ import { useLocale } from "next-intl"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { type RefObject, useEffect, useMemo, useRef, useState } from "react"; -import type { Locale, Project, SidebarPage, TSideBar, SidebarFolder as tSidebarFolder } from "~/app/types"; +import type { Locale, Project, SidebarPage, TSideBar, SidebarFolder as TSidebarFolder } from "~/app/types"; import { cn } from "~/lib/utils"; import sidebarData from "~/public/sidebar.json"; import DocSearchComponent from "./DocSearchComponent"; @@ -21,7 +21,7 @@ const MotionChevron = motion.create(ChevronRight); * @param sidebarItems {(TSidebarFolder | SidebarPage)[]} * @returns {(TSidebarFolder | SidebarPage)[]} */ -const sortSidebarItems = (sidebarItems: (tSidebarFolder | SidebarPage)[]) => +const sortSidebarItems = (sidebarItems: (TSidebarFolder | SidebarPage)[]) => sidebarItems.sort((a, b) => { // If both items have navOrder, sort by that if (a.navOrder !== null && b.navOrder !== null) { @@ -39,20 +39,16 @@ const sortSidebarItems = (sidebarItems: (tSidebarFolder | SidebarPage)[]) => return a.label.localeCompare(b.label); }); -const pathSeparatorRegex = /[\\/]/; - export function processSourceFile(type: "page", locale: Locale, sourceFile: string): string; export function processSourceFile(type: "folder", locale: Locale, sourceFile: string | undefined): string | undefined; // Used by sidebar to process sourceFile values into usable routes export function processSourceFile(type: "folder" | "page", locale: Locale, sourceFile?: string) { - if (!sourceFile) { - return; - } + if (!sourceFile) return; // We can't use path.sep because the webpack node shim always returns '/'. // Because this might be running on Windows, we need to use a regex to split // by either / or \. - const pathSegments = sourceFile.split(pathSeparatorRegex).slice(2); + const pathSegments = sourceFile.split(/[\\/]/).slice(2); let returnPath = ""; @@ -89,13 +85,9 @@ const SidebarFolder = ({ const pathname = usePathname(); const memoizedIsOpen = useMemo(() => { - if (alwaysOpen) { - return true; - } + if (alwaysOpen) return true; - if (defaultOpen) { - return true; - } + if (defaultOpen) return true; return (children as React.ReactElement<{ href?: string }>[]).some((child) => child.props.href === pathname); }, [alwaysOpen, defaultOpen, children, pathname]); @@ -111,9 +103,7 @@ const SidebarFolder = ({ defaultOpen={defaultOpen ?? alwaysOpen} open={isOpen} onOpenChange={() => { - if (alwaysOpen) { - return; - } + if (alwaysOpen) return; setIsOpen(!isOpen); }} className={cn("my-4 flex flex-col")} @@ -123,7 +113,7 @@ const SidebarFolder = ({ "focusable my-1 flex flex-1 items-center justify-between text-balance text-base font-semibold capitalize", !alwaysOpen && "cursor-pointer", )} - asChild={true} + asChild > {href ? ( @@ -133,7 +123,7 @@ const SidebarFolder = ({ className="h-4 w-4" initial={{ rotate: isOpen ? 90 : 0 }} animate={{ rotate: isOpen ? 90 : 0 }} - aria-hidden={true} + aria-hidden /> )} @@ -145,7 +135,7 @@ const SidebarFolder = ({ className="h-4 w-4" initial={{ rotate: isOpen ? 90 : 0 }} animate={{ rotate: isOpen ? 90 : 0 }} - aria-hidden={true} + aria-hidden /> )} @@ -153,7 +143,7 @@ const SidebarFolder = ({ @@ -202,7 +192,7 @@ const SidebarLink = ({ }; const renderSidebarItem = ( - item: tSidebarFolder | SidebarPage, + item: TSidebarFolder | SidebarPage, locale: Locale, sidebarContainerRef: RefObject, ) => { diff --git a/apps/documentation/components/TableOfContents.tsx b/apps/documentation/components/TableOfContents.tsx index 36e5ae48..b01c5711 100644 --- a/apps/documentation/components/TableOfContents.tsx +++ b/apps/documentation/components/TableOfContents.tsx @@ -7,7 +7,7 @@ import useHighlighted from "~/hooks/useHighlighted"; import type { HeadingNode } from "~/lib/tableOfContents"; import { cn } from "~/lib/utils"; -const tocLink = ({ +const TOCLink = ({ node, sideBar, }: { @@ -18,9 +18,7 @@ const tocLink = ({ const [highlighted] = useHighlighted(node.id); useEffect(() => { - if (!sideBar) { - return; - } + if (!sideBar) return; if (highlighted && ref.current) { ref.current.scrollIntoView({ @@ -75,7 +73,7 @@ function renderNodes(nodes: HeadingNode[], sideBar: boolean) { {nodes.map((node) => ( - + {node.children?.length > 0 && renderNodes(node.children, sideBar)} ))} diff --git a/apps/documentation/components/ai-assistant.tsx b/apps/documentation/components/ai-assistant.tsx index db4b644f..9fdf8e2d 100644 --- a/apps/documentation/components/ai-assistant.tsx +++ b/apps/documentation/components/ai-assistant.tsx @@ -41,7 +41,7 @@ const TriggerButton = () => { return ( - + } {content} - {showToc && } + {showToc && } > ); } diff --git a/apps/documentation/components/customComponents/CodeCopyButton.tsx b/apps/documentation/components/customComponents/CodeCopyButton.tsx index 85fba26d..06d9a5b7 100644 --- a/apps/documentation/components/customComponents/CodeCopyButton.tsx +++ b/apps/documentation/components/customComponents/CodeCopyButton.tsx @@ -13,13 +13,15 @@ const CodeCopyButton = ({ code }: { code: string }) => { await navigator.clipboard.writeText(text); setIsCopied(true); setTimeout(() => setIsCopied(false), 2000); // Reset state after 2 seconds - } catch (error) {} + } catch (error) { + console.error("Failed to copy to clipboard:", error); + } }; return ( - - + + {isCopied ? ( diff --git a/apps/documentation/components/customComponents/VideoIFrame.tsx b/apps/documentation/components/customComponents/VideoIFrame.tsx index 01c4d5b5..0a81e9da 100644 --- a/apps/documentation/components/customComponents/VideoIFrame.tsx +++ b/apps/documentation/components/customComponents/VideoIFrame.tsx @@ -1,5 +1,5 @@ const VideoIFrame = ({ src, title }: { src: string; title: string }) => { - return ; + return ; }; export default VideoIFrame; diff --git a/apps/documentation/lib/docs.tsx b/apps/documentation/lib/docs.tsx index 900cfde2..7479ac26 100644 --- a/apps/documentation/lib/docs.tsx +++ b/apps/documentation/lib/docs.tsx @@ -1,10 +1,9 @@ +import { existsSync, readFileSync } from "node:fs"; +import { join, sep } from "node:path"; import { Button, Details, Heading, ListItem, OrderedList, Paragraph, Summary, UnorderedList } from "@codaco/ui"; import rehypeFigure from "@microflash/rehype-figure"; import type { LinkProps } from "next/link"; -import { existsSync, readFileSync } from "node:fs"; -import { join, sep } from "node:path"; import type { ReactNode } from "react"; -// biome-ignore lint/style/noNamespaceImport: workaround import * as prod from "react/jsx-runtime"; import rehypeHighlight from "rehype-highlight"; import rehypeRaw from "rehype-raw"; @@ -33,6 +32,7 @@ import KeyConcept from "~/components/customComponents/KeyConcept"; import Pre from "~/components/customComponents/Pre"; import { PrerequisitesSection, SummaryCard, SummarySection } from "~/components/customComponents/SummaryCard"; import TipBox, { type TipBoxProps } from "~/components/customComponents/TipBox"; +import VideoIFrame from "~/components/customComponents/VideoIFrame"; import sidebar from "~/public/sidebar.json"; import { get } from "./helper_functions"; import processPreTags from "./processPreTags"; @@ -113,6 +113,7 @@ export const getDocsForRouteSegment = ({ const sidebarData = get(typedSidebar, [locale, project], null) as SidebarProject; if (!sidebarData) { + console.log(`No sidebar data found for ${locale} and ${project}`); return []; } @@ -158,9 +159,7 @@ export const getDocsForRouteSegment = ({ export const getSourceFile = (locale: string, project: string, pathSegment?: string[]) => { const projectSourceFile = get(sidebar, [locale, project, "sourceFile"], null) as string; - if (!pathSegment) { - return join(process.cwd(), projectSourceFile); - } + if (!pathSegment) return join(process.cwd(), projectSourceFile); const pathSegmentWithChildren = pathSegment.flatMap((segment, index) => { if (index === 0) { @@ -176,9 +175,7 @@ export const getSourceFile = (locale: string, project: string, pathSegment?: str null, ) as string | null; - if (!folderSourceFile) { - return null; - } + if (!folderSourceFile) return null; return join(process.cwd(), folderSourceFile); }; @@ -195,6 +192,7 @@ export async function getDocumentForPath({ const sourceFile = getSourceFile(locale, project, pathSegment); if (!sourceFile || (sourceFile && !existsSync(sourceFile))) { + console.log(`File not found: ${sourceFile}`); return null; } @@ -263,7 +261,7 @@ export async function getDocumentForPath({ keyconcept: (props: { title: string; children: ReactNode }) => , goodpractice: (props: { children: ReactNode }) => , badpractice: (props: { children: ReactNode }) => , - videoiframe: (props: { src: string; title: string }) => , + videoiframe: (props: { src: string; title: string }) => , summarycard: (props: { duration: string; children: ReactNode }) => , prerequisitessection: (props: { children: ReactNode }) => , summarysection: (props: { children: ReactNode }) => , diff --git a/apps/documentation/lib/helper_functions.ts b/apps/documentation/lib/helper_functions.ts index 66f7ec1c..5c896b6b 100644 --- a/apps/documentation/lib/helper_functions.ts +++ b/apps/documentation/lib/helper_functions.ts @@ -55,9 +55,7 @@ export const getNestedPath = (path: string) => { // it might not work for some edge cases. Test your code! export const get = (obj: Record, path: string | string[], defValue: unknown = undefined) => { // If path is not defined or it has false value - if (!path) { - return undefined; - } + if (!path) return undefined; // Check if path is string or array. Regex : ensure that we do not have '.' and brackets. // Regex explained: https://regexr.com/58j0k const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g); diff --git a/apps/documentation/lib/processPreTags.ts b/apps/documentation/lib/processPreTags.ts index e22b2c39..f2e12e6b 100644 --- a/apps/documentation/lib/processPreTags.ts +++ b/apps/documentation/lib/processPreTags.ts @@ -18,9 +18,7 @@ const processPreTags = () => { return (tree: Tree) => { visit(tree, { tagName: "pre" }, (node) => { const codeElement = node.children.find((child) => child.tagName === "code"); - if (!codeElement) { - return; - } + if (!codeElement) return; // Extract the text content from the `code` element const rawCodeContent = hastNodeToString(codeElement); diff --git a/apps/documentation/lib/writeSidebarJson.ts b/apps/documentation/lib/writeSidebarJson.ts index 722685cb..a6f0d6ba 100644 --- a/apps/documentation/lib/writeSidebarJson.ts +++ b/apps/documentation/lib/writeSidebarJson.ts @@ -60,15 +60,16 @@ function generateSidebarData() { } // Only process files ending in .md or .mdx - if (!file.name.endsWith(".md") && !file.name.endsWith(".mdx")) { - return; - } + if (!file.name.endsWith(".md") && !file.name.endsWith(".mdx")) return; // Determine locale based on file name (format is `index.en.mdx` or `index.en.md`) const locale = file.name.split(".")[1] as Locale | undefined; // If there's no locale, or the locale isn't included in the type, ignore it. if (!locale || !locales.includes(locale as Locale)) { + console.warn( + `File ${file.name} is missing a locale or has a locale not defined in Locale. Locale is ${locale}. Skipping.`, + ); return; } @@ -82,9 +83,7 @@ function generateSidebarData() { const matterResult = matter(markdownFile); // If file has "hidden: true" in frontmatter, skip it - if (matterResult.data.hidden) { - return; - } + if (matterResult.data.hidden) return; set(sidebarData[locale], [...nestedPath, key], createPageEntry(file, matterResult)); } @@ -97,7 +96,5 @@ try { writeFileSync(join(process.cwd(), "public", "sidebar.json"), JSON.stringify(sidebarData, null, 2), "utf-8"); } catch (e) { - // biome-ignore lint/suspicious/noConsole: - console.error(e); - process.exit(1); + console.log("Error writing sidebar data!", e); } diff --git a/apps/documentation/public/algolia-logo.svg b/apps/documentation/public/algolia-logo.svg index 2a5d5e63..44e9942d 100644 --- a/apps/documentation/public/algolia-logo.svg +++ b/apps/documentation/public/algolia-logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/documentation/public/assets/img/logo-inline.svg b/apps/documentation/public/assets/img/logo-inline.svg index d5058852..9c3e33d8 100644 --- a/apps/documentation/public/assets/img/logo-inline.svg +++ b/apps/documentation/public/assets/img/logo-inline.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/documentation/public/assets/img/logo.svg b/apps/documentation/public/assets/img/logo.svg index f8cbf280..0ad76d88 100644 --- a/apps/documentation/public/assets/img/logo.svg +++ b/apps/documentation/public/assets/img/logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/documentation/public/assets/img/sidebar-bg-cropped.svg b/apps/documentation/public/assets/img/sidebar-bg-cropped.svg index b015ae8e..f84765cb 100644 --- a/apps/documentation/public/assets/img/sidebar-bg-cropped.svg +++ b/apps/documentation/public/assets/img/sidebar-bg-cropped.svg @@ -1 +1 @@ -sidebar-bg-cropped \ No newline at end of file +sidebar-bg-cropped \ No newline at end of file diff --git a/apps/documentation/public/assets/img/tip-caution.svg b/apps/documentation/public/assets/img/tip-caution.svg index dd2e7921..49535f4b 100644 --- a/apps/documentation/public/assets/img/tip-caution.svg +++ b/apps/documentation/public/assets/img/tip-caution.svg @@ -1 +1 @@ -Warning \ No newline at end of file +Warning \ No newline at end of file diff --git a/apps/documentation/public/assets/img/tip-info.svg b/apps/documentation/public/assets/img/tip-info.svg index e590d33d..c77c1b4c 100644 --- a/apps/documentation/public/assets/img/tip-info.svg +++ b/apps/documentation/public/assets/img/tip-info.svg @@ -1 +1 @@ -Info \ No newline at end of file +Info \ No newline at end of file diff --git a/apps/documentation/public/favicons/icon.svg b/apps/documentation/public/favicons/icon.svg index 52f50a5b..f19819df 100644 --- a/apps/documentation/public/favicons/icon.svg +++ b/apps/documentation/public/favicons/icon.svg @@ -12,12 +12,12 @@ .st6{fill:#0FA3CF;} .st7{fill:#13B3E2;} - - - - - - - - + + + + + + + + diff --git a/apps/documentation/public/images/key-concept.svg b/apps/documentation/public/images/key-concept.svg index a3db2199..2d458866 100644 --- a/apps/documentation/public/images/key-concept.svg +++ b/apps/documentation/public/images/key-concept.svg @@ -6,6 +6,6 @@ .st0{fill:#DEA800;} .st1{fill:#F2B700;} - - + + diff --git a/apps/documentation/public/images/mark.svg b/apps/documentation/public/images/mark.svg index 52f50a5b..f19819df 100644 --- a/apps/documentation/public/images/mark.svg +++ b/apps/documentation/public/images/mark.svg @@ -12,12 +12,12 @@ .st6{fill:#0FA3CF;} .st7{fill:#13B3E2;} - - - - - - - - + + + + + + + + diff --git a/apps/documentation/public/images/robot.svg b/apps/documentation/public/images/robot.svg index 54577b3f..4efe235a 100644 --- a/apps/documentation/public/images/robot.svg +++ b/apps/documentation/public/images/robot.svg @@ -28,56 +28,56 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/documentation/public/images/tip-caution.svg b/apps/documentation/public/images/tip-caution.svg index 43b64186..d5388560 100644 --- a/apps/documentation/public/images/tip-caution.svg +++ b/apps/documentation/public/images/tip-caution.svg @@ -9,22 +9,22 @@ .st3{fill:#F22F66;} - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/apps/documentation/public/images/tip-info.svg b/apps/documentation/public/images/tip-info.svg index e590d33d..c77c1b4c 100644 --- a/apps/documentation/public/images/tip-info.svg +++ b/apps/documentation/public/images/tip-info.svg @@ -1 +1 @@ -Info \ No newline at end of file +Info \ No newline at end of file diff --git a/apps/documentation/public/images/typemark-negative.svg b/apps/documentation/public/images/typemark-negative.svg index 35c15fdd..96a0954a 100644 --- a/apps/documentation/public/images/typemark-negative.svg +++ b/apps/documentation/public/images/typemark-negative.svg @@ -15,34 +15,34 @@ - - + + - - + + - - + - - + - - - - - - - - - - - - - - + + - - + + - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/biome.json b/biome.json index 3b90cb66..cd382fd6 100644 --- a/biome.json +++ b/biome.json @@ -7,33 +7,8 @@ "enabled": true, "rules": { "recommended": true, - "performance": { - "all": true - }, - "security": { - "all": true - }, - "style": { - "all": true, - "useNamingConvention": "off", - "useFilenamingConvention": "off", - "noDefaultExport": "off" - }, - "suspicious": { - "all": true, - "noReactSpecificProps": "off" - }, "correctness": { "noUnusedImports": "error" - }, - "a11y": { - "all": true - }, - "nursery": { - "useGoogleFontDisplay": "error", - "noDocumentImportInPage": "error", - "noHeadElement": "error", - "noHeadImportInDocument": "error" } } }, diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index f0bfd706..171619dd 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -88,8 +88,12 @@ export const createRouteHandler = ({ // Check if analytics is disabled if (disableAnalytics) { - // biome-ignore lint/suspicious/noConsole: console.info("🛑 Analytics disabled. Payload not sent."); + try { + console.info("Payload:", "\n", JSON.stringify(incomingEvent, null, 2)); + } catch (e) { + console.error("Error stringifying payload:", e); + } return NextResponse.json({ message: "Analytics disabled" }, { status: 200 }); } @@ -98,13 +102,14 @@ export const createRouteHandler = ({ const trackableEvent = TrackableEventSchema.safeParse(incomingEvent); if (!trackableEvent.success) { + console.error("Invalid event:", trackableEvent.error); return NextResponse.json({ error: "Invalid event" }, { status: 400 }); } // We don't want failures in third party services to prevent us from // tracking analytics events, so we'll catch any errors and log them // and continue with an 'Unknown' country code. - let countryIsoCode = "Unknown"; + let countryISOCode = "Unknown"; try { const ip = await fetch("https://api64.ipify.org").then((res) => res.text()); @@ -115,20 +120,18 @@ export const createRouteHandler = ({ const geoData = (await fetch(`http://ip-api.com/json/${ip}`).then((res) => res.json())) as GeoData; if (geoData.status === "success") { - countryIsoCode = geoData.countryCode; + countryISOCode = geoData.countryCode; } else { throw new Error(geoData.message); } } catch (e) { - const error = ensureError(e); - // biome-ignore lint/suspicious/noConsole: - console.error(`Error fetching country code: ${error.message}`); + console.error("Geolocation failed:", e); } const analyticsEvent: analyticsEvent = { ...trackableEvent.data, installationId, - countryISOCode: countryIsoCode, + countryISOCode, }; // Forward to backend @@ -156,6 +159,8 @@ export const createRouteHandler = ({ if (response.status === 500) { error = "Analytics platform returned an internal server error. Please check the platform logs."; } + + console.info(`⚠️ Analytics platform rejected event: ${error}`); return Response.json( { error, @@ -163,9 +168,11 @@ export const createRouteHandler = ({ { status: 500 }, ); } + console.info("🚀 Analytics event sent to platform!"); return Response.json({ message: "Event forwarded successfully" }); } catch (e) { const error = ensureError(e); + console.info("🚫 Internal error with sending analytics event."); return Response.json({ error: `Error in analytics route handler: ${error.message}` }, { status: 500 }); } diff --git a/packages/analytics/src/utils.ts b/packages/analytics/src/utils.ts index d49e6aa0..d562793e 100644 --- a/packages/analytics/src/utils.ts +++ b/packages/analytics/src/utils.ts @@ -1,23 +1,17 @@ // Helper function that ensures that a value is an Error export function ensureError(value: unknown): Error { - if (!value) { - return new Error("No value was thrown"); - } + if (!value) return new Error("No value was thrown"); - if (value instanceof Error) { - return value; - } + if (value instanceof Error) return value; // Test if value inherits from Error - if (Object.prototype.isPrototypeOf.call(value, Error)) { - return value as Error & typeof value; - } + if (Object.prototype.isPrototypeOf.call(value, Error)) return value as Error & typeof value; let stringified = "[Unable to stringify the thrown value]"; try { stringified = JSON.stringify(value); } catch (e) { - // Do nothing + console.error(e); } const error = new Error(`This value was thrown as is, not through an Error: ${stringified}`); diff --git a/packages/art/src/BackgroundBlobs/BackgroundBlobs.tsx b/packages/art/src/BackgroundBlobs/BackgroundBlobs.tsx index 59144ba9..f8b8eabe 100644 --- a/packages/art/src/BackgroundBlobs/BackgroundBlobs.tsx +++ b/packages/art/src/BackgroundBlobs/BackgroundBlobs.tsx @@ -1,6 +1,6 @@ "use client"; -import { svgPath } from "blobs/v2"; +import * as blobs2 from "blobs/v2"; import { interpolatePath } from "d3-interpolate-path"; import { memo, useMemo } from "react"; import Canvas from "./Canvas"; @@ -32,7 +32,7 @@ const gradients = [ const DEFAULT_SPEED_FACTOR = 1; -class NcBlob { +class NCBlob { layer: 1 | 2 | 3; speed: number; angle: number; @@ -168,14 +168,14 @@ class NcBlob { this.positionY = randomInt(0 - this.size / 2, this.canvasHeight - this.size / 2); // Create two random shapes to interpolate between for visual variation - this.shape = svgPath({ + this.shape = blobs2.svgPath({ seed: Math.random(), extraPoints: 6, randomness: 6, size: this.size, }); - this.shape2 = svgPath({ + this.shape2 = blobs2.svgPath({ seed: Math.random(), extraPoints: 8, randomness: 8, @@ -200,9 +200,7 @@ class NcBlob { this.initialize(ctx); } - if (!this.interpolator) { - return; - } + if (!this.interpolator) return; if (!this.gradient?.[0] || !this.gradient[1]) { return; @@ -249,9 +247,9 @@ const BackgroundBlobs = memo( }: BackgroundBlobsProps) => { const blobs = useMemo( () => [ - new Array(large).fill(null).map(() => new NcBlob(3, speedFactor)), - new Array(medium).fill(null).map(() => new NcBlob(2, speedFactor)), - new Array(small).fill(null).map(() => new NcBlob(1, speedFactor)), + new Array(large).fill(null).map(() => new NCBlob(3, speedFactor)), + new Array(medium).fill(null).map(() => new NCBlob(2, speedFactor)), + new Array(small).fill(null).map(() => new NCBlob(1, speedFactor)), ], [large, medium, small, speedFactor], ); diff --git a/packages/shared-consts/src/index.ts b/packages/shared-consts/src/index.ts new file mode 100644 index 00000000..15bd12e4 --- /dev/null +++ b/packages/shared-consts/src/index.ts @@ -0,0 +1,10 @@ +export * from "./assets"; +export * from "./codebook"; +export * from "./colors"; +export * from "./controls"; +export * from "./export-process"; +export * from "./network"; +export * from "./protocol"; +export * from "./session"; +export * from "./stages"; +export * from "./variables"; diff --git a/packages/ui/src/Alert.tsx b/packages/ui/src/Alert.tsx index 7590757c..5fff669c 100644 --- a/packages/ui/src/Alert.tsx +++ b/packages/ui/src/Alert.tsx @@ -43,4 +43,4 @@ const AlertDescription = React.forwardRef import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; +import * as React from "react"; import type { VariantProps } from "class-variance-authority"; -import { forwardRef, type ComponentPropsWithoutRef, type ElementRef, type HTMLAttributes } from "react"; import { buttonVariants } from "./Button"; import { DialogDescription, DialogTitle } from "./dialog"; import { cn } from "./utils"; @@ -18,9 +17,9 @@ const AlertDialogPortal = ({ ...props }: AlertDialogPrimitive.AlertDialogPortalP ); AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName; -const AlertDialogOverlay = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( , - ComponentPropsWithoutRef +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( @@ -51,19 +50,19 @@ const AlertDialogContent = forwardRef< )); AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; -const AlertDialogHeader = ({ className, ...props }: HTMLAttributes) => ( +const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( ); AlertDialogHeader.displayName = "AlertDialogHeader"; -const AlertDialogFooter = ({ className, ...props }: HTMLAttributes) => ( +const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( ); AlertDialogFooter.displayName = "AlertDialogFooter"; -const AlertDialogAction = forwardRef< - ElementRef, - ComponentPropsWithoutRef & { +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { buttonVariant?: VariantProps["variant"]; } >(({ className, buttonVariant, ...props }, ref) => ( @@ -75,9 +74,9 @@ const AlertDialogAction = forwardRef< )); AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; -const AlertDialogCancel = forwardRef< - ElementRef, - ComponentPropsWithoutRef & { +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { buttonVariant?: VariantProps["variant"]; } >(({ className, buttonVariant, ...props }, ref) => ( @@ -95,12 +94,12 @@ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; export { AlertDialog, - AlertDialogAction, - AlertDialogCancel, + AlertDialogTrigger, AlertDialogContent, - DialogDescription as AlertDialogDescription, - AlertDialogFooter, AlertDialogHeader, + AlertDialogFooter, DialogTitle as AlertDialogTitle, - AlertDialogTrigger, + DialogDescription as AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, }; diff --git a/packages/ui/src/Button.tsx b/packages/ui/src/Button.tsx index 1a926e61..6be28a7f 100644 --- a/packages/ui/src/Button.tsx +++ b/packages/ui/src/Button.tsx @@ -1,8 +1,8 @@ import { Slot } from "@radix-ui/react-slot"; import type { VariantProps } from "class-variance-authority"; import { cva } from "class-variance-authority"; +import * as React from "react"; -import { type ButtonHTMLAttributes, forwardRef } from "react"; import { cn } from "./utils"; const baseButtonClasses = cn( @@ -50,9 +50,9 @@ export type ButtonProps = { variant?: VariantProps["variant"]; size?: VariantProps["size"]; asChild?: boolean; -} & ButtonHTMLAttributes; +} & React.ButtonHTMLAttributes; -const Button = forwardRef( +const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { const Comp = asChild ? Slot : "button"; return ; diff --git a/packages/ui/src/FancyBox.tsx b/packages/ui/src/FancyBox.tsx index 146677f3..d5bdf9ea 100644 --- a/packages/ui/src/FancyBox.tsx +++ b/packages/ui/src/FancyBox.tsx @@ -51,16 +51,10 @@ export default function FancyBox { - if (value.length === 0) { - return placeholder; - } - if (value.length === items.length) { - return `All ${plural} Selected (${items.length})`; - } + if (value.length === 0) return placeholder; + if (value.length === items.length) return `All ${plural} Selected (${items.length})`; - if (value.length === 1) { - return `1 ${singular} Selected`; - } + if (value.length === 1) return `1 ${singular} Selected`; return `${value.length} ${plural} Selected`; }, [value, items, placeholder, plural, singular]); @@ -68,7 +62,7 @@ export default function FancyBox - + - + {showSearch && ( + {formattedDate} ); diff --git a/packages/ui/src/Input.tsx b/packages/ui/src/Input.tsx index e4371414..5b5987bd 100644 --- a/packages/ui/src/Input.tsx +++ b/packages/ui/src/Input.tsx @@ -44,7 +44,7 @@ const Input = React.forwardRef( return ( {label && ( - + {label} )} diff --git a/packages/ui/src/accordion.tsx b/packages/ui/src/accordion.tsx index 29efcbc2..6908f515 100644 --- a/packages/ui/src/accordion.tsx +++ b/packages/ui/src/accordion.tsx @@ -51,4 +51,4 @@ const AccordionContent = React.forwardRef< AccordionContent.displayName = AccordionPrimitive.Content.displayName; -export { Accordion, AccordionContent, AccordionItem, AccordionTrigger }; +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/packages/ui/src/card.tsx b/packages/ui/src/card.tsx index 44a51786..c8085175 100644 --- a/packages/ui/src/card.tsx +++ b/packages/ui/src/card.tsx @@ -39,4 +39,4 @@ const CardFooter = React.forwardRef(({ className, children, ...props }, ref) => ( - + {children} @@ -101,11 +101,11 @@ DialogClose.displayName = DialogPrimitive.Title.displayName; export { Dialog, - DialogClose, + DialogTrigger, DialogContent, - DialogDescription, - DialogFooter, DialogHeader, + DialogFooter, DialogTitle, - DialogTrigger, + DialogDescription, + DialogClose, }; diff --git a/packages/ui/src/dropdown-menu.tsx b/packages/ui/src/dropdown-menu.tsx index 74d799ef..9701bc04 100644 --- a/packages/ui/src/dropdown-menu.tsx +++ b/packages/ui/src/dropdown-menu.tsx @@ -164,18 +164,18 @@ DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; export { DropdownMenu, - DropdownMenuCheckboxItem, + DropdownMenuTrigger, DropdownMenuContent, - DropdownMenuGroup, DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuPortal, - DropdownMenuRadioGroup, + DropdownMenuCheckboxItem, DropdownMenuRadioItem, + DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, - DropdownMenuTrigger, + DropdownMenuRadioGroup, }; diff --git a/packages/ui/src/form.tsx b/packages/ui/src/form.tsx index aecc5b9d..804d13c1 100644 --- a/packages/ui/src/form.tsx +++ b/packages/ui/src/form.tsx @@ -85,7 +85,7 @@ const FormLabel = React.forwardRef< >(({ className, ...props }, ref) => { const { error, formItemId } = useFormField(); - return ; + return ; }); FormLabel.displayName = "FormLabel"; @@ -97,7 +97,7 @@ const FormControl = React.forwardRef, React.Compon @@ -135,4 +135,4 @@ const FormMessage = React.forwardRef(({ className, children, ...props }, ref) => ( {children} - + @@ -109,4 +109,4 @@ const SelectSeparator = React.forwardRef< )); SelectSeparator.displayName = SelectPrimitive.Separator.displayName; -export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue }; +export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator }; diff --git a/packages/ui/src/sheet.tsx b/packages/ui/src/sheet.tsx index 4b1e307a..f8c265e5 100644 --- a/packages/ui/src/sheet.tsx +++ b/packages/ui/src/sheet.tsx @@ -97,13 +97,13 @@ SheetDescription.displayName = SheetPrimitive.Description.displayName; export { Sheet, + SheetPortal, + SheetOverlay, + SheetTrigger, SheetClose, SheetContent, - SheetDescription, - SheetFooter, SheetHeader, - SheetOverlay, - SheetPortal, + SheetFooter, SheetTitle, - SheetTrigger, + SheetDescription, }; diff --git a/packages/ui/src/table.tsx b/packages/ui/src/table.tsx index d0f421a2..3f8d7c66 100644 --- a/packages/ui/src/table.tsx +++ b/packages/ui/src/table.tsx @@ -72,4 +72,4 @@ const TableCaption = React.forwardRef - + diff --git a/packages/ui/src/toast.tsx b/packages/ui/src/toast.tsx index 4bc11941..0b7d90bb 100644 --- a/packages/ui/src/toast.tsx +++ b/packages/ui/src/toast.tsx @@ -1,16 +1,15 @@ -// biome-ignore lint/style/noNamespaceImport: radix import * as ToastPrimitives from "@radix-ui/react-toast"; -import { cva, type VariantProps } from "class-variance-authority"; +import { type VariantProps, cva } from "class-variance-authority"; import { X } from "lucide-react"; -import { type ComponentPropsWithoutRef, type ElementRef, forwardRef, type ReactElement } from "react"; +import * as React from "react"; import Heading from "./typography/Heading"; import { cn } from "./utils"; const ToastProvider = ToastPrimitives.Provider; -const ToastViewport = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const ToastViewport = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( , - ComponentPropsWithoutRef & VariantProps +const Toast = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & VariantProps >(({ className, variant, ...props }, ref) => { return ; }); Toast.displayName = ToastPrimitives.Root.displayName; -const ToastAction = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const ToastAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( , - ComponentPropsWithoutRef +const ToastClose = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( , - ComponentPropsWithoutRef +const ToastTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); ToastTitle.displayName = ToastPrimitives.Title.displayName; -const ToastDescription = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const ToastDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); ToastDescription.displayName = ToastPrimitives.Description.displayName; -type ToastProps = ComponentPropsWithoutRef; +type ToastProps = React.ComponentPropsWithoutRef; -type ToastActionElement = ReactElement; +type ToastActionElement = React.ReactElement; export { - Toast, - ToastAction, - ToastClose, - ToastDescription, + type ToastProps, + type ToastActionElement, ToastProvider, - ToastTitle, ToastViewport, - type ToastActionElement, - type ToastProps, + Toast, + ToastTitle, + ToastDescription, + ToastClose, + ToastAction, }; diff --git a/packages/ui/src/tooltip.tsx b/packages/ui/src/tooltip.tsx index f9fd09b5..877b4ae2 100644 --- a/packages/ui/src/tooltip.tsx +++ b/packages/ui/src/tooltip.tsx @@ -1,8 +1,7 @@ "use client"; -// biome-ignore lint/style/noNamespaceImport: radix import * as TooltipPrimitive from "@radix-ui/react-tooltip"; -import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from "react"; +import * as React from "react"; import { cn } from "./utils"; const TooltipProvider = TooltipPrimitive.Provider; @@ -11,9 +10,9 @@ const Tooltip = TooltipPrimitive.Root; const TooltipTrigger = TooltipPrimitive.Trigger; -const TooltipContent = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( { ), }; } - case "REMOVE_TOAST": { + case "REMOVE_TOAST": if (action.toastId === undefined) { return { ...state, @@ -118,10 +120,6 @@ export const reducer = (state: State, action: Action): State => { ...state, toasts: state.toasts.filter((t) => t.id !== action.toastId), }; - } - - default: - return state; } }; @@ -155,9 +153,7 @@ function toast({ ...props }: Toast) { id, open: true, onOpenChange: (open) => { - if (!open) { - dismiss(); - } + if (!open) dismiss(); }, }, }); @@ -170,10 +166,10 @@ function toast({ ...props }: Toast) { } function useToast() { - const [state, setState] = useState(memoryState); + const [state, setState] = React.useState(memoryState); // biome-ignore lint/correctness/useExhaustiveDependencies: state is a reference, so it's fine - useEffect(() => { + React.useEffect(() => { listeners.push(setState); return () => { const index = listeners.indexOf(setState); @@ -190,4 +186,4 @@ function useToast() { }; } -export { toast, useToast }; +export { useToast, toast }; diff --git a/tooling/tailwind/base.ts b/tooling/tailwind/base.ts index 4ee95b6f..74a89ddd 100644 --- a/tooling/tailwind/base.ts +++ b/tooling/tailwind/base.ts @@ -1,6 +1,5 @@ import type { Config } from "tailwindcss"; -// biome-ignore lint/style/noDefaultExport: export default { darkMode: ["class"], content: ["./components/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", "./src/**/*.{ts,tsx}"],
cur === locale); - if (!isValidLocale) { - notFound(); - } + if (!isValidLocale) notFound(); // setting setRequestLocale to support next-intl for static rendering setRequestLocale(locale); @@ -65,12 +64,12 @@ export default async function MainLayout({ children, params: { locale } }: MainL } return ( - + - + {children} - + diff --git a/apps/documentation/app/icon.svg b/apps/documentation/app/icon.svg index 52f50a5b..f19819df 100644 --- a/apps/documentation/app/icon.svg +++ b/apps/documentation/app/icon.svg @@ -12,12 +12,12 @@ .st6{fill:#0FA3CF;} .st7{fill:#13B3E2;} - - - - - - - - + + + + + + + + diff --git a/apps/documentation/app/not-found.tsx b/apps/documentation/app/not-found.tsx index a6b7634a..67fbc611 100644 --- a/apps/documentation/app/not-found.tsx +++ b/apps/documentation/app/not-found.tsx @@ -13,7 +13,7 @@ const quicksand = Quicksand({ export default function NotFound() { return ( - + 404 - Not found diff --git a/apps/documentation/components/DocSearchComponent.tsx b/apps/documentation/components/DocSearchComponent.tsx index cb842c65..87de1f36 100644 --- a/apps/documentation/components/DocSearchComponent.tsx +++ b/apps/documentation/components/DocSearchComponent.tsx @@ -1,10 +1,10 @@ "use client"; -import { inputVariants } from "@codaco/ui"; -import "@docsearch/css"; import { DocSearch } from "@docsearch/react"; -import { Search } from "lucide-react"; import { useLocale, useTranslations } from "next-intl"; +import "@docsearch/css"; +import { inputVariants } from "@codaco/ui"; +import { Search } from "lucide-react"; import { env } from "~/env"; import { cn } from "~/lib/utils"; diff --git a/apps/documentation/components/Hero.tsx b/apps/documentation/components/Hero.tsx index 7ac9240a..27a4b6a7 100644 --- a/apps/documentation/components/Hero.tsx +++ b/apps/documentation/components/Hero.tsx @@ -58,7 +58,7 @@ export function Hero() { {t("Hero.title")} {t("Hero.tagline")} - + {resolvedTheme !== "dark" && ( diff --git a/apps/documentation/components/ProjectSwitcher.tsx b/apps/documentation/components/ProjectSwitcher.tsx index 94c8a9e1..e614c5d6 100644 --- a/apps/documentation/components/ProjectSwitcher.tsx +++ b/apps/documentation/components/ProjectSwitcher.tsx @@ -68,7 +68,7 @@ export default function ProjectSwitcher() { {projects.map((p) => ( - + ))} diff --git a/apps/documentation/components/SharedNav/Menu.tsx b/apps/documentation/components/SharedNav/Menu.tsx index c0be451d..b17b6c3e 100644 --- a/apps/documentation/components/SharedNav/Menu.tsx +++ b/apps/documentation/components/SharedNav/Menu.tsx @@ -54,7 +54,7 @@ export const NavigationMenuDemo = () => { const t = useTranslations("SharedNavigation"); return ( - + {links.map((link, i) => { @@ -62,13 +62,13 @@ export const NavigationMenuDemo = () => { return ( - {t(link.translationKey)} + {t(link.translationKey)} {link.menu.map((subLink, i) => ( - + { const t = useTranslations("SharedNavigation"); const [submenu, setSubmenu] = useState([]); - if (submenu.length === 0) { + if (!submenu.length) { return ( {links.map((link, i) => { diff --git a/apps/documentation/components/Sidebar.tsx b/apps/documentation/components/Sidebar.tsx index a48aa40c..5917dbb2 100644 --- a/apps/documentation/components/Sidebar.tsx +++ b/apps/documentation/components/Sidebar.tsx @@ -5,7 +5,7 @@ import { useLocale } from "next-intl"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { type RefObject, useEffect, useMemo, useRef, useState } from "react"; -import type { Locale, Project, SidebarPage, TSideBar, SidebarFolder as tSidebarFolder } from "~/app/types"; +import type { Locale, Project, SidebarPage, TSideBar, SidebarFolder as TSidebarFolder } from "~/app/types"; import { cn } from "~/lib/utils"; import sidebarData from "~/public/sidebar.json"; import DocSearchComponent from "./DocSearchComponent"; @@ -21,7 +21,7 @@ const MotionChevron = motion.create(ChevronRight); * @param sidebarItems {(TSidebarFolder | SidebarPage)[]} * @returns {(TSidebarFolder | SidebarPage)[]} */ -const sortSidebarItems = (sidebarItems: (tSidebarFolder | SidebarPage)[]) => +const sortSidebarItems = (sidebarItems: (TSidebarFolder | SidebarPage)[]) => sidebarItems.sort((a, b) => { // If both items have navOrder, sort by that if (a.navOrder !== null && b.navOrder !== null) { @@ -39,20 +39,16 @@ const sortSidebarItems = (sidebarItems: (tSidebarFolder | SidebarPage)[]) => return a.label.localeCompare(b.label); }); -const pathSeparatorRegex = /[\\/]/; - export function processSourceFile(type: "page", locale: Locale, sourceFile: string): string; export function processSourceFile(type: "folder", locale: Locale, sourceFile: string | undefined): string | undefined; // Used by sidebar to process sourceFile values into usable routes export function processSourceFile(type: "folder" | "page", locale: Locale, sourceFile?: string) { - if (!sourceFile) { - return; - } + if (!sourceFile) return; // We can't use path.sep because the webpack node shim always returns '/'. // Because this might be running on Windows, we need to use a regex to split // by either / or \. - const pathSegments = sourceFile.split(pathSeparatorRegex).slice(2); + const pathSegments = sourceFile.split(/[\\/]/).slice(2); let returnPath = ""; @@ -89,13 +85,9 @@ const SidebarFolder = ({ const pathname = usePathname(); const memoizedIsOpen = useMemo(() => { - if (alwaysOpen) { - return true; - } + if (alwaysOpen) return true; - if (defaultOpen) { - return true; - } + if (defaultOpen) return true; return (children as React.ReactElement<{ href?: string }>[]).some((child) => child.props.href === pathname); }, [alwaysOpen, defaultOpen, children, pathname]); @@ -111,9 +103,7 @@ const SidebarFolder = ({ defaultOpen={defaultOpen ?? alwaysOpen} open={isOpen} onOpenChange={() => { - if (alwaysOpen) { - return; - } + if (alwaysOpen) return; setIsOpen(!isOpen); }} className={cn("my-4 flex flex-col")} @@ -123,7 +113,7 @@ const SidebarFolder = ({ "focusable my-1 flex flex-1 items-center justify-between text-balance text-base font-semibold capitalize", !alwaysOpen && "cursor-pointer", )} - asChild={true} + asChild > {href ? ( @@ -133,7 +123,7 @@ const SidebarFolder = ({ className="h-4 w-4" initial={{ rotate: isOpen ? 90 : 0 }} animate={{ rotate: isOpen ? 90 : 0 }} - aria-hidden={true} + aria-hidden /> )} @@ -145,7 +135,7 @@ const SidebarFolder = ({ className="h-4 w-4" initial={{ rotate: isOpen ? 90 : 0 }} animate={{ rotate: isOpen ? 90 : 0 }} - aria-hidden={true} + aria-hidden /> )} @@ -153,7 +143,7 @@ const SidebarFolder = ({ @@ -202,7 +192,7 @@ const SidebarLink = ({ }; const renderSidebarItem = ( - item: tSidebarFolder | SidebarPage, + item: TSidebarFolder | SidebarPage, locale: Locale, sidebarContainerRef: RefObject, ) => { diff --git a/apps/documentation/components/TableOfContents.tsx b/apps/documentation/components/TableOfContents.tsx index 36e5ae48..b01c5711 100644 --- a/apps/documentation/components/TableOfContents.tsx +++ b/apps/documentation/components/TableOfContents.tsx @@ -7,7 +7,7 @@ import useHighlighted from "~/hooks/useHighlighted"; import type { HeadingNode } from "~/lib/tableOfContents"; import { cn } from "~/lib/utils"; -const tocLink = ({ +const TOCLink = ({ node, sideBar, }: { @@ -18,9 +18,7 @@ const tocLink = ({ const [highlighted] = useHighlighted(node.id); useEffect(() => { - if (!sideBar) { - return; - } + if (!sideBar) return; if (highlighted && ref.current) { ref.current.scrollIntoView({ @@ -75,7 +73,7 @@ function renderNodes(nodes: HeadingNode[], sideBar: boolean) { {nodes.map((node) => ( - + {node.children?.length > 0 && renderNodes(node.children, sideBar)} ))} diff --git a/apps/documentation/components/ai-assistant.tsx b/apps/documentation/components/ai-assistant.tsx index db4b644f..9fdf8e2d 100644 --- a/apps/documentation/components/ai-assistant.tsx +++ b/apps/documentation/components/ai-assistant.tsx @@ -41,7 +41,7 @@ const TriggerButton = () => { return ( - + } {content} - {showToc && } + {showToc && } > ); } diff --git a/apps/documentation/components/customComponents/CodeCopyButton.tsx b/apps/documentation/components/customComponents/CodeCopyButton.tsx index 85fba26d..06d9a5b7 100644 --- a/apps/documentation/components/customComponents/CodeCopyButton.tsx +++ b/apps/documentation/components/customComponents/CodeCopyButton.tsx @@ -13,13 +13,15 @@ const CodeCopyButton = ({ code }: { code: string }) => { await navigator.clipboard.writeText(text); setIsCopied(true); setTimeout(() => setIsCopied(false), 2000); // Reset state after 2 seconds - } catch (error) {} + } catch (error) { + console.error("Failed to copy to clipboard:", error); + } }; return ( - - + + {isCopied ? ( diff --git a/apps/documentation/components/customComponents/VideoIFrame.tsx b/apps/documentation/components/customComponents/VideoIFrame.tsx index 01c4d5b5..0a81e9da 100644 --- a/apps/documentation/components/customComponents/VideoIFrame.tsx +++ b/apps/documentation/components/customComponents/VideoIFrame.tsx @@ -1,5 +1,5 @@ const VideoIFrame = ({ src, title }: { src: string; title: string }) => { - return ; + return ; }; export default VideoIFrame; diff --git a/apps/documentation/lib/docs.tsx b/apps/documentation/lib/docs.tsx index 900cfde2..7479ac26 100644 --- a/apps/documentation/lib/docs.tsx +++ b/apps/documentation/lib/docs.tsx @@ -1,10 +1,9 @@ +import { existsSync, readFileSync } from "node:fs"; +import { join, sep } from "node:path"; import { Button, Details, Heading, ListItem, OrderedList, Paragraph, Summary, UnorderedList } from "@codaco/ui"; import rehypeFigure from "@microflash/rehype-figure"; import type { LinkProps } from "next/link"; -import { existsSync, readFileSync } from "node:fs"; -import { join, sep } from "node:path"; import type { ReactNode } from "react"; -// biome-ignore lint/style/noNamespaceImport: workaround import * as prod from "react/jsx-runtime"; import rehypeHighlight from "rehype-highlight"; import rehypeRaw from "rehype-raw"; @@ -33,6 +32,7 @@ import KeyConcept from "~/components/customComponents/KeyConcept"; import Pre from "~/components/customComponents/Pre"; import { PrerequisitesSection, SummaryCard, SummarySection } from "~/components/customComponents/SummaryCard"; import TipBox, { type TipBoxProps } from "~/components/customComponents/TipBox"; +import VideoIFrame from "~/components/customComponents/VideoIFrame"; import sidebar from "~/public/sidebar.json"; import { get } from "./helper_functions"; import processPreTags from "./processPreTags"; @@ -113,6 +113,7 @@ export const getDocsForRouteSegment = ({ const sidebarData = get(typedSidebar, [locale, project], null) as SidebarProject; if (!sidebarData) { + console.log(`No sidebar data found for ${locale} and ${project}`); return []; } @@ -158,9 +159,7 @@ export const getDocsForRouteSegment = ({ export const getSourceFile = (locale: string, project: string, pathSegment?: string[]) => { const projectSourceFile = get(sidebar, [locale, project, "sourceFile"], null) as string; - if (!pathSegment) { - return join(process.cwd(), projectSourceFile); - } + if (!pathSegment) return join(process.cwd(), projectSourceFile); const pathSegmentWithChildren = pathSegment.flatMap((segment, index) => { if (index === 0) { @@ -176,9 +175,7 @@ export const getSourceFile = (locale: string, project: string, pathSegment?: str null, ) as string | null; - if (!folderSourceFile) { - return null; - } + if (!folderSourceFile) return null; return join(process.cwd(), folderSourceFile); }; @@ -195,6 +192,7 @@ export async function getDocumentForPath({ const sourceFile = getSourceFile(locale, project, pathSegment); if (!sourceFile || (sourceFile && !existsSync(sourceFile))) { + console.log(`File not found: ${sourceFile}`); return null; } @@ -263,7 +261,7 @@ export async function getDocumentForPath({ keyconcept: (props: { title: string; children: ReactNode }) => , goodpractice: (props: { children: ReactNode }) => , badpractice: (props: { children: ReactNode }) => , - videoiframe: (props: { src: string; title: string }) => , + videoiframe: (props: { src: string; title: string }) => , summarycard: (props: { duration: string; children: ReactNode }) => , prerequisitessection: (props: { children: ReactNode }) => , summarysection: (props: { children: ReactNode }) => , diff --git a/apps/documentation/lib/helper_functions.ts b/apps/documentation/lib/helper_functions.ts index 66f7ec1c..5c896b6b 100644 --- a/apps/documentation/lib/helper_functions.ts +++ b/apps/documentation/lib/helper_functions.ts @@ -55,9 +55,7 @@ export const getNestedPath = (path: string) => { // it might not work for some edge cases. Test your code! export const get = (obj: Record, path: string | string[], defValue: unknown = undefined) => { // If path is not defined or it has false value - if (!path) { - return undefined; - } + if (!path) return undefined; // Check if path is string or array. Regex : ensure that we do not have '.' and brackets. // Regex explained: https://regexr.com/58j0k const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g); diff --git a/apps/documentation/lib/processPreTags.ts b/apps/documentation/lib/processPreTags.ts index e22b2c39..f2e12e6b 100644 --- a/apps/documentation/lib/processPreTags.ts +++ b/apps/documentation/lib/processPreTags.ts @@ -18,9 +18,7 @@ const processPreTags = () => { return (tree: Tree) => { visit(tree, { tagName: "pre" }, (node) => { const codeElement = node.children.find((child) => child.tagName === "code"); - if (!codeElement) { - return; - } + if (!codeElement) return; // Extract the text content from the `code` element const rawCodeContent = hastNodeToString(codeElement); diff --git a/apps/documentation/lib/writeSidebarJson.ts b/apps/documentation/lib/writeSidebarJson.ts index 722685cb..a6f0d6ba 100644 --- a/apps/documentation/lib/writeSidebarJson.ts +++ b/apps/documentation/lib/writeSidebarJson.ts @@ -60,15 +60,16 @@ function generateSidebarData() { } // Only process files ending in .md or .mdx - if (!file.name.endsWith(".md") && !file.name.endsWith(".mdx")) { - return; - } + if (!file.name.endsWith(".md") && !file.name.endsWith(".mdx")) return; // Determine locale based on file name (format is `index.en.mdx` or `index.en.md`) const locale = file.name.split(".")[1] as Locale | undefined; // If there's no locale, or the locale isn't included in the type, ignore it. if (!locale || !locales.includes(locale as Locale)) { + console.warn( + `File ${file.name} is missing a locale or has a locale not defined in Locale. Locale is ${locale}. Skipping.`, + ); return; } @@ -82,9 +83,7 @@ function generateSidebarData() { const matterResult = matter(markdownFile); // If file has "hidden: true" in frontmatter, skip it - if (matterResult.data.hidden) { - return; - } + if (matterResult.data.hidden) return; set(sidebarData[locale], [...nestedPath, key], createPageEntry(file, matterResult)); } @@ -97,7 +96,5 @@ try { writeFileSync(join(process.cwd(), "public", "sidebar.json"), JSON.stringify(sidebarData, null, 2), "utf-8"); } catch (e) { - // biome-ignore lint/suspicious/noConsole: - console.error(e); - process.exit(1); + console.log("Error writing sidebar data!", e); } diff --git a/apps/documentation/public/algolia-logo.svg b/apps/documentation/public/algolia-logo.svg index 2a5d5e63..44e9942d 100644 --- a/apps/documentation/public/algolia-logo.svg +++ b/apps/documentation/public/algolia-logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/documentation/public/assets/img/logo-inline.svg b/apps/documentation/public/assets/img/logo-inline.svg index d5058852..9c3e33d8 100644 --- a/apps/documentation/public/assets/img/logo-inline.svg +++ b/apps/documentation/public/assets/img/logo-inline.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/documentation/public/assets/img/logo.svg b/apps/documentation/public/assets/img/logo.svg index f8cbf280..0ad76d88 100644 --- a/apps/documentation/public/assets/img/logo.svg +++ b/apps/documentation/public/assets/img/logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/documentation/public/assets/img/sidebar-bg-cropped.svg b/apps/documentation/public/assets/img/sidebar-bg-cropped.svg index b015ae8e..f84765cb 100644 --- a/apps/documentation/public/assets/img/sidebar-bg-cropped.svg +++ b/apps/documentation/public/assets/img/sidebar-bg-cropped.svg @@ -1 +1 @@ -sidebar-bg-cropped \ No newline at end of file +sidebar-bg-cropped \ No newline at end of file diff --git a/apps/documentation/public/assets/img/tip-caution.svg b/apps/documentation/public/assets/img/tip-caution.svg index dd2e7921..49535f4b 100644 --- a/apps/documentation/public/assets/img/tip-caution.svg +++ b/apps/documentation/public/assets/img/tip-caution.svg @@ -1 +1 @@ -Warning \ No newline at end of file +Warning \ No newline at end of file diff --git a/apps/documentation/public/assets/img/tip-info.svg b/apps/documentation/public/assets/img/tip-info.svg index e590d33d..c77c1b4c 100644 --- a/apps/documentation/public/assets/img/tip-info.svg +++ b/apps/documentation/public/assets/img/tip-info.svg @@ -1 +1 @@ -Info \ No newline at end of file +Info \ No newline at end of file diff --git a/apps/documentation/public/favicons/icon.svg b/apps/documentation/public/favicons/icon.svg index 52f50a5b..f19819df 100644 --- a/apps/documentation/public/favicons/icon.svg +++ b/apps/documentation/public/favicons/icon.svg @@ -12,12 +12,12 @@ .st6{fill:#0FA3CF;} .st7{fill:#13B3E2;} - - - - - - - - + + + + + + + + diff --git a/apps/documentation/public/images/key-concept.svg b/apps/documentation/public/images/key-concept.svg index a3db2199..2d458866 100644 --- a/apps/documentation/public/images/key-concept.svg +++ b/apps/documentation/public/images/key-concept.svg @@ -6,6 +6,6 @@ .st0{fill:#DEA800;} .st1{fill:#F2B700;} - - + + diff --git a/apps/documentation/public/images/mark.svg b/apps/documentation/public/images/mark.svg index 52f50a5b..f19819df 100644 --- a/apps/documentation/public/images/mark.svg +++ b/apps/documentation/public/images/mark.svg @@ -12,12 +12,12 @@ .st6{fill:#0FA3CF;} .st7{fill:#13B3E2;} - - - - - - - - + + + + + + + + diff --git a/apps/documentation/public/images/robot.svg b/apps/documentation/public/images/robot.svg index 54577b3f..4efe235a 100644 --- a/apps/documentation/public/images/robot.svg +++ b/apps/documentation/public/images/robot.svg @@ -28,56 +28,56 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/documentation/public/images/tip-caution.svg b/apps/documentation/public/images/tip-caution.svg index 43b64186..d5388560 100644 --- a/apps/documentation/public/images/tip-caution.svg +++ b/apps/documentation/public/images/tip-caution.svg @@ -9,22 +9,22 @@ .st3{fill:#F22F66;} - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/apps/documentation/public/images/tip-info.svg b/apps/documentation/public/images/tip-info.svg index e590d33d..c77c1b4c 100644 --- a/apps/documentation/public/images/tip-info.svg +++ b/apps/documentation/public/images/tip-info.svg @@ -1 +1 @@ -Info \ No newline at end of file +Info \ No newline at end of file diff --git a/apps/documentation/public/images/typemark-negative.svg b/apps/documentation/public/images/typemark-negative.svg index 35c15fdd..96a0954a 100644 --- a/apps/documentation/public/images/typemark-negative.svg +++ b/apps/documentation/public/images/typemark-negative.svg @@ -15,34 +15,34 @@ - - + + - - + + - - + - - + - - - - - - - - - - - - - - + + - - + + - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/biome.json b/biome.json index 3b90cb66..cd382fd6 100644 --- a/biome.json +++ b/biome.json @@ -7,33 +7,8 @@ "enabled": true, "rules": { "recommended": true, - "performance": { - "all": true - }, - "security": { - "all": true - }, - "style": { - "all": true, - "useNamingConvention": "off", - "useFilenamingConvention": "off", - "noDefaultExport": "off" - }, - "suspicious": { - "all": true, - "noReactSpecificProps": "off" - }, "correctness": { "noUnusedImports": "error" - }, - "a11y": { - "all": true - }, - "nursery": { - "useGoogleFontDisplay": "error", - "noDocumentImportInPage": "error", - "noHeadElement": "error", - "noHeadImportInDocument": "error" } } }, diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index f0bfd706..171619dd 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -88,8 +88,12 @@ export const createRouteHandler = ({ // Check if analytics is disabled if (disableAnalytics) { - // biome-ignore lint/suspicious/noConsole: console.info("🛑 Analytics disabled. Payload not sent."); + try { + console.info("Payload:", "\n", JSON.stringify(incomingEvent, null, 2)); + } catch (e) { + console.error("Error stringifying payload:", e); + } return NextResponse.json({ message: "Analytics disabled" }, { status: 200 }); } @@ -98,13 +102,14 @@ export const createRouteHandler = ({ const trackableEvent = TrackableEventSchema.safeParse(incomingEvent); if (!trackableEvent.success) { + console.error("Invalid event:", trackableEvent.error); return NextResponse.json({ error: "Invalid event" }, { status: 400 }); } // We don't want failures in third party services to prevent us from // tracking analytics events, so we'll catch any errors and log them // and continue with an 'Unknown' country code. - let countryIsoCode = "Unknown"; + let countryISOCode = "Unknown"; try { const ip = await fetch("https://api64.ipify.org").then((res) => res.text()); @@ -115,20 +120,18 @@ export const createRouteHandler = ({ const geoData = (await fetch(`http://ip-api.com/json/${ip}`).then((res) => res.json())) as GeoData; if (geoData.status === "success") { - countryIsoCode = geoData.countryCode; + countryISOCode = geoData.countryCode; } else { throw new Error(geoData.message); } } catch (e) { - const error = ensureError(e); - // biome-ignore lint/suspicious/noConsole: - console.error(`Error fetching country code: ${error.message}`); + console.error("Geolocation failed:", e); } const analyticsEvent: analyticsEvent = { ...trackableEvent.data, installationId, - countryISOCode: countryIsoCode, + countryISOCode, }; // Forward to backend @@ -156,6 +159,8 @@ export const createRouteHandler = ({ if (response.status === 500) { error = "Analytics platform returned an internal server error. Please check the platform logs."; } + + console.info(`⚠️ Analytics platform rejected event: ${error}`); return Response.json( { error, @@ -163,9 +168,11 @@ export const createRouteHandler = ({ { status: 500 }, ); } + console.info("🚀 Analytics event sent to platform!"); return Response.json({ message: "Event forwarded successfully" }); } catch (e) { const error = ensureError(e); + console.info("🚫 Internal error with sending analytics event."); return Response.json({ error: `Error in analytics route handler: ${error.message}` }, { status: 500 }); } diff --git a/packages/analytics/src/utils.ts b/packages/analytics/src/utils.ts index d49e6aa0..d562793e 100644 --- a/packages/analytics/src/utils.ts +++ b/packages/analytics/src/utils.ts @@ -1,23 +1,17 @@ // Helper function that ensures that a value is an Error export function ensureError(value: unknown): Error { - if (!value) { - return new Error("No value was thrown"); - } + if (!value) return new Error("No value was thrown"); - if (value instanceof Error) { - return value; - } + if (value instanceof Error) return value; // Test if value inherits from Error - if (Object.prototype.isPrototypeOf.call(value, Error)) { - return value as Error & typeof value; - } + if (Object.prototype.isPrototypeOf.call(value, Error)) return value as Error & typeof value; let stringified = "[Unable to stringify the thrown value]"; try { stringified = JSON.stringify(value); } catch (e) { - // Do nothing + console.error(e); } const error = new Error(`This value was thrown as is, not through an Error: ${stringified}`); diff --git a/packages/art/src/BackgroundBlobs/BackgroundBlobs.tsx b/packages/art/src/BackgroundBlobs/BackgroundBlobs.tsx index 59144ba9..f8b8eabe 100644 --- a/packages/art/src/BackgroundBlobs/BackgroundBlobs.tsx +++ b/packages/art/src/BackgroundBlobs/BackgroundBlobs.tsx @@ -1,6 +1,6 @@ "use client"; -import { svgPath } from "blobs/v2"; +import * as blobs2 from "blobs/v2"; import { interpolatePath } from "d3-interpolate-path"; import { memo, useMemo } from "react"; import Canvas from "./Canvas"; @@ -32,7 +32,7 @@ const gradients = [ const DEFAULT_SPEED_FACTOR = 1; -class NcBlob { +class NCBlob { layer: 1 | 2 | 3; speed: number; angle: number; @@ -168,14 +168,14 @@ class NcBlob { this.positionY = randomInt(0 - this.size / 2, this.canvasHeight - this.size / 2); // Create two random shapes to interpolate between for visual variation - this.shape = svgPath({ + this.shape = blobs2.svgPath({ seed: Math.random(), extraPoints: 6, randomness: 6, size: this.size, }); - this.shape2 = svgPath({ + this.shape2 = blobs2.svgPath({ seed: Math.random(), extraPoints: 8, randomness: 8, @@ -200,9 +200,7 @@ class NcBlob { this.initialize(ctx); } - if (!this.interpolator) { - return; - } + if (!this.interpolator) return; if (!this.gradient?.[0] || !this.gradient[1]) { return; @@ -249,9 +247,9 @@ const BackgroundBlobs = memo( }: BackgroundBlobsProps) => { const blobs = useMemo( () => [ - new Array(large).fill(null).map(() => new NcBlob(3, speedFactor)), - new Array(medium).fill(null).map(() => new NcBlob(2, speedFactor)), - new Array(small).fill(null).map(() => new NcBlob(1, speedFactor)), + new Array(large).fill(null).map(() => new NCBlob(3, speedFactor)), + new Array(medium).fill(null).map(() => new NCBlob(2, speedFactor)), + new Array(small).fill(null).map(() => new NCBlob(1, speedFactor)), ], [large, medium, small, speedFactor], ); diff --git a/packages/shared-consts/src/index.ts b/packages/shared-consts/src/index.ts new file mode 100644 index 00000000..15bd12e4 --- /dev/null +++ b/packages/shared-consts/src/index.ts @@ -0,0 +1,10 @@ +export * from "./assets"; +export * from "./codebook"; +export * from "./colors"; +export * from "./controls"; +export * from "./export-process"; +export * from "./network"; +export * from "./protocol"; +export * from "./session"; +export * from "./stages"; +export * from "./variables"; diff --git a/packages/ui/src/Alert.tsx b/packages/ui/src/Alert.tsx index 7590757c..5fff669c 100644 --- a/packages/ui/src/Alert.tsx +++ b/packages/ui/src/Alert.tsx @@ -43,4 +43,4 @@ const AlertDescription = React.forwardRef import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; +import * as React from "react"; import type { VariantProps } from "class-variance-authority"; -import { forwardRef, type ComponentPropsWithoutRef, type ElementRef, type HTMLAttributes } from "react"; import { buttonVariants } from "./Button"; import { DialogDescription, DialogTitle } from "./dialog"; import { cn } from "./utils"; @@ -18,9 +17,9 @@ const AlertDialogPortal = ({ ...props }: AlertDialogPrimitive.AlertDialogPortalP ); AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName; -const AlertDialogOverlay = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( , - ComponentPropsWithoutRef +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( @@ -51,19 +50,19 @@ const AlertDialogContent = forwardRef< )); AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; -const AlertDialogHeader = ({ className, ...props }: HTMLAttributes) => ( +const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( ); AlertDialogHeader.displayName = "AlertDialogHeader"; -const AlertDialogFooter = ({ className, ...props }: HTMLAttributes) => ( +const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( ); AlertDialogFooter.displayName = "AlertDialogFooter"; -const AlertDialogAction = forwardRef< - ElementRef, - ComponentPropsWithoutRef & { +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { buttonVariant?: VariantProps["variant"]; } >(({ className, buttonVariant, ...props }, ref) => ( @@ -75,9 +74,9 @@ const AlertDialogAction = forwardRef< )); AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; -const AlertDialogCancel = forwardRef< - ElementRef, - ComponentPropsWithoutRef & { +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { buttonVariant?: VariantProps["variant"]; } >(({ className, buttonVariant, ...props }, ref) => ( @@ -95,12 +94,12 @@ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; export { AlertDialog, - AlertDialogAction, - AlertDialogCancel, + AlertDialogTrigger, AlertDialogContent, - DialogDescription as AlertDialogDescription, - AlertDialogFooter, AlertDialogHeader, + AlertDialogFooter, DialogTitle as AlertDialogTitle, - AlertDialogTrigger, + DialogDescription as AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, }; diff --git a/packages/ui/src/Button.tsx b/packages/ui/src/Button.tsx index 1a926e61..6be28a7f 100644 --- a/packages/ui/src/Button.tsx +++ b/packages/ui/src/Button.tsx @@ -1,8 +1,8 @@ import { Slot } from "@radix-ui/react-slot"; import type { VariantProps } from "class-variance-authority"; import { cva } from "class-variance-authority"; +import * as React from "react"; -import { type ButtonHTMLAttributes, forwardRef } from "react"; import { cn } from "./utils"; const baseButtonClasses = cn( @@ -50,9 +50,9 @@ export type ButtonProps = { variant?: VariantProps["variant"]; size?: VariantProps["size"]; asChild?: boolean; -} & ButtonHTMLAttributes; +} & React.ButtonHTMLAttributes; -const Button = forwardRef( +const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { const Comp = asChild ? Slot : "button"; return ; diff --git a/packages/ui/src/FancyBox.tsx b/packages/ui/src/FancyBox.tsx index 146677f3..d5bdf9ea 100644 --- a/packages/ui/src/FancyBox.tsx +++ b/packages/ui/src/FancyBox.tsx @@ -51,16 +51,10 @@ export default function FancyBox { - if (value.length === 0) { - return placeholder; - } - if (value.length === items.length) { - return `All ${plural} Selected (${items.length})`; - } + if (value.length === 0) return placeholder; + if (value.length === items.length) return `All ${plural} Selected (${items.length})`; - if (value.length === 1) { - return `1 ${singular} Selected`; - } + if (value.length === 1) return `1 ${singular} Selected`; return `${value.length} ${plural} Selected`; }, [value, items, placeholder, plural, singular]); @@ -68,7 +62,7 @@ export default function FancyBox - + - + {showSearch && ( + {formattedDate} ); diff --git a/packages/ui/src/Input.tsx b/packages/ui/src/Input.tsx index e4371414..5b5987bd 100644 --- a/packages/ui/src/Input.tsx +++ b/packages/ui/src/Input.tsx @@ -44,7 +44,7 @@ const Input = React.forwardRef( return ( {label && ( - + {label} )} diff --git a/packages/ui/src/accordion.tsx b/packages/ui/src/accordion.tsx index 29efcbc2..6908f515 100644 --- a/packages/ui/src/accordion.tsx +++ b/packages/ui/src/accordion.tsx @@ -51,4 +51,4 @@ const AccordionContent = React.forwardRef< AccordionContent.displayName = AccordionPrimitive.Content.displayName; -export { Accordion, AccordionContent, AccordionItem, AccordionTrigger }; +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/packages/ui/src/card.tsx b/packages/ui/src/card.tsx index 44a51786..c8085175 100644 --- a/packages/ui/src/card.tsx +++ b/packages/ui/src/card.tsx @@ -39,4 +39,4 @@ const CardFooter = React.forwardRef(({ className, children, ...props }, ref) => ( - + {children} @@ -101,11 +101,11 @@ DialogClose.displayName = DialogPrimitive.Title.displayName; export { Dialog, - DialogClose, + DialogTrigger, DialogContent, - DialogDescription, - DialogFooter, DialogHeader, + DialogFooter, DialogTitle, - DialogTrigger, + DialogDescription, + DialogClose, }; diff --git a/packages/ui/src/dropdown-menu.tsx b/packages/ui/src/dropdown-menu.tsx index 74d799ef..9701bc04 100644 --- a/packages/ui/src/dropdown-menu.tsx +++ b/packages/ui/src/dropdown-menu.tsx @@ -164,18 +164,18 @@ DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; export { DropdownMenu, - DropdownMenuCheckboxItem, + DropdownMenuTrigger, DropdownMenuContent, - DropdownMenuGroup, DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuPortal, - DropdownMenuRadioGroup, + DropdownMenuCheckboxItem, DropdownMenuRadioItem, + DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, - DropdownMenuTrigger, + DropdownMenuRadioGroup, }; diff --git a/packages/ui/src/form.tsx b/packages/ui/src/form.tsx index aecc5b9d..804d13c1 100644 --- a/packages/ui/src/form.tsx +++ b/packages/ui/src/form.tsx @@ -85,7 +85,7 @@ const FormLabel = React.forwardRef< >(({ className, ...props }, ref) => { const { error, formItemId } = useFormField(); - return ; + return ; }); FormLabel.displayName = "FormLabel"; @@ -97,7 +97,7 @@ const FormControl = React.forwardRef, React.Compon @@ -135,4 +135,4 @@ const FormMessage = React.forwardRef(({ className, children, ...props }, ref) => ( {children} - + @@ -109,4 +109,4 @@ const SelectSeparator = React.forwardRef< )); SelectSeparator.displayName = SelectPrimitive.Separator.displayName; -export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue }; +export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator }; diff --git a/packages/ui/src/sheet.tsx b/packages/ui/src/sheet.tsx index 4b1e307a..f8c265e5 100644 --- a/packages/ui/src/sheet.tsx +++ b/packages/ui/src/sheet.tsx @@ -97,13 +97,13 @@ SheetDescription.displayName = SheetPrimitive.Description.displayName; export { Sheet, + SheetPortal, + SheetOverlay, + SheetTrigger, SheetClose, SheetContent, - SheetDescription, - SheetFooter, SheetHeader, - SheetOverlay, - SheetPortal, + SheetFooter, SheetTitle, - SheetTrigger, + SheetDescription, }; diff --git a/packages/ui/src/table.tsx b/packages/ui/src/table.tsx index d0f421a2..3f8d7c66 100644 --- a/packages/ui/src/table.tsx +++ b/packages/ui/src/table.tsx @@ -72,4 +72,4 @@ const TableCaption = React.forwardRef - + diff --git a/packages/ui/src/toast.tsx b/packages/ui/src/toast.tsx index 4bc11941..0b7d90bb 100644 --- a/packages/ui/src/toast.tsx +++ b/packages/ui/src/toast.tsx @@ -1,16 +1,15 @@ -// biome-ignore lint/style/noNamespaceImport: radix import * as ToastPrimitives from "@radix-ui/react-toast"; -import { cva, type VariantProps } from "class-variance-authority"; +import { type VariantProps, cva } from "class-variance-authority"; import { X } from "lucide-react"; -import { type ComponentPropsWithoutRef, type ElementRef, forwardRef, type ReactElement } from "react"; +import * as React from "react"; import Heading from "./typography/Heading"; import { cn } from "./utils"; const ToastProvider = ToastPrimitives.Provider; -const ToastViewport = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const ToastViewport = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( , - ComponentPropsWithoutRef & VariantProps +const Toast = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & VariantProps >(({ className, variant, ...props }, ref) => { return ; }); Toast.displayName = ToastPrimitives.Root.displayName; -const ToastAction = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const ToastAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( , - ComponentPropsWithoutRef +const ToastClose = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( , - ComponentPropsWithoutRef +const ToastTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); ToastTitle.displayName = ToastPrimitives.Title.displayName; -const ToastDescription = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const ToastDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); ToastDescription.displayName = ToastPrimitives.Description.displayName; -type ToastProps = ComponentPropsWithoutRef; +type ToastProps = React.ComponentPropsWithoutRef; -type ToastActionElement = ReactElement; +type ToastActionElement = React.ReactElement; export { - Toast, - ToastAction, - ToastClose, - ToastDescription, + type ToastProps, + type ToastActionElement, ToastProvider, - ToastTitle, ToastViewport, - type ToastActionElement, - type ToastProps, + Toast, + ToastTitle, + ToastDescription, + ToastClose, + ToastAction, }; diff --git a/packages/ui/src/tooltip.tsx b/packages/ui/src/tooltip.tsx index f9fd09b5..877b4ae2 100644 --- a/packages/ui/src/tooltip.tsx +++ b/packages/ui/src/tooltip.tsx @@ -1,8 +1,7 @@ "use client"; -// biome-ignore lint/style/noNamespaceImport: radix import * as TooltipPrimitive from "@radix-ui/react-tooltip"; -import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from "react"; +import * as React from "react"; import { cn } from "./utils"; const TooltipProvider = TooltipPrimitive.Provider; @@ -11,9 +10,9 @@ const Tooltip = TooltipPrimitive.Root; const TooltipTrigger = TooltipPrimitive.Trigger; -const TooltipContent = forwardRef< - ElementRef, - ComponentPropsWithoutRef +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( { ), }; } - case "REMOVE_TOAST": { + case "REMOVE_TOAST": if (action.toastId === undefined) { return { ...state, @@ -118,10 +120,6 @@ export const reducer = (state: State, action: Action): State => { ...state, toasts: state.toasts.filter((t) => t.id !== action.toastId), }; - } - - default: - return state; } }; @@ -155,9 +153,7 @@ function toast({ ...props }: Toast) { id, open: true, onOpenChange: (open) => { - if (!open) { - dismiss(); - } + if (!open) dismiss(); }, }, }); @@ -170,10 +166,10 @@ function toast({ ...props }: Toast) { } function useToast() { - const [state, setState] = useState(memoryState); + const [state, setState] = React.useState(memoryState); // biome-ignore lint/correctness/useExhaustiveDependencies: state is a reference, so it's fine - useEffect(() => { + React.useEffect(() => { listeners.push(setState); return () => { const index = listeners.indexOf(setState); @@ -190,4 +186,4 @@ function useToast() { }; } -export { toast, useToast }; +export { useToast, toast }; diff --git a/tooling/tailwind/base.ts b/tooling/tailwind/base.ts index 4ee95b6f..74a89ddd 100644 --- a/tooling/tailwind/base.ts +++ b/tooling/tailwind/base.ts @@ -1,6 +1,5 @@ import type { Config } from "tailwindcss"; -// biome-ignore lint/style/noDefaultExport: export default { darkMode: ["class"], content: ["./components/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", "./src/**/*.{ts,tsx}"],