diff --git a/.changeset/friendly-cats-draw.md b/.changeset/friendly-cats-draw.md new file mode 100644 index 000000000..65921ac09 --- /dev/null +++ b/.changeset/friendly-cats-draw.md @@ -0,0 +1,6 @@ +--- +"@status-im/status-network": patch +"hub": patch +--- + +discover section diff --git a/apps/hub/public/apps/cats-fishing-avatar.png b/apps/hub/public/apps/cats-fishing-avatar.png index 0ce674148..acc9a115f 100644 Binary files a/apps/hub/public/apps/cats-fishing-avatar.png and b/apps/hub/public/apps/cats-fishing-avatar.png differ diff --git a/apps/hub/public/apps/cats-fishing-cover.png b/apps/hub/public/apps/cats-fishing-cover.png index ae1cf63ae..b3220397e 100644 Binary files a/apps/hub/public/apps/cats-fishing-cover.png and b/apps/hub/public/apps/cats-fishing-cover.png differ diff --git a/apps/hub/public/apps/cats-on-canvas-avatar.png b/apps/hub/public/apps/cats-on-canvas-avatar.png new file mode 100644 index 000000000..0ecb6722c Binary files /dev/null and b/apps/hub/public/apps/cats-on-canvas-avatar.png differ diff --git a/apps/hub/public/apps/cats-on-canvas-cover.png b/apps/hub/public/apps/cats-on-canvas-cover.png new file mode 100644 index 000000000..2ca7d801d Binary files /dev/null and b/apps/hub/public/apps/cats-on-canvas-cover.png differ diff --git a/apps/hub/public/apps/cuddleclub-avatar.png b/apps/hub/public/apps/cuddleclub-avatar.png new file mode 100644 index 000000000..8f0436110 Binary files /dev/null and b/apps/hub/public/apps/cuddleclub-avatar.png differ diff --git a/apps/hub/public/apps/cuddleclub-cover.png b/apps/hub/public/apps/cuddleclub-cover.png new file mode 100644 index 000000000..d03275d9f Binary files /dev/null and b/apps/hub/public/apps/cuddleclub-cover.png differ diff --git a/apps/hub/public/apps/feline-friends-avatar.png b/apps/hub/public/apps/feline-friends-avatar.png new file mode 100644 index 000000000..c29ff2f7a Binary files /dev/null and b/apps/hub/public/apps/feline-friends-avatar.png differ diff --git a/apps/hub/public/apps/feline-friends-cover.png b/apps/hub/public/apps/feline-friends-cover.png new file mode 100644 index 000000000..249dfec42 Binary files /dev/null and b/apps/hub/public/apps/feline-friends-cover.png differ diff --git a/apps/hub/public/apps/furtastic-adventures-avatar.png b/apps/hub/public/apps/furtastic-adventures-avatar.png new file mode 100644 index 000000000..bf0507f78 Binary files /dev/null and b/apps/hub/public/apps/furtastic-adventures-avatar.png differ diff --git a/apps/hub/public/apps/furtastic-adventures-cover.png b/apps/hub/public/apps/furtastic-adventures-cover.png new file mode 100644 index 000000000..7aa212128 Binary files /dev/null and b/apps/hub/public/apps/furtastic-adventures-cover.png differ diff --git a/apps/hub/public/apps/kittycoin-avatar.png b/apps/hub/public/apps/kittycoin-avatar.png new file mode 100644 index 000000000..3f0fcd2c9 Binary files /dev/null and b/apps/hub/public/apps/kittycoin-avatar.png differ diff --git a/apps/hub/public/apps/kittycoin-cover.png b/apps/hub/public/apps/kittycoin-cover.png new file mode 100644 index 000000000..c1cb1bf8e Binary files /dev/null and b/apps/hub/public/apps/kittycoin-cover.png differ diff --git a/apps/hub/public/apps/meow-marketplace-avatar.png b/apps/hub/public/apps/meow-marketplace-avatar.png new file mode 100644 index 000000000..d21e04d21 Binary files /dev/null and b/apps/hub/public/apps/meow-marketplace-avatar.png differ diff --git a/apps/hub/public/apps/meow-marketplace-cover.png b/apps/hub/public/apps/meow-marketplace-cover.png new file mode 100644 index 000000000..aed177b75 Binary files /dev/null and b/apps/hub/public/apps/meow-marketplace-cover.png differ diff --git a/apps/hub/public/apps/paw-sitive-vibes-avatar.png b/apps/hub/public/apps/paw-sitive-vibes-avatar.png new file mode 100644 index 000000000..97794c3de Binary files /dev/null and b/apps/hub/public/apps/paw-sitive-vibes-avatar.png differ diff --git a/apps/hub/public/apps/paw-sitive-vibes-cover.png b/apps/hub/public/apps/paw-sitive-vibes-cover.png new file mode 100644 index 000000000..611851606 Binary files /dev/null and b/apps/hub/public/apps/paw-sitive-vibes-cover.png differ diff --git a/apps/hub/public/apps/pawse-avatar.png b/apps/hub/public/apps/pawse-avatar.png new file mode 100644 index 000000000..5bbde0c0f Binary files /dev/null and b/apps/hub/public/apps/pawse-avatar.png differ diff --git a/apps/hub/public/apps/pawse-cover.png b/apps/hub/public/apps/pawse-cover.png new file mode 100644 index 000000000..3f2ea3319 Binary files /dev/null and b/apps/hub/public/apps/pawse-cover.png differ diff --git a/apps/hub/public/apps/status-network-bridge-avatar.png b/apps/hub/public/apps/status-network-bridge-avatar.png index 52ab4d83c..f7909474c 100644 Binary files a/apps/hub/public/apps/status-network-bridge-avatar.png and b/apps/hub/public/apps/status-network-bridge-avatar.png differ diff --git a/apps/hub/public/apps/whiskers-waves-avatar.png b/apps/hub/public/apps/whiskers-waves-avatar.png new file mode 100644 index 000000000..53fab1ce8 Binary files /dev/null and b/apps/hub/public/apps/whiskers-waves-avatar.png differ diff --git a/apps/hub/public/apps/whiskers-waves-cover.png b/apps/hub/public/apps/whiskers-waves-cover.png new file mode 100644 index 000000000..03c6f2098 Binary files /dev/null and b/apps/hub/public/apps/whiskers-waves-cover.png differ diff --git a/apps/hub/src/app/_components/app-card.tsx b/apps/hub/src/app/_components/app-card.tsx index 7988c2ba5..ffe7ba078 100644 --- a/apps/hub/src/app/_components/app-card.tsx +++ b/apps/hub/src/app/_components/app-card.tsx @@ -1,36 +1,90 @@ 'use client' -interface AppCardProps { +import { ExternalIcon } from '@status-im/icons/20' +import { TwitterIcon } from '@status-im/icons/social' +import { ButtonLink } from '@status-im/status-network/components' +import Image from 'next/image' + +type Props = { name: string description: string - category: string - onLaunch: () => void + website: string + twitter?: string + cover: string + icon: string } -export function AppCard({ - name, - description, - category, - onLaunch, -}: AppCardProps) { +function AppCard(props: Props) { + const { name, description, website, twitter, cover, icon } = props + return ( -
-
-
- - {category} - +
+
+
+ {name} +
+
+ {name}
-

{name}

-

{description}

- +
+

{name}

+

+ {description} +

+
+ + {website.replace('https://', '')}{' '} + + + {twitter && ( + + + + )} +
+
) } + +function AppCardSkeleton() { + return ( +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ ) +} + +export { AppCard, AppCardSkeleton } diff --git a/apps/hub/src/app/discover/page.tsx b/apps/hub/src/app/discover/page.tsx index 9eda1ea1c..cee115d8b 100644 --- a/apps/hub/src/app/discover/page.tsx +++ b/apps/hub/src/app/discover/page.tsx @@ -1,649 +1,156 @@ 'use client' -import { useState } from 'react' - +import { useMemo, useState } from 'react' + +import { Tag } from '@status-im/components' +import { ChevronDownIcon } from '@status-im/icons/20' +import { Button, ButtonLink } from '@status-im/status-network/components' +import { cx } from 'cva' + +import { categories } from '~/constants/categories' +import { tabs } from '~/constants/tabs' +import { apps } from '~/data/apps' +import { featuredApps } from '~/data/featured-apps' +import { AppCard } from '~components/app-card' import { HubLayout } from '~components/hub-layout' export default function DiscoverPage() { const [activeTab, setActiveTab] = useState('all') const [selectedTag, setSelectedTag] = useState('all-apps') + const [openCategories, setOpenCategories] = useState(false) - const tabs = [ - { id: 'popular', label: 'Popular' }, - { id: 'new', label: 'New' }, - { id: 'all', label: 'All' }, - ] - - // Simple app data for demonstration - const apps = [ - { - id: 1, - name: 'Paw-sitive Vibes', - category: 'Community', - status: 'Live', - description: 'Join the community that supports animal welfare!', - icon: '🐾', - rating: 4.8, - users: '2.1M', - }, - { - id: 2, - name: 'Whiskers & Waves', - category: 'Social', - status: 'Live', - description: 'Surf the web with a feline twist', - icon: '🐱', - rating: 4.7, - users: '1.8M', - }, - { - id: 3, - name: 'Feline Friends', - category: 'Social', - status: 'Live', - description: 'A social platform for cat lovers to connect', - icon: '🐈', - rating: 4.6, - users: '950K', - }, - { - id: 4, - name: 'KittyCoin', - category: 'DeFi', - status: 'Live', - description: 'The cryptocurrency for cat enthusiasts', - icon: '🪙', - rating: 4.5, - users: '750K', - }, - { - id: 5, - name: 'Meow Marketplace', - category: 'NFT', - status: 'Live', - description: 'Buy, sell, and trade cat-related goods', - icon: '🛍️', - rating: 4.4, - users: '200K', - }, - { - id: 6, - name: 'Fur-tastic Adventures', - category: 'Gaming', - status: 'Live', - description: 'Documenting the adventures of cats', - icon: '🚗', - rating: 4.3, - users: '120K', - }, - { - id: 7, - name: 'Cats on Canvas', - category: 'NFT', - status: 'Live', - description: 'Art inspired by our furry friends', - icon: '🎨', - rating: 4.2, - users: '80K', - }, - { - id: 8, - name: 'Pawse', - category: 'Social', - status: 'Live', - description: "Cat's first music platform", - icon: '🎵', - rating: 4.1, - users: '50K', - }, - { - id: 9, - name: 'Cuddle Club', - category: 'Community', - status: 'Live', - description: 'A subscription box for cat lovers and their pets', - icon: '📦', - rating: 4.0, - users: '30K', - }, - ] - - const getStatusColor = (status: string) => { - switch (status.toLowerCase()) { - case 'live': - return 'bg-green-100 text-green-700' - case 'beta': - return 'bg-blue-100 text-blue-700' - case 'upcoming': - return 'bg-yellow-100 text-yellow-700' - default: - return 'bg-gray-100 text-gray-700' - } - } - - const getCategoryColor = (category: string) => { - switch (category.toLowerCase()) { - case 'defi': - return 'bg-purple-100 text-purple-700' - case 'nft': - return 'bg-pink-100 text-pink-700' - case 'gaming': - return 'bg-green-100 text-green-700' - case 'social': - return 'bg-blue-100 text-blue-700' - case 'tools': - return 'bg-orange-100 text-orange-700' - default: - return 'bg-gray-100 text-gray-700' - } - } + const currentApps = useMemo(() => { + return apps.filter(app => { + const matchesTab = + activeTab === 'all' || + (activeTab === 'popular' && app.isPopular) || + (activeTab === 'new' && app.isNew) - const getCurrentApps = () => { - return apps // For now, return all apps regardless of tab - } + const matchesCategory = + selectedTag === 'all-apps' || app.category.toLowerCase() === selectedTag - const currentApps = getCurrentApps() + return matchesTab && matchesCategory + }) + }, [selectedTag, activeTab]) return ( -
- {/* Hero Section */} -
-

Discover

-

- Explore new applications and opportunities -

-
- +
{/* Main Content */} -
+
{/* Hero Section */} -
-

- Decentralised + gasless = ❤️ +
+

+ Gasless apps FTW

-

+

Explore curated dApps and services built on Status Network

{/* Featured Section */} -
-
-

Featured

- +
{/* Featured Apps Grid */}
- {/* Cat Fishing */} -
-
-
-
-
🎣
-

- Cat Fishing -

-
-
-

- Cat Fishing -

-

- You love cats, cats love fish. -

-
- - - cats.fishing - - -
- - - - - - -
-
-
-
+ {featuredApps.map(app => ( + + ))} +
+
- {/* Status Network Bridge */} -
-
-
-
-
🌉
-

- Status Network Bridge -

-
-
-

- Status Network Bridge -

-

- Saving for gas? We've got you covered! -

- +
+ {/* Header with Title and Sorting Options */} +
+

+ {activeTab === 'popular' + ? 'Popular Apps' + : activeTab === 'new' + ? 'New Apps' + : 'All Apps'} +

+ +
+ {/* Sorting Options */} +
+ {tabs.map(tab => ( + + ))}
-
- {/* Hash Vegas */} -
-
-
-
-
🎰
-

- Hash Vegas -

-
-
-

- Hash Vegas -

-

- Fair and transparent onchain gaming -

-
- - - hashvegas.casino - - -
- - - - - - -
-
-
+ {/* Categories Button */} +
-
- {/* Header with Title and Sorting Options */} -
-

All Apps

- -
- {/* Sorting Options */} -
- {tabs.map(tab => ( - + {/* Category Filter Buttons */} +
+
+ {categories.map(category => ( + setSelectedTag(category.id)} + selected={selectedTag === category.id} + label={category.label} + size="32" + /> ))}
- - {/* Categories Button */} - -
-
- - {/* Category Filter Buttons */} -
- {/* First Row */} -
- - - - - - - - - - -
- {/* Second Row */} -
- - - -
-
- - {/* Apps Grid */} -
- {currentApps.map(app => ( -
-
-
-
- {app.icon} -
-
-

- {app.name} -

-
- - {app.category} - - - {app.status} - -
-
-
-
-
- - {app.rating} - - -
-

{app.users} users

-
+ {/* Apps Grid */} + {currentApps.length > 0 ? ( +
+ {currentApps.map(app => ( + + ))} +
+ ) : ( +
+
+

+ No apps found +

+

+ Try adjusting your filters to see more apps +

- -

- {app.description} -

- -
- ))} + )}
diff --git a/apps/hub/src/constants/categories.ts b/apps/hub/src/constants/categories.ts new file mode 100644 index 000000000..ebf284498 --- /dev/null +++ b/apps/hub/src/constants/categories.ts @@ -0,0 +1,18 @@ +import type { Category } from '~/types/app' + +export const categories: Category[] = [ + { id: 'all-apps', label: '🧩 All apps' }, + { id: 'ai', label: '✨ AI' }, + { id: 'bridge', label: '🚗 Bridge' }, + { id: 'community', label: '🐕 Community' }, + { id: 'defi', label: '📈 DeFi' }, + { id: 'gaming', label: '🎮 Gaming' }, + { id: 'infra', label: '💻 Infra' }, + { id: 'nft', label: '🖼️ NFT' }, + { id: 'payment', label: '💰 Payment' }, + { id: 'privacy', label: '🕵️ Privacy' }, + { id: 'social', label: '☕ Social' }, + { id: 'spending', label: '🐷 Spending' }, + { id: 'tooling', label: '☂️ Tooling' }, + { id: 'wallet', label: '💎 Wallet' }, +] diff --git a/apps/hub/src/constants/tabs.ts b/apps/hub/src/constants/tabs.ts new file mode 100644 index 000000000..35ee01a5e --- /dev/null +++ b/apps/hub/src/constants/tabs.ts @@ -0,0 +1,7 @@ +import type { Tab } from '~/types/app' + +export const tabs: Tab[] = [ + { id: 'popular', label: 'Popular' }, + { id: 'new', label: 'New' }, + { id: 'all', label: 'All' }, +] diff --git a/apps/hub/src/data/apps.ts b/apps/hub/src/data/apps.ts new file mode 100644 index 000000000..1ed973133 --- /dev/null +++ b/apps/hub/src/data/apps.ts @@ -0,0 +1,112 @@ +import type { App } from '~/types/app' + +export const apps: App[] = [ + { + id: 1, + name: 'Paw-sitive Vibes', + category: 'Community', + status: 'Live', + description: 'Join the community that supports animal welfare!', + website: 'https://paw-sitive.vibes', + cover: '/apps/paw-sitive-vibes-cover.png', + icon: '/apps/paw-sitive-vibes-avatar.png', + isPopular: true, + isNew: false, + }, + { + id: 2, + name: 'Whiskers & Waves', + category: 'Social', + status: 'Live', + description: 'Surf the web with a feline twist', + website: 'https://whiskers.waves', + cover: '/apps/whiskers-waves-cover.png', + icon: '/apps/whiskers-waves-avatar.png', + isPopular: false, + isNew: true, + }, + { + id: 3, + name: 'Feline Friends', + category: 'Social', + status: 'Live', + description: 'A social platform for cat lovers to connect', + website: 'https://feline-friends.com', + cover: '/apps/feline-friends-cover.png', + icon: '/apps/feline-friends-avatar.png', + isPopular: true, + isNew: false, + }, + { + id: 4, + name: 'KittyCoin', + category: 'DeFi', + status: 'Live', + description: 'The cryptocurrency for cat enthusiasts', + website: 'https://kittycoin.org', + cover: '/apps/kittycoin-cover.png', + icon: '/apps/kittycoin-avatar.png', + isPopular: true, + isNew: true, + }, + { + id: 5, + name: 'Meow Marketplace', + category: 'NFT', + status: 'Live', + description: 'Buy, sell, and trade cat-related goods', + website: 'https://meow.marketplace', + cover: '/apps/meow-marketplace-cover.png', + icon: '/apps/meow-marketplace-avatar.png', + isPopular: false, + isNew: true, + }, + { + id: 6, + name: 'Fur-tastic Adventures', + category: 'Gaming', + status: 'Live', + description: 'Documenting the adventures of cats', + website: 'https://furtastic.tube', + cover: '/apps/furtastic-adventures-cover.png', + icon: '/apps/furtastic-adventures-avatar.png', + isPopular: false, + isNew: false, + }, + { + id: 7, + name: 'Cats on Canvas', + category: 'NFT', + status: 'Live', + description: 'Art inspired by our furry friends', + website: 'https://cats.on.canvas', + cover: '/apps/cats-on-canvas-cover.png', + icon: '/apps/cats-on-canvas-avatar.png', + isPopular: true, + isNew: false, + }, + { + id: 8, + name: 'Pawse', + category: 'Social', + status: 'Live', + description: "Cat's first music platform", + website: 'https://pawse.fm', + cover: '/apps/pawse-cover.png', + icon: '/apps/pawse-avatar.png', + isPopular: false, + isNew: true, + }, + { + id: 9, + name: 'Cuddle Club', + category: 'Community', + status: 'Live', + description: 'A subscription box for cat lovers and their pets', + website: 'https://cuddleclub.com', + cover: '/apps/cuddleclub-cover.png', + icon: '/apps/cuddleclub-avatar.png', + isPopular: true, + isNew: false, + }, +] diff --git a/apps/hub/src/data/featured-apps.ts b/apps/hub/src/data/featured-apps.ts new file mode 100644 index 000000000..eec5b9efd --- /dev/null +++ b/apps/hub/src/data/featured-apps.ts @@ -0,0 +1,37 @@ +import type { App } from '~/types/app' + +export const featuredApps: App[] = [ + { + id: 1, + name: 'Cat Fishing', + category: 'Community', + status: 'Live', + description: 'You love cats, cats love fish.', + website: 'https://cats.fishing', + twitter: 'catsfishings', + icon: '/apps/cats-fishing-avatar.png', + cover: '/apps/cats-fishing-cover.png', + }, + { + id: 2, + name: 'Status Network Bridge', + category: 'Bridge', + status: 'Live', + description: "Saving for gas? We've got you covered!", + website: 'https://bridge.status.network', + twitter: 'StatusL2', + icon: '/apps/status-network-bridge-avatar.png', + cover: '/apps/status-network-bridge-cover.png', + }, + { + id: 3, + name: 'Hash Vegas', + category: 'Gaming', + status: 'Live', + description: 'Fair and transparent onchain gaming', + website: 'https://hashvegas.casino', + twitter: 'Hashvegas_Offi', + icon: '/apps/hashvegas-avatar.png', + cover: '/apps/hashvegas-cover.png', + }, +] diff --git a/apps/hub/src/types/app.ts b/apps/hub/src/types/app.ts new file mode 100644 index 000000000..8c82825c4 --- /dev/null +++ b/apps/hub/src/types/app.ts @@ -0,0 +1,23 @@ +export type App = { + id: number + name: string + category: string + status: string + description: string + website: string + twitter?: string + cover: string + icon: string + isPopular?: boolean + isNew?: boolean +} + +export type Category = { + id: string + label: string +} + +export type Tab = { + id: 'popular' | 'new' | 'all' + label: string +} diff --git a/apps/hub/tailwind.config.ts b/apps/hub/tailwind.config.ts index 737e118d6..4f68468e6 100644 --- a/apps/hub/tailwind.config.ts +++ b/apps/hub/tailwind.config.ts @@ -160,6 +160,17 @@ export default { 2: '0px 4px 20px rgba(9, 16, 28, 0.08)', 3: '0px 8px 30px rgba(9, 16, 28, 0.12)', }, + + keyframes: { + skeleton: { + '0%, 100%': { backgroundPosition: '0% 50%' }, + '50%': { backgroundPosition: '100% 50%' }, + }, + }, + + animation: { + skeleton: 'skeleton 1.5s ease infinite', + }, }, }, diff --git a/packages/status-network/src/components/button/index.tsx b/packages/status-network/src/components/button/index.tsx index 8932d123a..7251e9514 100644 --- a/packages/status-network/src/components/button/index.tsx +++ b/packages/status-network/src/components/button/index.tsx @@ -3,7 +3,7 @@ import { forwardRef } from 'react' import { cva, cx } from 'cva' type Props = { - variant?: 'primary' | 'secondary' | 'white' + variant?: 'primary' | 'secondary' | 'white' | 'grey' backdropFilter?: boolean children?: React.ReactNode active?: boolean @@ -22,6 +22,7 @@ const buttonStyles = cva({ 'border-white-10 bg-white-5 text-white-100 hover:border-white-20 hover:bg-white-10', white: 'border-neutral-30 bg-white-100 text-dark-100 hover:border-neutral-40 hover:bg-white-80', + grey: 'bg-neutral-10 text-neutral-100 hover:bg-neutral-20 hover:text-neutral-100', }, withIcon: { true: '', @@ -51,6 +52,11 @@ const buttonStyles = cva({ { size: '32', withIcon: true, className: 'pl-3 pr-2' }, { size: '40', withIconBefore: true, className: 'pl-3 pr-4' }, { size: '32', withIconBefore: true, className: 'pl-2 pr-3' }, + { + variant: 'grey', + active: true, + className: 'bg-neutral-50 text-white-100', + }, ], })