diff --git a/heat-stack/app/components/ui/README.md b/heat-stack/app/components/ui/README.md index 433847df..1ad189cb 100644 --- a/heat-stack/app/components/ui/README.md +++ b/heat-stack/app/components/ui/README.md @@ -4,4 +4,4 @@ Some components in this directory are downloaded via the [shadcn/ui](https://ui.shadcn.com) [CLI](https://ui.shadcn.com/docs/cli). Feel free to customize them to your needs. It's important to know that shadcn/ui is not a library of components you install, but instead it's a registry of prebuilt -components which you can download and customize. +components which you can download and customize. \ No newline at end of file diff --git a/heat-stack/app/components/ui/checkbox.tsx b/heat-stack/app/components/ui/checkbox.tsx index 902fb648..298447c9 100644 --- a/heat-stack/app/components/ui/checkbox.tsx +++ b/heat-stack/app/components/ui/checkbox.tsx @@ -4,6 +4,13 @@ import { Check } from 'lucide-react' import { cn } from '#app/utils/misc.tsx' +export type CheckboxProps = Omit< + React.ComponentPropsWithoutRef, + 'type' +> & { + type?: string +} + const Checkbox = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef @@ -20,6 +27,14 @@ const Checkbox = React.forwardRef< className={cn('flex items-center justify-center text-current')} > + {/* + + */} )) diff --git a/heat-stack/app/root.tsx b/heat-stack/app/root.tsx index 65010781..49246039 100644 --- a/heat-stack/app/root.tsx +++ b/heat-stack/app/root.tsx @@ -1,497 +1,56 @@ -import { useForm } from '@conform-to/react' -import { parse } from '@conform-to/zod' import { cssBundleHref } from '@remix-run/css-bundle' -import { - json, - type DataFunctionArgs, - type HeadersFunction, - type LinksFunction, - type MetaFunction, -} from '@remix-run/node' -import { - Form, - Link, - Links, - LiveReload, - Meta, - Outlet, - Scripts, - ScrollRestoration, - useFetcher, - useFetchers, - useLoaderData, - useMatches, - useSubmit, -} from '@remix-run/react' -import { withSentry } from '@sentry/remix' -import { Suspense, lazy, useEffect, useRef, useState } from 'react' -import { object, z } from 'zod' -import { Confetti } from './components/confetti.tsx' -import { GeneralErrorBoundary } from './components/error-boundary.tsx' -import { ErrorList } from './components/forms.tsx' -import { SearchBar } from './components/search-bar.tsx' -import { EpicToaster } from './components/toaster.tsx' -import { Button } from './components/ui/button.tsx' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuPortal, - DropdownMenuTrigger, -} from './components/ui/dropdown-menu.tsx' -import { Icon, href as iconsHref } from './components/ui/icon.tsx' import fontStyleSheetUrl from './styles/font.css' import tailwindStyleSheetUrl from './styles/tailwind.css' -import { authenticator, getUserId } from './utils/auth.server.ts' -import { ClientHintCheck, getHints, useHints } from './utils/client-hints.tsx' -import { getConfetti } from './utils/confetti.server.ts' -import { prisma } from './utils/db.server.ts' -import { getEnv } from './utils/env.server.ts' -import { - combineHeaders, - getDomainUrl, - getUserImgSrc, - invariantResponse, -} from './utils/misc.tsx' -import { useNonce } from './utils/nonce-provider.ts' -import { useRequestInfo } from './utils/request-info.ts' -import { type Theme, setTheme, getTheme } from './utils/theme.server.ts' -import { makeTimings, time } from './utils/timing.server.ts' -import { getToast } from './utils/toast.server.ts' -import { useOptionalUser, useUser } from './utils/user.ts' +import { Links } from '@remix-run/react' +import { href as iconsHref } from './components/ui/icon.tsx' +import { type LinksFunction } from '@remix-run/node' -import { WeatherExample } from './components/WeatherExample.tsx' import { CaseSummary } from './components/CaseSummary.tsx' -import type { Weather } from './WeatherExample.d.ts' - -import * as pyodideModule from 'pyodide' -import engine from '../../rules-engine/src/rules_engine/engine.py' - import './App.css' -const getPyodide = async () => { - // public folder: - return await pyodideModule.loadPyodide({ - indexURL: 'pyodide-env/', - }) -} - -const runPythonScript = async () => { - const pyodide: any = await getPyodide() - // console.log(engine); - await pyodide.loadPackage('numpy') - await pyodide.runPythonAsync(engine) - return pyodide -} - export const links: LinksFunction = () => { - return [ - // Preload svg sprite as a resource to avoid render blocking - { rel: 'preload', href: iconsHref, as: 'image' }, - // Preload CSS as a resource to avoid render blocking - { rel: 'preload', href: fontStyleSheetUrl, as: 'style' }, - { rel: 'preload', href: tailwindStyleSheetUrl, as: 'style' }, - cssBundleHref ? { rel: 'preload', href: cssBundleHref, as: 'style' } : null, - { rel: 'mask-icon', href: '/favicons/mask-icon.svg' }, - { - rel: 'alternate icon', - type: 'image/png', - href: '/favicons/favicon-32x32.png', - }, - { rel: 'apple-touch-icon', href: '/favicons/apple-touch-icon.png' }, - { - rel: 'manifest', - href: '/site.webmanifest', - crossOrigin: 'use-credentials', - } as const, // necessary to make typescript happy - //These should match the css preloads above to avoid css as render blocking resource - { rel: 'icon', type: 'image/svg+xml', href: '/favicons/favicon.svg' }, - { rel: 'stylesheet', href: fontStyleSheetUrl }, - { rel: 'stylesheet', href: tailwindStyleSheetUrl }, - cssBundleHref ? { rel: 'stylesheet', href: cssBundleHref } : null, - ].filter(Boolean) -} - -export const meta: MetaFunction = ({ data }) => { - return [ - { title: data ? 'Epic Notes' : 'Error | Epic Notes' }, - { name: 'description', content: `Your own captain's log` }, - ] -} - -// We can only have one `loader()`. More requires special gymnastics. -export async function loader({ request }: DataFunctionArgs) { - const timings = makeTimings('root loader') - const userId = await time(() => getUserId(request), { - timings, - type: 'getUserId', - desc: 'getUserId in root', - }) - - const user = userId - ? await time( - () => - prisma.user.findUniqueOrThrow({ - select: { - id: true, - name: true, - username: true, - image: { select: { id: true } }, - roles: { - select: { - name: true, - permissions: { - select: { entity: true, action: true, access: true }, - }, - }, - }, - }, - where: { id: userId }, - }), - { timings, type: 'find user', desc: 'find user in root' }, - ) - : null - if (userId && !user) { - console.info('something weird happened') - // something weird happened... The user is authenticated but we can't find - // them in the database. Maybe they were deleted? Let's log them out. - await authenticator.logout(request, { redirectTo: '/' }) - } - const { toast, headers: toastHeaders } = await getToast(request) - const { confettiId, headers: confettiHeaders } = getConfetti(request) - - // Weather station data - const w_href: string = - 'https://archive-api.open-meteo.com/v1/archive?latitude=52.52&longitude=13.41&daily=temperature_2m_max&timezone=America%2FNew_York&start_date=2022-01-01&end_date=2023-08-30&temperature_unit=fahrenheit' - const w_res: Response = await fetch(w_href) - const weather: Weather = (await w_res.json()) as Weather - - return json( - { - weather: weather, - user, - requestInfo: { - hints: getHints(request), - origin: getDomainUrl(request), - path: new URL(request.url).pathname, - userPrefs: { - theme: getTheme(request), - }, - }, - ENV: getEnv(), - toast, - confettiId, - }, - { - headers: combineHeaders( - { 'Server-Timing': timings.toString() }, - toastHeaders, - confettiHeaders, - ), - }, - ) -} - -export const headers: HeadersFunction = ({ loaderHeaders }) => { - const headers = { - 'Server-Timing': loaderHeaders.get('Server-Timing') ?? '', - } - return headers -} - -const ThemeFormSchema = z.object({ - theme: z.enum(['system', 'light', 'dark']), -}) - -export async function action({ request }: DataFunctionArgs) { - const formData = await request.formData() - invariantResponse( - formData.get('intent') === 'update-theme', - 'Invalid intent', - { status: 400 }, - ) - const submission = parse(formData, { - schema: ThemeFormSchema, - }) - if (submission.intent !== 'submit') { - return json({ status: 'success', submission } as const) - } - if (!submission.value) { - return json({ status: 'error', submission } as const, { status: 400 }) - } - const { theme } = submission.value - - const responseInit = { - headers: { 'set-cookie': setTheme(theme) }, - } - return json({ success: true, submission }, responseInit) -} - -function Document({ - children, - nonce, - theme = 'light', - env = {}, -}: { - children: React.ReactNode - nonce: string - theme?: Theme - env?: Record -}) { - const [output, setOutput] = useState('(loading python...)') - - useEffect(() => { - const run = async () => { - const pyodide: any = await runPythonScript() - // console.log(pyodide); - const result = await pyodide.runPythonAsync('hdd(57, 60)') - setOutput(result) - } - run() - }, []) - return ( - - - - - - - - - - {/*
-
Output:
- {output} -
*/} - {/* */} - {children} -