From ab97e0857c2fbcdf9308e6f9c16d8f8754d03acc Mon Sep 17 00:00:00 2001 From: chaewon-huh Date: Mon, 24 Nov 2025 00:10:11 +0900 Subject: [PATCH 1/9] feat(cli): add @openai/apps-sdk-ui dependency to template creation - Add Apps SDK UI as dependency for list, carousel, and albums templates - Maintain existing template-specific dependencies (lucide-react, embla-carousel) - Keep default template minimal without additional dependencies - Prepare templates for migration to OpenAI's design system --- fastapps/cli/commands/create.py | 221 +++++++++++++++----------------- 1 file changed, 100 insertions(+), 121 deletions(-) diff --git a/fastapps/cli/commands/create.py b/fastapps/cli/commands/create.py index 875a109..bce4731 100644 --- a/fastapps/cli/commands/create.py +++ b/fastapps/cli/commands/create.py @@ -121,129 +121,108 @@ def create_widget(name: str, auth_type: str = None, scopes: list = None, templat dest_dir = widget_dir / item.name shutil.copytree(item, dest_dir, dirs_exist_ok=True) - # Install additional dependencies for templates - if template in ["list", "carousel", "albums"]: - console.print(f"\n[green][OK] Widget '{name}' created from '{template}' template![/green]") - - dep_name = {"list": "Tailwind CSS", "carousel": "Carousel", "albums": "Albums"}.get(template, "Template") - console.print(f"\n[cyan]Installing {dep_name} dependencies...[/cyan]") - - # Check if package.json exists - package_json_path = Path("package.json") - if package_json_path.exists(): - try: - # Read current package.json - with open(package_json_path, 'r') as f: - package_data = json.load(f) - - # Add Tailwind dependencies to devDependencies - if 'devDependencies' not in package_data: - package_data['devDependencies'] = {} - if 'dependencies' not in package_data: - package_data['dependencies'] = {} - - # Template-specific dependencies - if template == "list": - # Dev dependencies for list - template_dev_deps = { - "@tailwindcss/vite": "^4.1.11", - "autoprefixer": "^10.4.21", - "postcss": "^8.5.6", - "tailwindcss": "^4.1.11" - } - # Runtime dependencies for list - template_deps = { - "lucide-react": "^0.552.0" - } - elif template == "carousel": - # Dev dependencies for carousel - template_dev_deps = { - "@tailwindcss/vite": "^4.1.11", - "autoprefixer": "^10.4.21", - "postcss": "^8.5.6", - "tailwindcss": "^4.1.11" - } - # Runtime dependencies for carousel - template_deps = { - "lucide-react": "^0.552.0", - "embla-carousel-react": "^8.6.0" - } - elif template == "albums": - # Dev dependencies for albums - template_dev_deps = { - "@tailwindcss/vite": "^4.1.11", - "autoprefixer": "^10.4.21", - "postcss": "^8.5.6", - "tailwindcss": "^4.1.11" - } - # Runtime dependencies for albums - template_deps = { - "lucide-react": "^0.552.0", - "embla-carousel-react": "^8.6.0" - } - else: - template_dev_deps = {} - template_deps = {} - - # Check if dependencies already exist - deps_to_install = [] - for dep, version in template_dev_deps.items(): - if dep not in package_data['devDependencies']: - package_data['devDependencies'][dep] = version - deps_to_install.append(dep) - - for dep, version in template_deps.items(): - if dep not in package_data['dependencies']: - package_data['dependencies'][dep] = version - deps_to_install.append(dep) - - # Write updated package.json - if deps_to_install: - with open(package_json_path, 'w') as f: - json.dump(package_data, f, indent=2) - - dep_type = "template" if template else "Tailwind" - console.print(f"[cyan]Added {len(deps_to_install)} {dep_type} dependencies to package.json[/cyan]") - - # Run npm install - console.print("[cyan]Running npm install...[/cyan]") - try: - result = subprocess.run( - ["npm", "install"], - capture_output=True, - text=True, - check=True - ) - success_msg = f"{dep_name} dependencies" if template in ["list", "carousel", "albums"] else "Dependencies" - console.print(f"[green]✓ {success_msg} installed[/green]") - except subprocess.CalledProcessError as e: - console.print("[yellow]⚠ npm install failed. Run 'npm install' manually[/yellow]") - except FileNotFoundError: - console.print("[yellow]⚠ npm not found. Run 'npm install' manually[/yellow]") - else: - success_msg = f"{dep_name} dependencies" if template in ["list", "carousel", "albums"] else "Dependencies" - console.print(f"[green]✓ {success_msg} already installed[/green]") - - except Exception as e: - console.print(f"[yellow]⚠ Could not update package.json: {e}[/yellow]") - if template in ["carousel", "albums"]: - console.print(f"[yellow]Please install {template} dependencies manually:[/yellow]") - console.print("[dim] npm install embla-carousel-react lucide-react[/dim]") - console.print("[dim] npm install -D @tailwindcss/vite tailwindcss autoprefixer postcss[/dim]") - else: - console.print("[yellow]Please install Tailwind CSS manually:[/yellow]") - console.print("[dim] npm install -D @tailwindcss/vite tailwindcss autoprefixer postcss[/dim]") - else: - console.print("[yellow]⚠ package.json not found[/yellow]") - if template in ["carousel", "albums"]: - console.print(f"[yellow]Please install {template} dependencies manually:[/yellow]") - console.print("[dim] npm install embla-carousel-react lucide-react[/dim]") - console.print("[dim] npm install -D @tailwindcss/vite tailwindcss autoprefixer postcss[/dim]") + # Install dependencies for templates (Apps SDK UI + Tailwind + template extras) + console.print(f"\n[green][OK] Widget '{name}' created from '{template_name}' template![/green]") + + dep_name = {"list": "List", "carousel": "Carousel", "albums": "Albums"}.get(template_name, "Widget") + console.print(f"\n[cyan]Installing {dep_name} dependencies...[/cyan]") + + # Check if package.json exists + package_json_path = Path("package.json") + if package_json_path.exists(): + try: + # Read current package.json + with open(package_json_path, 'r') as f: + package_data = json.load(f) + + if 'devDependencies' not in package_data: + package_data['devDependencies'] = {} + if 'dependencies' not in package_data: + package_data['dependencies'] = {} + + # Base deps shared across templates (Apps SDK UI + Tailwind 4) + template_dev_deps = { + "@tailwindcss/vite": "^4.1.11", + "autoprefixer": "^10.4.21", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.11" + } + template_deps = { + "@openai/apps-sdk-ui": "^0.1.0" + } + + # Template-specific runtime deps + if template_name == "list": + template_deps.update({ + "lucide-react": "^0.552.0" + }) + elif template_name == "carousel": + template_deps.update({ + "lucide-react": "^0.552.0", + "embla-carousel-react": "^8.6.0" + }) + elif template_name == "albums": + template_deps.update({ + "lucide-react": "^0.552.0", + "embla-carousel-react": "^8.6.0" + }) + + # Check if dependencies already exist + deps_to_install = [] + for dep, version in template_dev_deps.items(): + if dep not in package_data['devDependencies']: + package_data['devDependencies'][dep] = version + deps_to_install.append(dep) + + for dep, version in template_deps.items(): + if dep not in package_data['dependencies']: + package_data['dependencies'][dep] = version + deps_to_install.append(dep) + + # Write updated package.json + if deps_to_install: + with open(package_json_path, 'w') as f: + json.dump(package_data, f, indent=2) + + console.print(f"[cyan]Added {len(deps_to_install)} dependencies to package.json[/cyan]") + + # Run npm install + console.print("[cyan]Running npm install...[/cyan]") + try: + result = subprocess.run( + ["npm", "install"], + capture_output=True, + text=True, + check=True + ) + console.print(f"[green]✓ {dep_name} dependencies installed[/green]") + except subprocess.CalledProcessError as e: + console.print("[yellow]⚠ npm install failed. Run 'npm install' manually[/yellow]") + except FileNotFoundError: + console.print("[yellow]⚠ npm not found. Run 'npm install' manually[/yellow]") else: - console.print("[yellow]Please install Tailwind CSS manually:[/yellow]") - console.print("[dim] npm install -D @tailwindcss/vite tailwindcss autoprefixer postcss[/dim]") + console.print(f"[green]✓ {dep_name} dependencies already installed[/green]") + + except Exception as e: + console.print(f"[yellow]⚠ Could not update package.json: {e}[/yellow]") + console.print("[yellow]Please install dependencies manually:[/yellow]") + manual_deps = ["@openai/apps-sdk-ui"] + if template_name in ["carousel", "albums"]: + manual_deps.extend(["embla-carousel-react", "lucide-react"]) + elif template_name == "list": + manual_deps.append("lucide-react") + console.print(f"[dim] npm install {' '.join(manual_deps)}[/dim]") + console.print("[dim] npm install -D @tailwindcss/vite tailwindcss autoprefixer postcss[/dim]") else: - console.print(f"\n[green][OK] Widget '{name}' created![/green]") + console.print("[yellow]⚠ package.json not found[/yellow]") + manual_deps = ["@openai/apps-sdk-ui"] + if template_name in ["carousel", "albums"]: + manual_deps.extend(["embla-carousel-react", "lucide-react"]) + elif template_name == "list": + manual_deps.append("lucide-react") + console.print("[yellow]Please install dependencies manually:[/yellow]") + console.print(f"[dim] npm install {' '.join(manual_deps)}[/dim]") + console.print("[dim] npm install -D @tailwindcss/vite tailwindcss autoprefixer postcss[/dim]") console.print("\n[green][OK] Widget created successfully![/green]") console.print("\n[cyan]Created files:[/cyan]") From 7eaa80b464197b7a23cf1c37e03d1f55ae92bafc Mon Sep 17 00:00:00 2001 From: chaewon-huh Date: Mon, 24 Nov 2025 00:12:21 +0900 Subject: [PATCH 2/9] chore: add apps-sdk-ui tailwind base to templates --- fastapps/templates/albums/widget/index.css | 43 ++------------------ fastapps/templates/carousel/widget/index.css | 43 ++------------------ fastapps/templates/default/widget/index.css | 3 ++ fastapps/templates/list/widget/index.css | 43 ++------------------ 4 files changed, 12 insertions(+), 120 deletions(-) create mode 100644 fastapps/templates/default/widget/index.css diff --git a/fastapps/templates/albums/widget/index.css b/fastapps/templates/albums/widget/index.css index 7b9c76c..a895ecb 100644 --- a/fastapps/templates/albums/widget/index.css +++ b/fastapps/templates/albums/widget/index.css @@ -1,40 +1,3 @@ -@import "tailwindcss" source("."); - -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer utilities { - .overflow-auto > *, - .overflow-scroll > *, - .overflow-x-auto > *, - .overflow-y-auto > * { - scrollbar-color: auto; - } - - /* Base style for scrollable elements */ - .overflow-auto, - .overflow-scroll, - .overflow-x-auto, - .overflow-y-auto, - .overflow-x-scroll, - .overflow-y-scroll { - scrollbar-color: rgb(0, 0, 0, 0.1) transparent; - - @media (prefers-color-scheme: dark) { - scrollbar-color: rgb(255, 255, 255, 0.1) transparent; - } - } - - /* Hover state directly on the scrollable element */ - .overflow-auto:hover, - .overflow-scroll:hover, - .overflow-x-auto:hover, - .overflow-y-auto:hover { - scrollbar-color: rgb(0, 0, 0, 0.2) transparent; - - @media (prefers-color-scheme: dark) { - scrollbar-color: rgb(255, 255, 255, 0.2) transparent; - } - } -} +@import "tailwindcss"; +@import "@openai/apps-sdk-ui/css"; +@source "../node_modules/@openai/apps-sdk-ui"; diff --git a/fastapps/templates/carousel/widget/index.css b/fastapps/templates/carousel/widget/index.css index 7b9c76c..a895ecb 100644 --- a/fastapps/templates/carousel/widget/index.css +++ b/fastapps/templates/carousel/widget/index.css @@ -1,40 +1,3 @@ -@import "tailwindcss" source("."); - -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer utilities { - .overflow-auto > *, - .overflow-scroll > *, - .overflow-x-auto > *, - .overflow-y-auto > * { - scrollbar-color: auto; - } - - /* Base style for scrollable elements */ - .overflow-auto, - .overflow-scroll, - .overflow-x-auto, - .overflow-y-auto, - .overflow-x-scroll, - .overflow-y-scroll { - scrollbar-color: rgb(0, 0, 0, 0.1) transparent; - - @media (prefers-color-scheme: dark) { - scrollbar-color: rgb(255, 255, 255, 0.1) transparent; - } - } - - /* Hover state directly on the scrollable element */ - .overflow-auto:hover, - .overflow-scroll:hover, - .overflow-x-auto:hover, - .overflow-y-auto:hover { - scrollbar-color: rgb(0, 0, 0, 0.2) transparent; - - @media (prefers-color-scheme: dark) { - scrollbar-color: rgb(255, 255, 255, 0.2) transparent; - } - } -} +@import "tailwindcss"; +@import "@openai/apps-sdk-ui/css"; +@source "../node_modules/@openai/apps-sdk-ui"; diff --git a/fastapps/templates/default/widget/index.css b/fastapps/templates/default/widget/index.css new file mode 100644 index 0000000..a895ecb --- /dev/null +++ b/fastapps/templates/default/widget/index.css @@ -0,0 +1,3 @@ +@import "tailwindcss"; +@import "@openai/apps-sdk-ui/css"; +@source "../node_modules/@openai/apps-sdk-ui"; diff --git a/fastapps/templates/list/widget/index.css b/fastapps/templates/list/widget/index.css index 7b9c76c..a895ecb 100644 --- a/fastapps/templates/list/widget/index.css +++ b/fastapps/templates/list/widget/index.css @@ -1,40 +1,3 @@ -@import "tailwindcss" source("."); - -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer utilities { - .overflow-auto > *, - .overflow-scroll > *, - .overflow-x-auto > *, - .overflow-y-auto > * { - scrollbar-color: auto; - } - - /* Base style for scrollable elements */ - .overflow-auto, - .overflow-scroll, - .overflow-x-auto, - .overflow-y-auto, - .overflow-x-scroll, - .overflow-y-scroll { - scrollbar-color: rgb(0, 0, 0, 0.1) transparent; - - @media (prefers-color-scheme: dark) { - scrollbar-color: rgb(255, 255, 255, 0.1) transparent; - } - } - - /* Hover state directly on the scrollable element */ - .overflow-auto:hover, - .overflow-scroll:hover, - .overflow-x-auto:hover, - .overflow-y-auto:hover { - scrollbar-color: rgb(0, 0, 0, 0.2) transparent; - - @media (prefers-color-scheme: dark) { - scrollbar-color: rgb(255, 255, 255, 0.2) transparent; - } - } -} +@import "tailwindcss"; +@import "@openai/apps-sdk-ui/css"; +@source "../node_modules/@openai/apps-sdk-ui"; From 3fa532af94026ebb7a93b6dc59e3049ccfe62249 Mon Sep 17 00:00:00 2001 From: chaewon-huh Date: Mon, 24 Nov 2025 00:20:29 +0900 Subject: [PATCH 3/9] fix: avoid duplicate albums component name --- fastapps/templates/albums/widget/index.jsx | 53 +++++++++++++--------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/fastapps/templates/albums/widget/index.jsx b/fastapps/templates/albums/widget/index.jsx index 3117db3..bb14117 100644 --- a/fastapps/templates/albums/widget/index.jsx +++ b/fastapps/templates/albums/widget/index.jsx @@ -1,4 +1,7 @@ import React from "react"; +import { AppsSDKUIProvider } from "@openai/apps-sdk-ui/components/AppsSDKUIProvider"; +import { Button } from "@openai/apps-sdk-ui/components/Button"; +import { EmptyMessage } from "@openai/apps-sdk-ui/components/EmptyMessage"; import { useWidgetProps, useMaxHeight, useOpenAiGlobal } from "fastapps"; import useEmblaCarousel from "embla-carousel-react"; import { ArrowLeft, ArrowRight } from "lucide-react"; @@ -39,9 +42,9 @@ function AlbumsCarousel({ albums, onSelect }) { if (!hasAlbums) { return (
-
+ No albums available. Provide up to 8 entries for best results. -
+
); } @@ -61,38 +64,38 @@ function AlbumsCarousel({ albums, onSelect }) { {canPrev && ( - +