Ouro
  • Docs
  • Blog
Join for freeSign in
  • Teams
  • Search
Assets
  • Quests
  • Posts
  • APIs
  • Data
  • Teams
  • Search
Assets
  • Quests
  • Posts
  • APIs
  • Data
1mo
37 views
Loading compatible actions...

dear 'X" :

the Partial, this time's, is back in-game

html
}
"use client";

import { useState, useEffect } from "react";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { Search, Star, Download, Users } from "lucide-react";

// Define types
interface MarketplaceItem {
  id: string;
  name: string;
  description: string;
  category: string;
  rating: number;
  downloads: number;
  users: number;
  tags: string[];
  author: string;
  version: string;
  lastUpdated: string;
  size: string;
  license: string;
}

// Mock data
const mockItems: MarketplaceItem[] = [
  {
    id: "1",
    name: "TaskFlow AI",
    description: "AI-powered task automation for personal productivity",
    category: "AI Models",
    rating: 4.8,
    downloads: 12500,
    users: 8900,
    tags: ["productivity", "ai", "automation"],
    author: "AI Labs",
    version: "2.3.1",
    lastUpdated: "2023-10-15",
    size: "45MB",
    license: "MIT"
  },
  {
    id: "2",
    name: "WeatherPWA",
    description: "Beautiful weather app with location-based forecasts",
    category: "PWAs",
    rating: 4.5,
    downloads: 8700,
    users: 5400,
    tags: ["weather", "pwa", "forecast"],
    author: "Climate Devs",
    version: "1.8.2",
    lastUpdated: "2023-09-22",
    size: "12MB",
    license: "Apache 2.0"
  },
  {
    id: "3",
    name: "DataSync Pro",
    description: "Cross-platform data synchronization tool",
    category: "Automations",
    rating: 4.9,
    downloads: 21000,
    users: 15600,
    tags: ["sync", "data", "automation"],
    author: "SyncMaster Inc",
    version: "3.1.0",
    lastUpdated: "2023-11-05",
    size: "68MB",
    license: "GPL v3"
  },
  {
    id: "4",
    name: "CodeAssistant",
    description: "AI pair programmer for multiple languages",
    category: "AI Models",
    rating: 4.7,
    downloads: 34200,
    users: 28900,
    tags: ["coding", "ai", "developer"],
    author: "DevAI Solutions",
    version: "1.5.4",
    lastUpdated: "2023-10-30",
    size: "120MB",
    license: "MIT"
  },
  {
    id: "5",
    name: "NoteVault",
    description: "Secure note-taking PWA with encryption",
    category: "PWAs",
    rating: 4.6,
    downloads: 15600,
    users: 9800,
    tags: ["notes", "pwa", "security"],
    author: "SecureApps",
    version: "2.0.1",
    lastUpdated: "2023-08-17",
    size: "22MB",
    license: "BSD"
  },
  {
    id: "6",
    name: "SocialBot",
    description: "Automated social media scheduler and analyzer",
    category: "Automations",
    rating: 4.4,
    downloads: 9800,
    users: 6700,
    tags: ["social", "automation", "analytics"],
    author: "SocialTech",
    version: "1.9.3",
    lastUpdated: "2023-09-10",
    size: "35MB",
    license: "MIT"
  }
];

const categories = ["All", "PWAs", "AI Models", "Automations"];

