46
47OpenTownie is built with:
48- React frontend with TypeScript
49- React Router
50- Hono API server backend
51- Web Audio API for sound notifications
1/** @jsxImportSource https://esm.sh/react@18.2.0?dev */
2import { useLocalStorage } from "https://esm.sh/react-use?dev&deps=react@18.2.0&react-dom@18.2.0";
3import React, { useEffect, useRef, useState } from "https://esm.sh/react@18.2.0?dev";
4import { RefreshIcon } from "./icons.tsx";
5
39 }, [messages, running, currentEndpoint, customPath]);
40
41 const handleEndpointChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
42 setSelectedEndpointIndex(Number(e.target.value));
43 };
44
45 const handlePathChange = (e: React.ChangeEvent<HTMLInputElement>) => {
46 setCustomPath(e.target.value);
47 };
1/** @jsxImportSource https://esm.sh/react@18.2.0?dev */
2import { useEffect, useState } from "https://esm.sh/react@18.2.0?dev";
3
4const formatTime = (ms: number): string => {
1/** @jsxImportSource https://esm.sh/react@18.2.0?dev */
2import React from "https://esm.sh/react@18.2.0?dev";
3import { Link } from "https://esm.sh/react-router@7?dev&deps=react@18.2.0&react-dom@18.2.0";
4import {
5 SquarePenIcon,
98 </p>
99 <ul>
100 <li>React frontend with TypeScript</li>
101 <li>Hono API server backend</li>
102 <li>Web Audio API for sound notifications</li>
1/** @jsxImportSource https://esm.sh/react@18.2.0?dev */
2import React, { useState, createContext } from "https://esm.sh/react@18.2.0?dev";
3import {
4 BrowserRouter,
9 Navigate,
10 useLocation,
11} from "https://esm.sh/react-router@7?dev&deps=react@18.2.0&react-dom@18.2.0";
12import { useLocalStorage } from "https://esm.sh/react-use?dev&deps=react@18.2.0&react-dom@18.2.0";
13import { LayoutRoute } from "./LayoutRoute.tsx";
14import { Home } from "./Home.tsx";
1import { useEffect } from "https://esm.sh/react@18.2.0?dev";
2
3export function useUsageStats (messages: any[], usages: any[]) {
1import { useEffect, useRef } from 'https://esm.sh/react@18.2.0?dev';
2
3
1import { useState, useEffect } from "https://esm.sh/react@18.2.0?dev";
2import { useAuth } from "./useAuth.tsx";
3
1import { useState, useEffect } from "https://esm.sh/react@18.2.0?dev";
2import { useAuth } from "./useAuth.tsx";
3
1import { useEffect } from "https://esm.sh/react@18.2.0?dev";
2
3function setLoadingFavicon() {