@base44-preview/cli 0.0.26-pr.172.6febf45 → 0.0.26-pr.174.9ce53d2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/templates/chrome-extension/.nvmrc +1 -0
  2. package/dist/templates/chrome-extension/README.md +90 -0
  3. package/dist/templates/chrome-extension/base44/agents/search_agent.jsonc +13 -0
  4. package/dist/templates/chrome-extension/base44/app.jsonc.ejs +9 -0
  5. package/dist/templates/chrome-extension/base44/config.jsonc.ejs +8 -0
  6. package/dist/templates/chrome-extension/base44/entities/bookmark.jsonc +41 -0
  7. package/dist/templates/chrome-extension/gitignore.ejs +25 -0
  8. package/dist/templates/chrome-extension/package.json +30 -0
  9. package/dist/templates/chrome-extension/postcss.config.js +6 -0
  10. package/dist/templates/chrome-extension/public/icon/README.md +12 -0
  11. package/dist/templates/chrome-extension/public/manifest.json +25 -0
  12. package/dist/templates/chrome-extension/tailwind.config.js +8 -0
  13. package/dist/templates/chrome-extension/tsconfig.json +31 -0
  14. package/dist/templates/chrome-extension/tsconfig.node.json +10 -0
  15. package/dist/templates/chrome-extension/wxt-src/components/BookmarkCard.tsx +83 -0
  16. package/dist/templates/chrome-extension/wxt-src/components/Button.tsx +36 -0
  17. package/dist/templates/chrome-extension/wxt-src/components/Input.tsx +12 -0
  18. package/dist/templates/chrome-extension/wxt-src/entrypoints/background.ts +19 -0
  19. package/dist/templates/chrome-extension/wxt-src/entrypoints/popup/App.tsx +186 -0
  20. package/dist/templates/chrome-extension/wxt-src/entrypoints/popup/index.html +12 -0
  21. package/dist/templates/chrome-extension/wxt-src/entrypoints/popup/main.tsx +10 -0
  22. package/dist/templates/chrome-extension/wxt-src/entrypoints/popup/style.css +21 -0
  23. package/dist/templates/chrome-extension/wxt-src/lib/base44Client.ts.ejs +5 -0
  24. package/dist/templates/chrome-extension/wxt.config.ts +7 -0
  25. package/dist/templates/templates.json +6 -0
  26. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ 20
