svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground ${variants[variant]} ${className}`}
+ {...props}
+ />
+ )
+})
+Alert.displayName = "Alert"
+
+const AlertDescription = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+AlertDescription.displayName = "AlertDescription"
+
+export { Alert, AlertDescription }
\ No newline at end of file
diff --git a/web/src/components/ui/button.jsx b/web/src/components/ui/button.jsx
new file mode 100644
index 0000000..9fe64d0
--- /dev/null
+++ b/web/src/components/ui/button.jsx
@@ -0,0 +1,36 @@
+import * as React from "react"
+
+const Button = React.forwardRef(({
+ className = "",
+ variant = "default",
+ size = "default",
+ disabled = false,
+ ...props
+}, ref) => {
+ const baseStyles = "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
+
+ const variants = {
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground"
+ }
+
+ const sizes = {
+ default: "h-10 px-4 py-2",
+ sm: "h-9 rounded-md px-3",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-10 w-10"
+ }
+
+ return (
+
+ )
+})
+Button.displayName = "Button"
+
+export { Button }
\ No newline at end of file
diff --git a/web/src/components/ui/card.jsx b/web/src/components/ui/card.jsx
new file mode 100644
index 0000000..b2d2d16
--- /dev/null
+++ b/web/src/components/ui/card.jsx
@@ -0,0 +1,35 @@
+import * as React from "react"
+
+const Card = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+Card.displayName = "Card"
+
+const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+CardHeader.displayName = "CardHeader"
+
+const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+CardTitle.displayName = "CardTitle"
+
+const CardContent = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+CardContent.displayName = "CardContent"
+
+export { Card, CardHeader, CardTitle, CardContent }
\ No newline at end of file
diff --git a/web/src/components/ui/input.jsx b/web/src/components/ui/input.jsx
new file mode 100644
index 0000000..5c80894
--- /dev/null
+++ b/web/src/components/ui/input.jsx
@@ -0,0 +1,15 @@
+import * as React from "react"
+
+const Input = React.forwardRef(({ className, type, ...props }, ref) => {
+ return (
+
+ )
+})
+Input.displayName = "Input"
+
+export { Input }
\ No newline at end of file
diff --git a/web/src/components/ui/scroll-area.jsx b/web/src/components/ui/scroll-area.jsx
new file mode 100644
index 0000000..4f17a54
--- /dev/null
+++ b/web/src/components/ui/scroll-area.jsx
@@ -0,0 +1,29 @@
+import * as React from "react"
+import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
+
+const ScrollArea = React.forwardRef(({ className, children, ...props }, ref) => (
+
+
+ {children}
+
+
+
+
+
+
+
+
+))
+ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
+
+export { ScrollArea }
\ No newline at end of file
diff --git a/web/src/components/ui/tabs.jsx b/web/src/components/ui/tabs.jsx
new file mode 100644
index 0000000..89f92b5
--- /dev/null
+++ b/web/src/components/ui/tabs.jsx
@@ -0,0 +1,33 @@
+import * as React from "react"
+import * as TabsPrimitive from "@radix-ui/react-tabs"
+
+const Tabs = TabsPrimitive.Root
+
+const TabsList = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+TabsList.displayName = TabsPrimitive.List.displayName
+
+const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
+
+const TabsContent = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+TabsContent.displayName = TabsPrimitive.Content.displayName
+
+export { Tabs, TabsList, TabsTrigger, TabsContent }
\ No newline at end of file
diff --git a/web/src/components/ui/textarea.jsx b/web/src/components/ui/textarea.jsx
new file mode 100644
index 0000000..257ac8b
--- /dev/null
+++ b/web/src/components/ui/textarea.jsx
@@ -0,0 +1,14 @@
+import * as React from "react"
+
+const Textarea = React.forwardRef(({ className, ...props }, ref) => {
+ return (
+
+ )
+})
+Textarea.displayName = "Textarea"
+
+export { Textarea }
\ No newline at end of file
diff --git a/web/src/index.css b/web/src/index.css
new file mode 100644
index 0000000..8756161
--- /dev/null
+++ b/web/src/index.css
@@ -0,0 +1,46 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 222.2 84% 4.9%;
+
+ --card: 0 0% 100%;
+ --card-foreground: 222.2 84% 4.9%;
+
+ --popover: 0 0% 100%;
+ --popover-foreground: 222.2 84% 4.9%;
+
+ --primary: 222.2 47.4% 11.2%;
+ --primary-foreground: 210 40% 98%;
+
+ --secondary: 210 40% 96.1%;
+ --secondary-foreground: 222.2 47.4% 11.2%;
+
+ --muted: 210 40% 96.1%;
+ --muted-foreground: 215.4 16.3% 46.9%;
+
+ --accent: 210 40% 96.1%;
+ --accent-foreground: 222.2 47.4% 11.2%;
+
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 210 40% 98%;
+
+ --border: 214.3 31.8% 91.4%;
+ --input: 214.3 31.8% 91.4%;
+ --ring: 222.2 84% 4.9%;
+
+ --radius: 0.5rem;
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
\ No newline at end of file
diff --git a/web/src/index.jsx b/web/src/index.jsx
index 563acd8..54ef0fd 100644
--- a/web/src/index.jsx
+++ b/web/src/index.jsx
@@ -1,9 +1,10 @@
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import App from './components/App'
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './components/App';
+import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
-)
\ No newline at end of file
+);
\ No newline at end of file
diff --git a/web/src/utils/calculator.js b/web/src/utils/calculator.js
deleted file mode 100644
index 9464067..0000000
--- a/web/src/utils/calculator.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export const add = (a, b) => a + b
-export const subtract = (a, b) => a - b
-export const multiply = (a, b) => a * b
-export const divide = (a, b) => {
- if (b === 0) throw new Error('Division by zero')
- return a / b
-}
\ No newline at end of file
diff --git a/web/src/utils/calculator.test.js b/web/src/utils/calculator.test.js
deleted file mode 100644
index 3192f2a..0000000
--- a/web/src/utils/calculator.test.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// calculator.test.js
-import { add, subtract, multiply, divide } from './calculator.js' // Note the .js extension
-
-describe('Calculator', () => {
- describe('add', () => {
- it('adds two numbers correctly', () => {
- expect(add(2, 3)).toBe(5)
- })
- })
-
- describe('divide', () => {
- it('throws error on division by zero', () => {
- expect(() => divide(1, 0)).toThrow('Division by zero')
- })
- })
-})
\ No newline at end of file
diff --git a/web/tailwind.config.js b/web/tailwind.config.js
new file mode 100644
index 0000000..b878bd1
--- /dev/null
+++ b/web/tailwind.config.js
@@ -0,0 +1,67 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ darkMode: ["class"],
+ content: ["./src/**/*.{js,jsx}"],
+ theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
+ },
+ extend: {
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ keyframes: {
+ "accordion-down": {
+ from: { height: 0 },
+ to: { height: "var(--radix-accordion-content-height)" },
+ },
+ "accordion-up": {
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: 0 },
+ },
+ },
+ animation: {
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ },
+ },
+ },
+ plugins: [require("tailwindcss-animate")],
+}
\ No newline at end of file
diff --git a/web/vite.config.js b/web/vite.config.js
index 048bfae..8c66c0f 100644
--- a/web/vite.config.js
+++ b/web/vite.config.js
@@ -1,11 +1,19 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import path from 'path';
export default defineConfig({
plugins: [react()],
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, './src'),
+ 'components': path.resolve(__dirname, './src/components')
+ },
+ extensions: ['.js', '.jsx']
+ },
build: {
outDir: 'dist',
assetsDir: 'assets',
base: '/'
}
-})
+});
\ No newline at end of file