From 1bae85ad2205570bcb7c051e58bd3245c35e02b6 Mon Sep 17 00:00:00 2001 From: dor-chaouat Date: Mon, 2 Feb 2026 14:50:16 +0200 Subject: [PATCH] add noted app example --- noted/.gitignore | 22 ++++ noted/.nvmrc | 1 + noted/README.md | 41 +++++++ noted/base44/agents/task_manager.jsonc | 11 ++ noted/base44/config.jsonc | 16 +++ noted/base44/entities/task.jsonc | 16 +++ noted/components.json | 16 +++ noted/index.html | 13 +++ noted/jsconfig.json | 13 +++ noted/package.json | 24 ++++ noted/postcss.config.js | 6 + noted/src/App.jsx | 148 +++++++++++++++++++++++++ noted/src/api/base44Client.js | 5 + noted/src/components/Base44Logo.jsx | 15 +++ noted/src/components/ui/button.jsx | 23 ++++ noted/src/components/ui/checkbox.jsx | 20 ++++ noted/src/components/ui/input.jsx | 13 +++ noted/src/index.css | 37 +++++++ noted/src/main.jsx | 6 + noted/tailwind.config.js | 41 +++++++ noted/vite.config.js | 12 ++ 21 files changed, 499 insertions(+) create mode 100644 noted/.gitignore create mode 100644 noted/.nvmrc create mode 100644 noted/README.md create mode 100644 noted/base44/agents/task_manager.jsonc create mode 100644 noted/base44/config.jsonc create mode 100644 noted/base44/entities/task.jsonc create mode 100644 noted/components.json create mode 100644 noted/index.html create mode 100644 noted/jsconfig.json create mode 100644 noted/package.json create mode 100644 noted/postcss.config.js create mode 100644 noted/src/App.jsx create mode 100644 noted/src/api/base44Client.js create mode 100644 noted/src/components/Base44Logo.jsx create mode 100644 noted/src/components/ui/button.jsx create mode 100644 noted/src/components/ui/checkbox.jsx create mode 100644 noted/src/components/ui/input.jsx create mode 100644 noted/src/index.css create mode 100644 noted/src/main.jsx create mode 100644 noted/tailwind.config.js create mode 100644 noted/vite.config.js diff --git a/noted/.gitignore b/noted/.gitignore new file mode 100644 index 0000000..959a7a6 --- /dev/null +++ b/noted/.gitignore @@ -0,0 +1,22 @@ +--- +outputFileName: .gitignore +--- +# Dependencies +node_modules + +# Build +dist + +# Environment +.env +.env.* +*.local + +# Editor +.vscode +.idea +.DS_Store +*.swp + +# Base44 App Config +.app.json* diff --git a/noted/.nvmrc b/noted/.nvmrc new file mode 100644 index 0000000..5767036 --- /dev/null +++ b/noted/.nvmrc @@ -0,0 +1 @@ +22.21.1 diff --git a/noted/README.md b/noted/README.md new file mode 100644 index 0000000..24edf86 --- /dev/null +++ b/noted/README.md @@ -0,0 +1,41 @@ +# Noted + +A simple todo list app built with React and Base44 backend. + +## Structure + +``` +base44/ # Backend configuration +├── config.jsonc # Project settings +└── entities/ # Data schemas + └── task.jsonc # Task entity + +src/ # Frontend code +├── App.jsx # Main todo app +├── api/ # Base44 client +├── components/ui/ # UI components +└── lib/ # Utilities +``` + +## Development + +```bash +npm install +npm run dev +``` + +## Commands + +| Command | Description | +|---------|-------------| +| `npm run dev` | Start dev server | +| `npm run build` | Build for production | +| `npm run preview` | Preview production build | + +## Base44 CLI + +```bash +base44 login # Authenticate +base44 entities push # Push entity schemas +base44 deploy # Deploy backend + hosting +``` diff --git a/noted/base44/agents/task_manager.jsonc b/noted/base44/agents/task_manager.jsonc new file mode 100644 index 0000000..35253c0 --- /dev/null +++ b/noted/base44/agents/task_manager.jsonc @@ -0,0 +1,11 @@ +{ + "name": "task_manager", + "description": "An AI agent that helps you manage and change your tasks", + "instructions": "You are a helpful task management assistant. You can help users create, update, mark as completed, and delete tasks using the entity tool. When a user asks to change a task, help them modify it by updating the appropriate fields. Always be conversational and helpful.", + "tool_configs": [ + { + "entity_name": "Task", + "allowed_operations": ["read", "create", "update", "delete"] + } + ] +} diff --git a/noted/base44/config.jsonc b/noted/base44/config.jsonc new file mode 100644 index 0000000..4a87a8d --- /dev/null +++ b/noted/base44/config.jsonc @@ -0,0 +1,16 @@ +// JSONC enables inline documentation and discoverability directly in config files. +// Commented-out properties show available options you can enable. + +{ + "name": "Noted", + "description": "A calm, no-nonsense to-do list for getting things out of your head and actually done.", + + // Site/hosting configuration + // Docs: https://docs.base44.com/configuration/hosting + "site": { + "installCommand": "npm install", + "buildCommand": "npm run build", + "serveCommand": "npm run dev", + "outputDirectory": "./dist" + } +} diff --git a/noted/base44/entities/task.jsonc b/noted/base44/entities/task.jsonc new file mode 100644 index 0000000..82b8256 --- /dev/null +++ b/noted/base44/entities/task.jsonc @@ -0,0 +1,16 @@ +{ + "name": "Task", + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Task title" + }, + "completed": { + "type": "boolean", + "default": false, + "description": "Whether the task is completed" + } + }, + "required": ["title"] +} diff --git a/noted/components.json b/noted/components.json new file mode 100644 index 0000000..068bddc --- /dev/null +++ b/noted/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": false, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "slate", + "cssVariables": true + }, + "aliases": { + "components": "@/components", + "ui": "@/components/ui" + } +} diff --git a/noted/index.html b/noted/index.html new file mode 100644 index 0000000..01d8353 --- /dev/null +++ b/noted/index.html @@ -0,0 +1,13 @@ + + + + + + + Todo App + + +
+ + + diff --git a/noted/jsconfig.json b/noted/jsconfig.json new file mode 100644 index 0000000..39ebe91 --- /dev/null +++ b/noted/jsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "jsx": "react-jsx", + "module": "esnext", + "moduleResolution": "bundler", + "target": "esnext" + }, + "include": ["src"] +} diff --git a/noted/package.json b/noted/package.json new file mode 100644 index 0000000..91b53df --- /dev/null +++ b/noted/package.json @@ -0,0 +1,24 @@ +{ + "name": "base44-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@base44/sdk": "^0.8.3", + "lucide-react": "^0.475.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "postcss": "^8.5.3", + "tailwindcss": "^3.4.17", + "vite": "^6.1.0" + } +} diff --git a/noted/postcss.config.js b/noted/postcss.config.js new file mode 100644 index 0000000..2aa7205 --- /dev/null +++ b/noted/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/noted/src/App.jsx b/noted/src/App.jsx new file mode 100644 index 0000000..7129644 --- /dev/null +++ b/noted/src/App.jsx @@ -0,0 +1,148 @@ +import { useState, useEffect } from "react"; +import { base44 } from "@/api/base44Client"; +import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Input } from "@/components/ui/input"; +import { Base44Logo } from "@/components/Base44Logo"; +import { Plus, Trash2, CheckCircle2 } from "lucide-react"; + +const Task = base44.entities.Task; + +export default function App() { + const [tasks, setTasks] = useState([]); + const [newTaskTitle, setNewTaskTitle] = useState(""); + const [isLoading, setIsLoading] = useState(true); + + const fetchTasks = async () => { + const data = await Task.list(); + setTasks(data); + setIsLoading(false); + }; + + useEffect(() => { + fetchTasks(); + }, []); + + const handleSubmit = async (e) => { + e.preventDefault(); + if (!newTaskTitle.trim()) return; + await Task.create({ title: newTaskTitle.trim(), completed: false }); + setNewTaskTitle(""); + fetchTasks(); + }; + + const toggleTask = async (id, completed) => { + await Task.update(id, { completed }); + fetchTasks(); + }; + + const deleteTask = async (id) => { + await Task.delete(id); + fetchTasks(); + }; + + const clearCompleted = async () => { + await Promise.all( + tasks.filter((t) => t.completed).map((t) => Task.delete(t.id)) + ); + fetchTasks(); + }; + + const completedCount = tasks.filter((t) => t.completed).length; + const totalCount = tasks.length; + + return ( +
+
+ {/* Header */} +
+

+ + + Base44 + Tasks + +

+ {totalCount > 0 && ( +

+ {completedCount} of {totalCount} completed +

+ )} +
+ + {/* Add Task Form */} +
+
+ setNewTaskTitle(e.target.value)} + placeholder="What needs to be done?" + className="flex-1 h-12 bg-white border-slate-200 rounded-xl shadow-sm" + /> + +
+
+ + {/* Task List */} +
+ {isLoading ? ( +
+
+
+ ) : tasks.length === 0 ? ( +
+

No tasks yet. Add one above!

+
+ ) : ( + tasks.map((task) => ( +
+ toggleTask(task.id, checked)} + className="w-5 h-5 rounded-md border-slate-300 data-[state=checked]:bg-orange-500 data-[state=checked]:border-orange-500" + /> + + {task.title} + + +
+ )) + )} +
+ + {/* Footer */} + {completedCount > 0 && ( +
+ +
+ )} +
+
+ ); +} diff --git a/noted/src/api/base44Client.js b/noted/src/api/base44Client.js new file mode 100644 index 0000000..9606ca2 --- /dev/null +++ b/noted/src/api/base44Client.js @@ -0,0 +1,5 @@ +import { createClient } from '@base44/sdk'; + +export const base44 = createClient({ + appId: import.meta.env.VITE_BASE44_APP_ID, +}); diff --git a/noted/src/components/Base44Logo.jsx b/noted/src/components/Base44Logo.jsx new file mode 100644 index 0000000..c80bf52 --- /dev/null +++ b/noted/src/components/Base44Logo.jsx @@ -0,0 +1,15 @@ +export function Base44Logo({ className = "w-8 h-8" }) { + return ( + + + + ); +} diff --git a/noted/src/components/ui/button.jsx b/noted/src/components/ui/button.jsx new file mode 100644 index 0000000..f6ee99b --- /dev/null +++ b/noted/src/components/ui/button.jsx @@ -0,0 +1,23 @@ +import { forwardRef } from 'react'; + +const Button = forwardRef(({ className = '', variant, size, ...props }, ref) => { + const baseStyles = 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50'; + + const variantStyles = variant === 'ghost' + ? 'hover:bg-slate-100' + : 'bg-slate-900 text-white shadow hover:bg-slate-800'; + + const sizeStyles = size === 'icon' ? 'h-9 w-9' : 'h-9 px-4 py-2'; + + return ( + +)); + +Checkbox.displayName = 'Checkbox'; + +export { Checkbox }; diff --git a/noted/src/components/ui/input.jsx b/noted/src/components/ui/input.jsx new file mode 100644 index 0000000..33b32d0 --- /dev/null +++ b/noted/src/components/ui/input.jsx @@ -0,0 +1,13 @@ +import { forwardRef } from 'react'; + +const Input = forwardRef(({ className = '', ...props }, ref) => ( + +)); + +Input.displayName = 'Input'; + +export { Input }; diff --git a/noted/src/index.css b/noted/src/index.css new file mode 100644 index 0000000..863c421 --- /dev/null +++ b/noted/src/index.css @@ -0,0 +1,37 @@ +@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 antialiased; + } +} diff --git a/noted/src/main.jsx b/noted/src/main.jsx new file mode 100644 index 0000000..f2bf72b --- /dev/null +++ b/noted/src/main.jsx @@ -0,0 +1,6 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from '@/App.jsx'; +import '@/index.css'; + +ReactDOM.createRoot(document.getElementById('root')).render(); diff --git a/noted/tailwind.config.js b/noted/tailwind.config.js new file mode 100644 index 0000000..d04fdc3 --- /dev/null +++ b/noted/tailwind.config.js @@ -0,0 +1,41 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./index.html', './src/**/*.{js,jsx}'], + theme: { + extend: { + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + colors: { + 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))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + }, + }, + }, + plugins: [], +}; diff --git a/noted/vite.config.js b/noted/vite.config.js new file mode 100644 index 0000000..95d423e --- /dev/null +++ b/noted/vite.config.js @@ -0,0 +1,12 @@ +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'), + }, + }, +});