@@ -0,0 +1,90 @@
1
+ # Chrome Bookmarks Extension
2
+
3
+ A Chrome extension for bookmarking websites with AI-powered search, built with WXT framework and Base44 backend.
4
+
5
+ ## Features
6
+
7
+ - **Save Bookmarks**: Save any website with a single click
8
+ - **View Bookmarks**: Browse your saved bookmarks in the popup
9
+ - **AI Search**: Search through your bookmarks using natural language
10
+ - **Base44 Backend**: Powered by Base44 for data storage and AI capabilities
11
+
12
+ ## Structure
13
+
14
+ ```
15
+ base44/ # Backend configuration
16
+ ├── config.jsonc # Project settings
17
+ ├── entities/ # Data schemas
18
+ │ └── bookmark.jsonc # Bookmark entity
19
+ └── agents/ # AI agents
20
+ └── search_agent.jsonc # Bookmark search agent
21
+
22
+ wxt-src/ # Extension source code
23
+ ├── entrypoints/
24
+ │ ├── background/ # Background service worker
25
+ │ ├── content/ # Content scripts
26
+ │ └── popup/ # Extension popup UI
27
+ └── components/ # Shared React components
28
+
29
+ public/ # Static assets
30
+ └── icon/ # Extension icons
31
+ ```
32
+
33
+ ## Development
34
+
35
+ ```bash
36
+ npm install
37
+ npm run dev
38
+ ```
39
+
40
+ This will start WXT in development mode with hot-reload enabled.
41
+
42
+ ## Commands
43
+
44
+ | Command | Description |
45
+ |---------|-------------|
46
+ | `npm run dev` | Start development mode (Chrome) |
47
+ | `npm run dev:firefox` | Start development mode (Firefox) |
48
+ | `npm run build` | Build for production (Chrome) |
49
+ | `npm run build:firefox` | Build for production (Firefox) |
50
+ | `npm run zip` | Create distribution zip (Chrome) |
51
+ | `npm run zip:firefox` | Create distribution zip (Firefox) |
52
+
53
+ ## Base44 Setup
54
+
55
+ ```bash
56
+ base44 login # Authenticate
57
+ base44 entities push # Push entity schemas
58
+ base44 agents push # Push AI agents
59
+ base44 deploy # Deploy backend
60
+ ```
61
+
62
+ ## Loading the Extension
63
+
64
+ ### Chrome
65
+ 1. Run `npm run build` to create the production build
66
+ 2. Open Chrome and navigate to `chrome://extensions/`
67
+ 3. Enable "Developer mode"
68
+ 4. Click "Load unpacked"
69
+ 5. Select the `.output/chrome-mv3` directory
70
+
71
+ ### Firefox
72
+ 1. Run `npm run build:firefox`
73
+ 2. Open Firefox and navigate to `about:debugging#/runtime/this-firefox`
74
+ 3. Click "Load Temporary Add-on"
75
+ 4. Select any file in the `.output/firefox-mv3` directory
76
+
77
+ ## Usage
78
+
79
+ 1. **Save a Bookmark**: Click the extension icon and press "Save Current Page"
80
+ 2. **View Bookmarks**: Open the popup to see your saved bookmarks
81
+ 3. **Search**: Use the search bar with natural language queries like "show me articles about React"
82
+ 4. **Delete**: Click the trash icon to remove a bookmark
83
+
84
+ ## Architecture
85
+
86
+ - **WXT Framework**: Modern web extension development framework with Vite
87
+ - **React**: UI components with hooks
88
+ - **Base44 SDK**: Backend integration for data storage
89
+ - **AI Agents**: Natural language search powered by Base44 agents
90
+ - **Tailwind CSS**: Utility-first styling
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "Bookmark Search Agent",
3
+ "description": "AI agent that helps users search through their bookmarks using natural language queries",
4
+ "instructions": "You are a helpful assistant that searches through a user's bookmarks. When a user asks a question or describes what they're looking for, search through their bookmarks and return the most relevant results. You can understand natural language queries like 'articles about React', 'bookmarks from last week', or 'tutorials I saved'.",
5
+ "tools": [
6
+ {
7
+ "type": "query",
8
+ "entity": "Bookmark",
9
+ "description": "Search and filter bookmarks"
10
+ }
11
+ ],
12
+ "model": "gpt-4-turbo-preview"
13
+ }
@@ -0,0 +1,9 @@
1
+ ---
2
+ outputFileName: .app.jsonc
3
+ ---
4
+ // Base44 App Configuration
5
+ // This file links your local project to your Base44 app.
6
+ // Do not commit this file to version control.
7
+ {
8
+ "id": "<%= projectId %>"
9
+ }
@@ -0,0 +1,8 @@
1
+ // Base44 Project Configuration
2
+ // JSONC enables inline documentation and discoverability directly in config files.
3
+ // Chrome extension template with WXT framework and Base44 backend.
4
+
5
+ {
6
+ "name": "<%= name %>"<% if (description) { %>,
7
+ "description": "<%= description %>"<% } %>
8
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "Bookmark",
3
+ "fields": {
4
+ "url": {
5
+ "type": "string",
6
+ "required": true,
7
+ "description": "The URL of the bookmarked page"
8
+ },
9
+ "title": {
10
+ "type": "string",
11
+ "required": true,
12
+ "description": "The title of the bookmarked page"
13
+ },
14
+ "description": {
15
+ "type": "string",
16
+ "description": "Optional description or notes about the bookmark"
17
+ },
18
+ "favicon": {
19
+ "type": "string",
20
+ "description": "URL to the site's favicon"
21
+ },
22
+ "tags": {
23
+ "type": "array",
24
+ "items": {
25
+ "type": "string"
26
+ },
27
+ "description": "Tags for categorizing bookmarks"
28
+ },
29
+ "createdAt": {
30
+ "type": "timestamp",
31
+ "autoCreate": true,
32
+ "description": "Timestamp when the bookmark was created"
33
+ }
34
+ },
35
+ "indexes": [
36
+ {
37
+ "fields": ["createdAt"],
38
+ "direction": "desc"
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,25 @@
1
+ ---
2
+ outputFileName: .gitignore
3
+ ---
4
+ # Dependencies
5
+ node_modules/
6
+
7
+ # Build outputs
8
+ .output/
9
+ .wxt/
10
+ dist/
11
+
12
+ # Environment
13
+ .env
14
+ .env.local
15
+ .app.jsonc
16
+
17
+ # OS
18
+ .DS_Store
19
+ Thumbs.db
20
+
21
+ # IDE
22
+ .vscode/
23
+ .idea/
24
+ *.swp
25
+ *.swo
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "chrome-bookmarks-extension",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "wxt",
8
+ "dev:firefox": "wxt -b firefox",
9
+ "build": "wxt build",
10
+ "build:firefox": "wxt build -b firefox",
11
+ "zip": "wxt zip",
12
+ "zip:firefox": "wxt zip -b firefox",
13
+ "postinstall": "wxt prepare"
14
+ },
15
+ "dependencies": {
16
+ "@base44/sdk": "^0.8.3",
17
+ "lucide-react": "^0.475.0",
18
+ "react": "^18.2.0",
19
+ "react-dom": "^18.2.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/react": "^18.2.79",
23
+ "@types/react-dom": "^18.2.25",
24
+ "@vitejs/plugin-react": "^4.3.4",
25
+ "autoprefixer": "^10.4.20",
26
+ "postcss": "^8.5.3",
27
+ "tailwindcss": "^3.4.17",
28
+ "wxt": "^0.19.0"
29
+ }
30
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -0,0 +1,12 @@
1
+ # Extension Icons
2
+
3
+ Place your extension icons here:
4
+
5
+ - `16.png` - 16x16 pixels (browser toolbar)
6
+ - `32.png` - 32x32 pixels (Windows)
7
+ - `48.png` - 48x48 pixels (extensions page)
8
+ - `128.png` - 128x128 pixels (Chrome Web Store)
9
+
10
+ You can use tools like [Figma](https://figma.com), [Canva](https://canva.com), or any image editor to create these icons.
11
+
12
+ For now, WXT will generate default icons if these are missing.
@@ -0,0 +1,25 @@
1
+ {
2
+ "manifest_version": 3,
3
+ "name": "Bookmark Manager",
4
+ "version": "1.0.0",
5
+ "description": "Save and search bookmarks with AI assistance",
6
+ "permissions": ["tabs", "storage"],
7
+ "action": {
8
+ "default_popup": "popup.html",
9
+ "default_icon": {
10
+ "16": "icon/16.png",
11
+ "32": "icon/32.png",
12
+ "48": "icon/48.png",
13
+ "128": "icon/128.png"
14
+ }
15
+ },
16
+ "icons": {
17
+ "16": "icon/16.png",
18
+ "32": "icon/32.png",
19
+ "48": "icon/48.png",
20
+ "128": "icon/128.png"
21
+ },
22
+ "background": {
23
+ "service_worker": "background.js"
24
+ }
25
+ }
@@ -0,0 +1,8 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ['./wxt-src/**/*.{js,jsx,ts,tsx,html}'],
4
+ theme: {
5
+ extend: {},
6
+ },
7
+ plugins: [],
8
+ };
@@ -0,0 +1,31 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+
23
+ /* Path aliases */
24
+ "baseUrl": ".",
25
+ "paths": {
26
+ "@/*": ["./wxt-src/*"]
27
+ }
28
+ },
29
+ "include": ["wxt-src"],
30
+ "references": [{ "path": "./tsconfig.node.json" }]
31
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true
8
+ },
9
+ "include": ["wxt.config.ts"]
10
+ }
@@ -0,0 +1,83 @@
1
+ import React from 'react';
2
+ import { ExternalLink, Trash2 } from 'lucide-react';
3
+ import { Button } from './Button';
4
+
5
+ interface Bookmark {
6
+ id: string;
7
+ url: string;
8
+ title: string;
9
+ favicon?: string;
10
+ description?: string;
11
+ createdAt?: string;
12
+ }
13
+
14
+ interface BookmarkCardProps {
15
+ bookmark: Bookmark;
16
+ onDelete: () => void;
17
+ }
18
+
19
+ export const BookmarkCard: React.FC<BookmarkCardProps> = ({ bookmark, onDelete }) => {
20
+ const handleClick = () => {
21
+ browser.tabs.create({ url: bookmark.url });
22
+ };
23
+
24
+ return (
25
+ <div className="group flex items-start gap-3 p-3 bg-white rounded-lg border border-slate-200 hover:shadow-md transition-all duration-200">
26
+ {/* Favicon */}
27
+ {bookmark.favicon ? (
28
+ <img
29
+ src={bookmark.favicon}
30
+ alt=""
31
+ className="w-5 h-5 mt-0.5 rounded"
32
+ onError={(e) => {
33
+ (e.target as HTMLImageElement).style.display = 'none';
34
+ }}
35
+ />
36
+ ) : (
37
+ <div className="w-5 h-5 mt-0.5 bg-slate-200 rounded" />
38
+ )}
39
+
40
+ {/* Content */}
41
+ <div className="flex-1 min-w-0">
42
+ <button
43
+ onClick={handleClick}
44
+ className="text-left w-full group/link"
45
+ >
46
+ <h3 className="text-sm font-medium text-slate-900 group-hover/link:text-blue-600 transition-colors line-clamp-1">
47
+ {bookmark.title}
48
+ </h3>
49
+ <p className="text-xs text-slate-500 line-clamp-1 mt-0.5">
50
+ {new URL(bookmark.url).hostname}
51
+ </p>
52
+ </button>
53
+ {bookmark.description && (
54
+ <p className="text-xs text-slate-600 mt-1 line-clamp-2">
55
+ {bookmark.description}
56
+ </p>
57
+ )}
58
+ </div>
59
+
60
+ {/* Actions */}
61
+ <div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
62
+ <Button
63
+ variant="ghost"
64
+ size="icon"
65
+ onClick={handleClick}
66
+ className="h-7 w-7 text-slate-400 hover:text-blue-600"
67
+ title="Open in new tab"
68
+ >
69
+ <ExternalLink className="w-3.5 h-3.5" />
70
+ </Button>
71
+ <Button
72
+ variant="ghost"
73
+ size="icon"
74
+ onClick={onDelete}
75
+ className="h-7 w-7 text-slate-400 hover:text-red-600 hover:bg-red-50"
76
+ title="Delete bookmark"
77
+ >
78
+ <Trash2 className="w-3.5 h-3.5" />
79
+ </Button>
80
+ </div>
81
+ </div>
82
+ );
83
+ };
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
+ variant?: 'default' | 'ghost';
5
+ size?: 'default' | 'sm' | 'icon';
6
+ }
7
+
8
+ export const Button: React.FC<ButtonProps> = ({
9
+ children,
10
+ className = '',
11
+ variant = 'default',
12
+ size = 'default',
13
+ ...props
14
+ }) => {
15
+ const baseStyles = 'inline-flex items-center justify-center rounded-lg font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400 disabled:pointer-events-none disabled:opacity-50';
16
+
17
+ const variants = {
18
+ default: 'bg-slate-900 text-white hover:bg-slate-800',
19
+ ghost: 'hover:bg-slate-100 text-slate-700',
20
+ };
21
+
22
+ const sizes = {
23
+ default: 'h-10 px-4 py-2',
24
+ sm: 'h-8 px-3 text-sm',
25
+ icon: 'h-9 w-9',
26
+ };
27
+
28
+ return (
29
+ <button
30
+ className={`${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`}
31
+ {...props}
32
+ >
33
+ {children}
34
+ </button>
35
+ );
36
+ };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+
3
+ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
4
+
5
+ export const Input: React.FC<InputProps> = ({ className = '', ...props }) => {
6
+ return (
7
+ <input
8
+ className={`flex h-9 w-full rounded-lg border border-slate-200 bg-white px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400 disabled:cursor-not-allowed disabled:opacity-50 ${className}`}
9
+ {...props}
10
+ />
11
+ );
12
+ };
@@ -0,0 +1,19 @@
1
+ export default defineBackground(() => {
2
+ console.log('Bookmark Extension background loaded');
3
+
4
+ // Listen for messages from popup or content scripts
5
+ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
6
+ if (message.type === 'GET_CURRENT_TAB') {
7
+ browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
8
+ if (tabs[0]) {
9
+ sendResponse({
10
+ url: tabs[0].url,
11
+ title: tabs[0].title,
12
+ favicon: tabs[0].favIconUrl,
13
+ });
14
+ }
15
+ });
16
+ return true; // Keep message channel open for async response
17
+ }
18
+ });
19
+ });
@@ -0,0 +1,186 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { base44 } from '@/lib/base44Client';
3
+ import { Button } from '@/components/Button';
4
+ import { Input } from '@/components/Input';
5
+ import { BookmarkCard } from '@/components/BookmarkCard';
6
+ import { Bookmark, Plus, Search, Sparkles } from 'lucide-react';
7
+
8
+ const BookmarkEntity = base44.entities.Bookmark;
9
+
10
+ interface CurrentTab {
11
+ url?: string;
12
+ title?: string;
13
+ favicon?: string;
14
+ }
15
+
16
+ export default function App() {
17
+ const [bookmarks, setBookmarks] = useState<any[]>([]);
18
+ const [searchQuery, setSearchQuery] = useState('');
19
+ const [isLoading, setIsLoading] = useState(true);
20
+ const [isSaving, setIsSaving] = useState(false);
21
+ const [currentTab, setCurrentTab] = useState<CurrentTab>({});
22
+ const [isAISearch, setIsAISearch] = useState(false);
23
+
24
+ useEffect(() => {
25
+ fetchBookmarks();
26
+ getCurrentTab();
27
+ }, []);
28
+
29
+ const getCurrentTab = async () => {
30
+ try {
31
+ const response = await browser.runtime.sendMessage({ type: 'GET_CURRENT_TAB' });
32
+ setCurrentTab(response);
33
+ } catch (error) {
34
+ console.error('Error getting current tab:', error);
35
+ }
36
+ };
37
+
38
+ const fetchBookmarks = async () => {
39
+ try {
40
+ const data = await BookmarkEntity.list();
41
+ setBookmarks(data);
42
+ } catch (error) {
43
+ console.error('Error fetching bookmarks:', error);
44
+ } finally {
45
+ setIsLoading(false);
46
+ }
47
+ };
48
+
49
+ const saveCurrentPage = async () => {
50
+ if (!currentTab.url || !currentTab.title) return;
51
+
52
+ setIsSaving(true);
53
+ try {
54
+ await BookmarkEntity.create({
55
+ url: currentTab.url,
56
+ title: currentTab.title,
57
+ favicon: currentTab.favicon || '',
58
+ tags: [],
59
+ });
60
+ await fetchBookmarks();
61
+ } catch (error) {
62
+ console.error('Error saving bookmark:', error);
63
+ } finally {
64
+ setIsSaving(false);
65
+ }
66
+ };
67
+
68
+ const deleteBookmark = async (id: string) => {
69
+ try {
70
+ await BookmarkEntity.delete(id);
71
+ await fetchBookmarks();
72
+ } catch (error) {
73
+ console.error('Error deleting bookmark:', error);
74
+ }
75
+ };
76
+
77
+ const handleSearch = async () => {
78
+ if (!searchQuery.trim()) {
79
+ fetchBookmarks();
80
+ return;
81
+ }
82
+
83
+ if (isAISearch) {
84
+ // Use AI agent for natural language search
85
+ try {
86
+ const agent = base44.agents.BookmarkSearchAgent;
87
+ const response = await agent.run(searchQuery);
88
+ // Parse agent response and filter bookmarks
89
+ // This is a placeholder - actual implementation depends on agent response format
90
+ console.log('AI Search result:', response);
91
+ } catch (error) {
92
+ console.error('Error with AI search:', error);
93
+ }
94
+ } else {
95
+ // Simple text search
96
+ const filtered = bookmarks.filter((bookmark) =>
97
+ bookmark.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
98
+ bookmark.url.toLowerCase().includes(searchQuery.toLowerCase())
99
+ );
100
+ setBookmarks(filtered);
101
+ }
102
+ };
103
+
104
+ const filteredBookmarks = searchQuery
105
+ ? bookmarks.filter((bookmark) =>
106
+ bookmark.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
107
+ bookmark.url.toLowerCase().includes(searchQuery.toLowerCase())
108
+ )
109
+ : bookmarks;
110
+
111
+ return (
112
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-blue-50/30">
113
+ <div className="w-full h-full">
114
+ {/* Header */}
115
+ <div className="bg-white border-b border-slate-200 px-4 py-3">
116
+ <div className="flex items-center justify-between mb-3">
117
+ <h1 className="text-lg font-semibold text-slate-900 flex items-center gap-2">
118
+ <Bookmark className="w-5 h-5 text-blue-600" />
119
+ My Bookmarks
120
+ </h1>
121
+ <Button
122
+ onClick={saveCurrentPage}
123
+ disabled={isSaving || !currentTab.url}
124
+ size="sm"
125
+ className="bg-blue-600 hover:bg-blue-700"
126
+ >
127
+ <Plus className="w-4 h-4 mr-1" />
128
+ Save Page
129
+ </Button>
130
+ </div>
131
+
132
+ {/* Search Bar */}
133
+ <div className="relative">
134
+ <Input
135
+ type="text"
136
+ value={searchQuery}
137
+ onChange={(e) => setSearchQuery(e.target.value)}
138
+ onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
139
+ placeholder="Search bookmarks..."
140
+ className="pl-9 pr-10"
141
+ />
142
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
143
+ <button
144
+ onClick={() => setIsAISearch(!isAISearch)}
145
+ className={`absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded transition-colors ${
146
+ isAISearch ? 'text-purple-600 bg-purple-50' : 'text-slate-400 hover:text-slate-600'
147
+ }`}
148
+ title="Toggle AI Search"
149
+ >
150
+ <Sparkles className="w-4 h-4" />
151
+ </button>
152
+ </div>
153
+ </div>
154
+
155
+ {/* Bookmarks List */}
156
+ <div className="p-4 space-y-2 max-h-[440px] overflow-y-auto">
157
+ {isLoading ? (
158
+ <div className="flex items-center justify-center py-12">
159
+ <div className="w-6 h-6 border-2 border-slate-200 border-t-blue-600 rounded-full animate-spin" />
160
+ </div>
161
+ ) : filteredBookmarks.length === 0 ? (
162
+ <div className="text-center py-12">
163
+ <Bookmark className="w-12 h-12 text-slate-300 mx-auto mb-3" />
164
+ <p className="text-slate-400 text-sm">
165
+ {searchQuery ? 'No bookmarks found' : 'No bookmarks yet'}
166
+ </p>
167
+ {!searchQuery && (
168
+ <p className="text-slate-400 text-xs mt-1">
169
+ Click "Save Page" to bookmark this page
170
+ </p>
171
+ )}
172
+ </div>
173
+ ) : (
174
+ filteredBookmarks.map((bookmark) => (
175
+ <BookmarkCard
176
+ key={bookmark.id}
177
+ bookmark={bookmark}
178
+ onDelete={() => deleteBookmark(bookmark.id)}
179
+ />
180
+ ))
181
+ )}
182
+ </div>
183
+ </div>
184
+ </div>
185
+ );
186
+ }
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Bookmarks</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="./main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import App from './App';
4
+ import './style.css';
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>
10
+ );
@@ -0,0 +1,21 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ body {
6
+ margin: 0;
7
+ padding: 0;
8
+ min-width: 400px;
9
+ max-width: 400px;
10
+ min-height: 500px;
11
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
12
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
13
+ sans-serif;
14
+ -webkit-font-smoothing: antialiased;
15
+ -moz-osx-font-smoothing: grayscale;
16
+ }
17
+
18
+ #root {
19
+ width: 100%;
20
+ height: 100%;
21
+ }
@@ -0,0 +1,5 @@
1
+ import { Base44 } from '@base44/sdk';
2
+
3
+ export const base44 = new Base44({
4
+ projectId: '<%= projectId %>',
5
+ });
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'wxt';
2
+
3
+ export default defineConfig({
4
+ extensionApi: 'chrome',
5
+ modules: ['@wxt-dev/module-react'],
6
+ srcDir: 'wxt-src',
7
+ });
@@ -11,6 +11,12 @@
11
11
  "name": "Create a basic project",
12
12
  "description": "Minimal Base44 backend for defining your data models and logic",
13
13
  "path": "backend-only"
14
+ },
15
+ {
16
+ "id": "chrome-extension",
17
+ "name": "Chrome Extension",
18
+ "description": "Chrome extension with WXT framework and Base44 backend for bookmarking with AI search",
19
+ "path": "chrome-extension"
14
20
  }
15
21
  ]
16
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/cli",
3
- "version": "0.0.26-pr.172.6febf45",
3
+ "version": "0.0.26-pr.174.9ce53d2",
4
4
  "description": "Base44 CLI - Unified interface for managing Base44 applications",
5
5
  "type": "module",
6
6
  "bin": {