cfahlgren1 HF staff commited on
Commit
e9c0734
·
1 Parent(s): 390e277

add categories

Browse files
app/page.tsx CHANGED
@@ -1,15 +1,21 @@
 
1
  import PillLink from '@/components/PillLink';
 
 
2
 
3
  export default function Home() {
4
  return (
5
- <div className="mx-auto p-4 text-center">
6
  <PillLink text="Transformers.js" link="https://www.npmjs.com/package/@xenova/transformers" newText='Powered by' />
7
- <h1 className="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tighter">
8
  Playground
9
  </h1>
10
- <p className="font-bold text-slate-700 mt-4 font-mono italic text-md">
11
  The fastest way to get started with Transformers.js.
12
  </p>
 
 
 
13
  </div>
14
  );
15
- }
 
1
+ "use client"
2
  import PillLink from '@/components/PillLink';
3
+ import CategoryRow from '@/components/CategoryRow';
4
+ import { categories } from "@/lib/categories";
5
 
6
  export default function Home() {
7
  return (
8
+ <div className="container mx-auto px-4 py-8 text-center">
9
  <PillLink text="Transformers.js" link="https://www.npmjs.com/package/@xenova/transformers" newText='Powered by' />
10
+ <h1 className="text-4xl sm:text-5xl md:text-6xl font-extrabold tracking-tighter mb-4">
11
  Playground
12
  </h1>
13
+ <p className="font-bold text-slate-700 font-mono italic text-lg mb-10">
14
  The fastest way to get started with Transformers.js.
15
  </p>
16
+ <div className="mt-24">
17
+ <CategoryRow categories={categories} />
18
+ </div>
19
  </div>
20
  );
21
+ }
components/CategoryCard.tsx ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import type { Category } from '../types/categories';
3
+ import { getColorConfig } from '@/lib/utils';
4
+
5
+ type CategoryCardProps = Category;
6
+
7
+ const CategoryCard: React.FC<CategoryCardProps> = ({
8
+ title,
9
+ icon: Icon,
10
+ colorName,
11
+ description,
12
+ isNew,
13
+ graphic: Graphic
14
+ }) => {
15
+ const { text, gradient, iconBg } = getColorConfig(colorName);
16
+
17
+ return (
18
+ <div className={`bg-gradient-to-br ${gradient} rounded-xl p-4 text-white w-92 h-[380px] flex flex-col relative shadow-lg transition-transform duration-300 ease-in-out hover:scale-105`}>
19
+ {isNew && (
20
+ <div className={`absolute top-2 right-2 ${iconBg} ${text} text-xs font-bold py-1 px-2 rounded-full`}>
21
+ New
22
+ </div>
23
+ )}
24
+ <div className="flex items-center mb-3">
25
+ <div className={`${iconBg} ${text} p-1.5 rounded-full mr-2`}>
26
+ <Icon size={20} />
27
+ </div>
28
+ <h2 className="text-xl font-bold">{title}</h2>
29
+ </div>
30
+ <div className="mb-3 flex-grow">
31
+ <Graphic />
32
+ </div>
33
+ <p className="text-xs mb-3 leading-tight">{description}</p>
34
+ <button className={`w-full bg-white ${text} py-2 px-3 rounded-lg text-sm font-semibold hover:bg-opacity-90 transition-colors mt-auto`}>
35
+ View Tools
36
+ </button>
37
+ </div>
38
+ );
39
+ };
40
+
41
+ export default CategoryCard;
components/CategoryRow.tsx ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { motion } from 'framer-motion';
2
+ import CategoryCard from '@/components/CategoryCard';
3
+ import { Category } from '@/types/categories';
4
+
5
+ interface CategoryRowProps {
6
+ categories: Category[];
7
+ }
8
+
9
+ export default function CategoryRow({ categories }: CategoryRowProps) {
10
+ return (
11
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 sm:gap-12 max-w-5xl mx-auto">
12
+ {categories.map((category, index) => (
13
+ <motion.div
14
+ key={category.title}
15
+ initial={{ opacity: 0, y: 20 }}
16
+ animate={{ opacity: 1, y: 0 }}
17
+ transition={{ duration: 0.5, delay: index * 0.1 }}
18
+ >
19
+ <CategoryCard {...category} />
20
+ </motion.div>
21
+ ))}
22
+ </div>
23
+ );
24
+ }
lib/categories.tsx ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+ import { Scissors, Sparkles, Mic, Smile } from 'lucide-react';
3
+ import type { Category } from '../types/categories';
4
+ import SegmentationIcon from './icons/SegmentationIcon';
5
+ import TranscriptionIcon from './icons/TranscriptionIcon';
6
+ import SentimentAnalysisIcon from './icons/SentimentAnalysisIcon';
7
+ import EmbeddingIcon from './icons/EmbeddingIcon';
8
+
9
+ export const categories: Category[] = [
10
+ {
11
+ title: "Segment",
12
+ icon: Scissors,
13
+ description: "Break down images into distinct segments based on the object or background.",
14
+ isNew: true,
15
+ colorName: "indigo",
16
+ graphic: SegmentationIcon
17
+ },
18
+ {
19
+ title: "Embed",
20
+ icon: Sparkles,
21
+ description: "Create vector embeddings for text and images.",
22
+ colorName: "teal",
23
+ graphic: EmbeddingIcon
24
+ },
25
+ {
26
+ title: "Transcribe",
27
+ icon: Mic,
28
+ description: "Convert speech to text with high accuracy using advanced AI-powered transcription (Whisper).",
29
+ colorName: "rose",
30
+ graphic: TranscriptionIcon
31
+ },
32
+ {
33
+ title: "Sentiment",
34
+ icon: Smile,
35
+ description: "Analyze text to determine the emotional tone and attitude, classifying it as positive, negative, or neutral.",
36
+ colorName: "amber",
37
+ graphic: SentimentAnalysisIcon
38
+ }
39
+ ];
lib/icons/EmbeddingIcon.tsx ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ interface IconProps {
4
+ className?: string;
5
+ }
6
+
7
+ const EmbeddingIcon: React.FC<IconProps> = ({ className = '' }) => {
8
+ return (
9
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" className={`w-full h-auto max-h-28 ${className}`}>
10
+ <rect x="0" y="0" width="200" height="100" fill="#5eead4" rx="10" ry="10" />
11
+
12
+ {/* Text representation */}
13
+ <rect x="10" y="10" width="80" height="80" fill="#f0fdfa" stroke="#fff" strokeWidth="1" rx="5" ry="5" />
14
+ <text x="20" y="40" fill="#f472b6" fontSize="14" fontWeight="bold">Hello</text>
15
+ <text x="20" y="70" fill="#60a5fa" fontSize="14" fontWeight="bold">World</text>
16
+
17
+ {/* Arrow */}
18
+ <line x1="95" y1="50" x2="105" y2="50" stroke="#fff" strokeWidth="2" />
19
+ <polygon points="105,46 113,50 105,54" fill="#fff" />
20
+
21
+ {/* 3D space representation */}
22
+ <rect x="110" y="10" width="80" height="80" fill="#f0fdfa" stroke="#fff" strokeWidth="1" rx="5" ry="5" />
23
+
24
+ {/* 3D axes */}
25
+ <line x1="115" y1="85" x2="185" y2="85" stroke="#0f766e" strokeWidth="1" opacity="0.5" />
26
+ <line x1="115" y1="85" x2="115" y2="15" stroke="#0f766e" strokeWidth="1" opacity="0.5" />
27
+ <line x1="115" y1="85" x2="145" y2="65" stroke="#0f766e" strokeWidth="1" opacity="0.5" />
28
+
29
+ {/* 3D points */}
30
+ <circle cx="150" cy="40" r="4" fill="#f472b6" />
31
+ <text x="157" y="44" fill="#f472b6" fontSize="10" fontWeight="bold">Hello</text>
32
+ <circle cx="155" cy="70" r="4" fill="#60a5fa" />
33
+ <text x="120" y="74" fill="#60a5fa" fontSize="10" fontWeight="bold">World</text>
34
+ </svg>
35
+ );
36
+ };
37
+
38
+ export default EmbeddingIcon;
lib/icons/SegmentationIcon.tsx ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ interface IconProps {
4
+ className?: string;
5
+ }
6
+
7
+ const SegmentationIcon: React.FC<IconProps> = ({ className = '' }) => {
8
+ return (
9
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" className={`w-full h-auto max-h-28 ${className}`}>
10
+ <rect x="0" y="0" width="200" height="100" fill="#818cf8" rx="10" ry="10" />
11
+
12
+ {/* Original Image */}
13
+ <rect x="10" y="10" width="80" height="80" fill="#e0e0e0" stroke="#fff" strokeWidth="1" rx="5" ry="5" />
14
+ <circle cx="35" cy="35" r="15" fill="#fbbf24" />
15
+ <rect x="55" y="45" width="25" height="35" fill="#34d399" />
16
+
17
+ {/* Arrow */}
18
+ <line x1="95" y1="50" x2="105" y2="50" stroke="#fff" strokeWidth="2" />
19
+ <polygon points="105,46 113,50 105,54" fill="#fff" />
20
+
21
+ {/* Segmented Image */}
22
+ <rect x="110" y="10" width="80" height="80" fill="#e0e0e0" stroke="#fff" strokeWidth="1" rx="5" ry="5" />
23
+ <circle cx="135" cy="35" r="15" fill="#fbbf24" stroke="#e11d48" strokeWidth="2" strokeDasharray="4 2" />
24
+ <rect x="155" y="45" width="25" height="35" fill="#34d399" stroke="#e11d48" strokeWidth="2" strokeDasharray="4 2" />
25
+ </svg>
26
+ );
27
+ };
28
+
29
+ export default SegmentationIcon;
lib/icons/SentimentAnalysisIcon.tsx ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ interface IconProps {
4
+ className?: string;
5
+ }
6
+
7
+ const SentimentAnalysisIcon: React.FC<IconProps> = ({ className = '' }) => {
8
+ return (
9
+ <svg
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ viewBox="0 0 200 100"
12
+ className={`w-full h-auto max-h-28 ${className}`}
13
+ >
14
+ <rect x="0" y="0" width="200" height="100" fill="#fbbf24" rx="10" ry="10" />
15
+
16
+ {/* Input text */}
17
+ <rect x="10" y="10" width="80" height="80" fill="#fffbeb" stroke="#fff" strokeWidth="1" rx="5" ry="5" />
18
+ <text x="15" y="35" fill="#92400e" fontSize="8" fontWeight="bold">Great product!</text>
19
+ <text x="15" y="50" fill="#92400e" fontSize="8" fontWeight="bold">Highly</text>
20
+ <text x="15" y="65" fill="#92400e" fontSize="8" fontWeight="bold">recommended.</text>
21
+
22
+ {/* Arrow */}
23
+ <line x1="95" y1="50" x2="105" y2="50" stroke="#fff" strokeWidth="2" />
24
+ <polygon points="105,46 113,50 105,54" fill="#fff" />
25
+
26
+ {/* Sentiment analysis result */}
27
+ <rect x="110" y="10" width="80" height="80" fill="#fffbeb" stroke="#fff" strokeWidth="1" rx="5" ry="5" />
28
+ <circle cx="150" cy="50" r="22" fill="#4ade80" />
29
+ <path d="M140 50 Q 150 60, 160 50" fill="none" stroke="#fffbeb" strokeWidth="2" />
30
+ <circle cx="143" cy="43" r="2" fill="#fffbeb" />
31
+ <circle cx="157" cy="43" r="2" fill="#fffbeb" />
32
+ </svg>
33
+ );
34
+ };
35
+
36
+ export default SentimentAnalysisIcon;
lib/icons/TranscriptionIcon.tsx ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+
3
+ interface TranscriptionIconProps {
4
+ className?: string;
5
+ }
6
+
7
+ const TranscriptionIcon: React.FC<TranscriptionIconProps> = ({ className = '' }) => {
8
+ return (
9
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" className={`w-full h-auto max-h-28 ${className}`}>
10
+ <rect x="0" y="0" width="200" height="100" fill="#fb7185" rx="10" ry="10" />
11
+
12
+ {/* Audio waveform */}
13
+ <rect x="10" y="10" width="80" height="80" fill="#fff1f2" stroke="#fff" strokeWidth="1" rx="5" ry="5" />
14
+ <path d="M15 50 Q 25 20, 35 50 Q 45 80, 55 50 Q 65 20, 75 50 Q 85 80, 95 50"
15
+ fill="none" stroke="#e11d48" strokeWidth="2" />
16
+
17
+ {/* Arrow */}
18
+ <line x1="95" y1="50" x2="105" y2="50" stroke="#fff" strokeWidth="2" />
19
+ <polygon points="105,46 113,50 105,54" fill="#fff" />
20
+
21
+ {/* Transcribed text */}
22
+ <rect x="110" y="10" width="80" height="80" fill="#fff1f2" stroke="#fff" strokeWidth="1" rx="5" ry="5" />
23
+ <text x="120" y="30" fill="#be123c" fontSize="10" fontWeight="bold">Hello, how</text>
24
+ <text x="120" y="45" fill="#be123c" fontSize="10" fontWeight="bold">are you</text>
25
+ <text x="120" y="60" fill="#be123c" fontSize="10" fontWeight="bold">today?</text>
26
+ <line x1="120" y1="70" x2="180" y2="70" stroke="#fda4af" strokeWidth="1" />
27
+ <line x1="120" y1="80" x2="170" y2="80" stroke="#fda4af" strokeWidth="1" />
28
+ </svg>
29
+ );
30
+ };
31
+
32
+ export default TranscriptionIcon;
lib/utils.ts CHANGED
@@ -4,3 +4,46 @@ import { twMerge } from "tailwind-merge"
4
  export function cn(...inputs: ClassValue[]) {
5
  return twMerge(clsx(inputs))
6
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  export function cn(...inputs: ClassValue[]) {
5
  return twMerge(clsx(inputs))
6
  }
7
+
8
+ export type ColorConfig = {
9
+ bg: string;
10
+ text: string;
11
+ gradient: string;
12
+ iconBg: string;
13
+ };
14
+
15
+ export const colorConfigs: Record<string, ColorConfig> = {
16
+ indigo: {
17
+ bg: 'bg-indigo-200',
18
+ text: 'text-indigo-800',
19
+ gradient: 'from-indigo-500 to-indigo-700',
20
+ iconBg: 'bg-indigo-200',
21
+ },
22
+ teal: {
23
+ bg: 'bg-teal-200',
24
+ text: 'text-teal-800',
25
+ gradient: 'from-teal-500 to-teal-700',
26
+ iconBg: 'bg-teal-200',
27
+ },
28
+ rose: {
29
+ bg: 'bg-rose-200',
30
+ text: 'text-rose-800',
31
+ gradient: 'from-rose-500 to-rose-700',
32
+ iconBg: 'bg-rose-200',
33
+ },
34
+ amber: {
35
+ bg: 'bg-amber-200',
36
+ text: 'text-amber-800',
37
+ gradient: 'from-amber-500 to-amber-700',
38
+ iconBg: 'bg-amber-200',
39
+ },
40
+ };
41
+
42
+ export const getColorConfig = (colorName: string): ColorConfig => {
43
+ return colorConfigs[colorName] || {
44
+ bg: 'bg-gray-200',
45
+ text: 'text-gray-800',
46
+ gradient: 'from-gray-500 to-gray-700',
47
+ iconBg: 'bg-gray-200',
48
+ };
49
+ };
package-lock.json CHANGED
@@ -14,6 +14,7 @@
14
  "class-variance-authority": "^0.7.0",
15
  "clsx": "^2.1.1",
16
  "cmdk": "^1.0.0",
 
17
  "lucide-react": "^0.451.0",
18
  "next": "14.2.15",
19
  "react": "^18",
@@ -3054,6 +3055,31 @@
3054
  "url": "https://github.com/sponsors/isaacs"
3055
  }