export default function BazaarMarketplace() {
  const [items, setItems] = useState<MarketplaceItem[]>(mockItems);
  const [filteredItems, setFilteredItems] = useState<MarketplaceItem[]>(mockItems);
  const [searchTerm, setSearchTerm] = useState("");
  const [selectedCategory, setSelectedCategory] = useState("All");
  const [selectedItem, setSelectedItem] = useState<MarketplaceItem | null>(null);

  // Filter items based on search and category
  useEffect(() => {
    let result = items;
    
    if (selectedCategory !== "All") {
      result = result.filter(item => item.category === selectedCategory);
    }
    
    if (searchTerm) {
      const term = searchTerm.toLowerCase();
      result = result.filter(item => 
        item.name.toLowerCase().includes(term) || 
        item.description.toLowerCase().includes(term) ||
        item.tags.some(tag => tag.toLowerCase().includes(term))
      );
    }
    
    setFilteredItems(result);
  }, [searchTerm, selectedCategory, items]);

  const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSearchTerm(e.target.value);
  };

  const handleCategoryChange = (value: string) => {
    setSelectedCategory(value);
  };

  const openItemDetails = (item: MarketplaceItem) => {
    setSelectedItem(item);
  };

  const closeItemDetails = () => {
    setSelectedItem(null);
  };

  return (
    <div className="min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 p-4 md:p-8">
      <div className="max-w-7xl mx-auto">
        {/* Header */}
        <header className="mb-8 text-center">
          <h1 className="text-4xl font-bold text-gray-900 mb-2">Bazaar Marketplace</h1>
          <p className="text-gray-600 max-w-2xl mx-auto">
            Discover open-source PWAs, AI models, automations, and cross-platform tools
          </p>
        </header>

        {/* Search and Filter Section */}
        <div className="bg-white rounded-xl shadow-md p-6 mb-8">
          <div className="flex flex-col md:flex-row gap-4">
            <div className="relative flex-1">
              <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" />
              <Input
                placeholder="Search tools, apps, models..."
                className="pl-10 py-6"
                value={searchTerm}
                onChange={handleSearch}
              />
            </div>
            <div className="w-full md:w-64">
              <Select value={selectedCategory} onValueChange={handleCategoryChange}>
                <SelectTrigger className="py-6">
                  <SelectValue placeholder="Category" />
                </SelectTrigger>
                <SelectContent>
                  {categories.map(category => (
                    <SelectItem key={category} value={category}>
                      {category}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          </div>
        </div>

        {/* Results Info */}
        <div className="mb-6 flex justify-between items-center">
          <p className="text-gray-600">
            Showing {filteredItems.length} of {items.length} items
          </p>
        </div>

        {/* Items Grid */}
        {filteredItems.length === 0 ? (
          <div className="text-center py-12">
            <h3 className="text-xl font-semibold text-gray-900 mb-2">No items found</h3>
            <p className="text-gray-600">Try adjusting your search or filter criteria</p>
          </div>
        ) : (
          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
            {filteredItems.map(item => (
              <Card 
                key={item.id} 
                className="overflow-hidden hover:shadow-lg transition-shadow cursor-pointer"
                onClick={() => openItemDetails(item)}
              >
                <CardHeader className="pb-3">
                  <div className="flex justify-between items-start">
                    <CardTitle className="text-xl">{item.name}</CardTitle>
                    <span className="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded">
                      {item.category}
                    </span>
                  </div>
                  <CardDescription className="line-clamp-2">{item.description}</CardDescription>
                </CardHeader>
                <CardContent>
                  <div className="flex items-center mb-3">
                    <div className="flex items-center mr-4">
                      <Star className="h-4 w-4 text-yellow-400 fill-current" />
                      <span className="ml-1 text-sm font-medium">{item.rating}</span>
                    </div>
                    <div className="flex items-center">
                      <Download className="h-4 w-4 text-gray-500" />
                      <span className="ml-1 text-sm text-gray-600">{item.downloads.toLocaleString()}</span>
                    </div>
                  </div>
                  <div className="flex flex-wrap gap-2">
                    {item.tags.slice(0, 3).map(tag => (
                      <span 
                        key={tag} 
                        className="bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded"
                      >
                        {tag}
                      </span>
                    ))}
                  </div>
                </CardContent>
                <CardFooter className="bg-gray-50 py-3">
                  <div className="flex justify-between items-center w-full">
                    <span className="text-sm text-gray-600">by {item.author}</span>
                    <Button variant="outline" size="sm">Install</Button>
                  </div>
                </CardFooter>
              </Card>
            ))}
          </div>
        )}

        {/* Item Detail Modal */}
        {selectedItem && (
          <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
            <div 
              className="bg-white rounded-xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto"
              onClick={(e) => e.stopPropagation()}
            >
              <div className="p-6">
                <div className="flex justify-between items-start mb-4">
                  <div>
                    <h2 className="text-2xl font-bold text-gray-900">{selectedItem.name}</h2>
                    <p className="text-gray-600">{selectedItem.category}</p>
                  </div>
                  <Button variant="ghost" onClick={closeItemDetails}>✕</Button>
                </div>
                
                <div className="mb-6">
                  <p className="text-gray-700 mb-4">{selectedItem.description}</p>
                  
                  <div className="grid grid-cols-2 gap-4 mb-6">
                    <div className="bg-gray-50 p-4 rounded-lg">
                      <h3 className="font-semibold text-gray-900 mb-2">Details</h3>
                      <ul className="space-y-2 text-sm text-gray-600">
                        <li className="flex justify-between">
                          <span>Version:</span>
                          <span className="font-medium">{selectedItem.version}</span>
                        </li>
                        <li className="flex justify-between">
                          <span>Last Updated:</span>
                          <span className="font-medium">{selectedItem.lastUpdated}</span>
                        </li>
                        <li className="flex justify-between">
                          <span>Size:</span>
                          <span className="font-medium">{selectedItem.size}</span>
                        </li>
                        <li className="flex justify-between">
                          <span>License:</span>
                          <span className="font-medium">{selectedItem.license}</span>
                        </li>
                      </ul>
                    </div>
                    
                    <div className="bg-gray-50 p-4 rounded-lg">
                      <h3 className="font-semibold text-gray-900 mb-2">Statistics</h3>
                      <ul className="space-y-2 text-sm text-gray-600">
                        <li className="flex justify-between">
                          <span>Rating:</span>
                          <span className="font-medium flex items-center">
                            <Star className="h-4 w-4 text-yellow-400 fill-current mr-1" />
                            {selectedItem.rating}
                          </span>
                        </li>
                        <li className="flex justify-between">
                          <span>Downloads:</span>
                          <span className="font-medium">{selectedItem.downloads.toLocaleString()}</span>
                        </li>
                        <li className="flex justify-between">
                          <span>Active Users:</span>
                          <span className="font-medium flex items-center">
                            <Users className="h-4 w-4 text-gray-500 mr-1" />
                            {selectedItem.users.toLocaleString()}
                          </span>
                        </li>
                      </ul>
                    </div>
                  </div>
                  
                  <div className="mb-6">
                    <h3 className="font-semibold text-gray-900 mb-2">Tags</h3>
                    <div className="flex flex-wrap gap-2">
                      {selectedItem.tags.map(tag => (
                        <span 
                          key={tag} 
                          className="bg-blue-100 text-blue-800 text-sm px-3 py-1 rounded-full"
                        >
                          {tag}
                        </span>
                      ))}
                    </div>
                  </div>
                </div>
                
                <div className="flex flex-col sm:flex-row gap-3">
                  <Button className="flex-1">Install</Button>
                  <Button variant="outline" className="flex-1">View Source</Button>
                </div>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}




this one from the Bigg Hand
Loading comments...