3056
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3057
  "node_modules/fs.realpath": {
3058
  "version": "1.0.0",
3059
  "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
 
14
  "class-variance-authority": "^0.7.0",
15
  "clsx": "^2.1.1",
16
  "cmdk": "^1.0.0",
17
+ "framer-motion": "^11.11.7",
18
  "lucide-react": "^0.451.0",
19
  "next": "14.2.15",
20
  "react": "^18",
 
3055
  "url": "https://github.com/sponsors/isaacs"
3056
  }
3057
  },
3058
+ "node_modules/framer-motion": {
3059
+ "version": "11.11.7",
3060
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.11.7.tgz",
3061
+ "integrity": "sha512-89CgILOXPeG3L7ymOTGrLmf8IiKubYLUN/QkYgQuLvehAHfqgwJbLfCnhuyRI4WTds1TXkUp67A7IJrgRY/j1w==",
3062
+ "license": "MIT",
3063
+ "dependencies": {
3064
+ "tslib": "^2.4.0"
3065
+ },
3066
+ "peerDependencies": {
3067
+ "@emotion/is-prop-valid": "*",
3068
+ "react": "^18.0.0",
3069
+ "react-dom": "^18.0.0"
3070
+ },
3071
+ "peerDependenciesMeta": {
3072
+ "@emotion/is-prop-valid": {
3073
+ "optional": true
3074
+ },
3075
+ "react": {
3076
+ "optional": true
3077
+ },
3078
+ "react-dom": {
3079
+ "optional": true
3080
+ }
3081
+ }
3082
+ },
3083
  "node_modules/fs.realpath": {
3084
  "version": "1.0.0",
3085
  "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
package.json CHANGED
@@ -15,6 +15,7 @@
15
  "class-variance-authority": "^0.7.0",
16
  "clsx": "^2.1.1",
17
  "cmdk": "^1.0.0",
 
18
  "lucide-react": "^0.451.0",
19
  "next": "14.2.15",
20
  "react": "^18",
 
15
  "class-variance-authority": "^0.7.0",
16
  "clsx": "^2.1.1",
17
  "cmdk": "^1.0.0",
18
+ "framer-motion": "^11.11.7",
19
  "lucide-react": "^0.451.0",
20
  "next": "14.2.15",
21
  "react": "^18",
types/categories.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { LucideIcon } from 'lucide-react';
2
+
3
+ export interface Category {
4
+ title: string;
5
+ icon: LucideIcon;
6
+ description: string;
7
+ isNew?: boolean;
8
+ colorName: string;
9
+ graphic: React.ComponentType<React.SVGProps<SVGSVGElement>>;
10
+ };