diff --git a/.DS_Store b/.DS_Store
index 0fb5f74..35a3b20 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..ac47ff6
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,61 @@
+name: Deploy to GitHub Pages
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 8
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'pnpm'
+
+ - name: Install dependencies
+ run: pnpm install
+
+ - name: Build
+ run: pnpm build
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: './out'
+
+ deploy:
+ environment:
+ name: github-pages
+ url: https://www.dash-ai.com/
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
+
diff --git a/.gitignore b/.gitignore
index 0e4802d..b0d93fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,47 @@
-*.DS_Store
+__pycache__
+
+
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+.yarn/install-state.gz
+
+# testing
+/coverage
+
+# next.js
+frontend/.next/
+frontend/node_modules
+.next/
+/out/
+
+# production
+/build
+
+# misc
.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env*.local
+.env
+backend/.env
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
+
+backend/data/new_docs_test
+.next
+.vscode
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..538d1cf
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,17 @@
+FROM node:20.16.0-bullseye-slim
+
+# Instalar pnpm
+RUN npm install -g pnpm
+
+WORKDIR /app
+
+# Copiar archivos de dependencias
+COPY package.json pnpm-lock.yaml ./
+
+# Instalar dependencias con pnpm
+RUN pnpm install
+COPY . .
+
+#RUN pnpm run build
+
+CMD ["pnpm", "run", "dev"]
diff --git a/app/globals.css b/app/globals.css
new file mode 100644
index 0000000..1f0dab6
--- /dev/null
+++ b/app/globals.css
@@ -0,0 +1,124 @@
+@import "tailwindcss";
+@import "tw-animate-css";
+
+@custom-variant dark (&:is(.dark *));
+
+:root {
+ --background: oklch(0.98 0 0);
+ --foreground: oklch(0.98 0 0);
+ --card: oklch(0.12 0 0);
+ --card-foreground: oklch(0.98 0 0);
+ --popover: oklch(0.12 0 0);
+ --popover-foreground: oklch(0.98 0 0);
+ --primary: oklch(0.75 0.18 195);
+ --primary-foreground: oklch(0.1 0 0);
+ --secondary: oklch(0.28 0 0);
+ --secondary-foreground: oklch(0.98 0 0);
+ --muted: oklch(0.22 0 0);
+ --muted-foreground: oklch(0.65 0 0);
+ --accent: oklch(0.65 0.18 45);
+ --accent-foreground: oklch(0.1 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --destructive-foreground: oklch(0.985 0 0);
+ --border: oklch(0.28 0 0);
+ --input: oklch(0.28 0 0);
+ --ring: oklch(0.75 0.18 195);
+ --chart-1: oklch(0.75 0.18 195);
+ --chart-2: oklch(0.65 0.18 45);
+ --chart-3: oklch(0.6 0.15 240);
+ --chart-4: oklch(0.7 0.15 280);
+ --chart-5: oklch(0.55 0.12 210);
+ --radius: 0.75rem;
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
+}
+
+.dark {
+ --background: oklch(0.08 0 0);
+ --foreground: oklch(0.98 0 0);
+ --card: oklch(0.12 0 0);
+ --card-foreground: oklch(0.98 0 0);
+ --popover: oklch(0.12 0 0);
+ --popover-foreground: oklch(0.98 0 0);
+ --primary: oklch(0.75 0.18 195);
+ --primary-foreground: oklch(0.1 0 0);
+ --secondary: oklch(0.28 0 0);
+ --secondary-foreground: oklch(0.98 0 0);
+ --muted: oklch(0.22 0 0);
+ --muted-foreground: oklch(0.65 0 0);
+ --accent: oklch(0.65 0.18 45);
+ --accent-foreground: oklch(0.1 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --destructive-foreground: oklch(0.985 0 0);
+ --border: oklch(0.28 0 0);
+ --input: oklch(0.28 0 0);
+ --ring: oklch(0.75 0.18 195);
+ --chart-1: oklch(0.75 0.18 195);
+ --chart-2: oklch(0.65 0.18 45);
+ --chart-3: oklch(0.6 0.15 240);
+ --chart-4: oklch(0.7 0.15 280);
+ --chart-5: oklch(0.55 0.12 210);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(0.269 0 0);
+ --sidebar-ring: oklch(0.439 0 0);
+}
+
+@theme inline {
+ /* optional: --font-sans, --font-serif, --font-mono if they are applied in the layout.tsx */
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-destructive-foreground: var(--destructive-foreground);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/app/layout.tsx b/app/layout.tsx
new file mode 100644
index 0000000..070369f
--- /dev/null
+++ b/app/layout.tsx
@@ -0,0 +1,43 @@
+import type React from "react"
+import type { Metadata } from "next"
+import { Geist, Geist_Mono } from "next/font/google"
+import { Analytics } from "@vercel/analytics/next"
+import "./globals.css"
+
+const _geist = Geist({ subsets: ["latin"] })
+const _geistMono = Geist_Mono({ subsets: ["latin"] })
+
+export const metadata: Metadata = {
+ title: "DashAI - Plataforma Open Source de IA",
+ description:
+ "Integra, experimenta y visualiza modelos de IA mediante una interfaz visual intuitiva. Democratizando el acceso al machine learning.",
+ generator: "v0.app",
+ icons: {
+ icon: [
+ {
+ url: "/icon-light-32x32.png",
+ media: "(prefers-color-scheme: light)",
+ },
+ {
+ url: "/icon-dark-32x32.png",
+ media: "(prefers-color-scheme: dark)",
+ },
+ ],
+ apple: "/apple-icon.png",
+ },
+}
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode
+}>) {
+ return (
+
+
+ {children}
+
+
+
+ )
+}
diff --git a/app/page.tsx b/app/page.tsx
new file mode 100644
index 0000000..805f9f3
--- /dev/null
+++ b/app/page.tsx
@@ -0,0 +1,24 @@
+import { Navbar } from "@/components/navbar"
+import { HeroSection } from "@/components/hero-section"
+import { FeaturesSection } from "@/components/features-section"
+//import { ModulesCarousel } from "@/components/modules-carousel"
+import { DownloadSection } from "@/components/download-section"
+import { SupportedBySection } from "@/components/supported-by-section"
+import { CommunitySection } from "@/components/community-section"
+import { ContactSection } from "@/components/contact-section"
+import { Footer } from "@/components/footer"
+
+export default function Home() {
+ return (
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/components.json b/components.json
new file mode 100644
index 0000000..4ee62ee
--- /dev/null
+++ b/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "app/globals.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
diff --git a/components/community-section.tsx b/components/community-section.tsx
new file mode 100644
index 0000000..2f3c559
--- /dev/null
+++ b/components/community-section.tsx
@@ -0,0 +1,110 @@
+"use client"
+
+import { Button } from "@/components/ui/button"
+import { Card, CardContent } from "@/components/ui/card"
+import { Github, BookOpen, Code2, Package } from "lucide-react"
+import { siteConfig } from "@/lib/config"
+
+const communityLinks = [
+ {
+ icon: Github,
+ title: "GitHub",
+ description: "Explore the source code",
+ link: siteConfig.github.url,
+ // stats: "2.5k stars",
+ },
+ // {
+ // icon: Package,
+ // title: "Plugin Hub",
+ // description: "Browse community plugins",
+ // link: siteConfig.resources.pluginHub,
+ // // stats: "100+ plugins",
+ // },
+ {
+ icon: BookOpen,
+ title: "Docs",
+ description: "Visit the technical documentation",
+ link: siteConfig.docs.url,
+ // stats: "Complete guides",
+ },
+ {
+ icon: Code2,
+ title: "Contribute",
+ description: "Improve the project",
+ link: siteConfig.github.contribute,
+ // stats: "Open to all",
+ },
+]
+
+export function CommunitySection() {
+ return (
+
+ )
+}
diff --git a/components/contact-section.tsx b/components/contact-section.tsx
new file mode 100644
index 0000000..4bce56c
--- /dev/null
+++ b/components/contact-section.tsx
@@ -0,0 +1,137 @@
+'use client'
+
+import { useState } from 'react'
+import { Button } from '@/components/ui/button'
+
+export function ContactSection() {
+ const [formData, setFormData] = useState({
+ name: '',
+ email: '',
+ message: '',
+ })
+ const [status, setStatus] = useState<'idle' | 'sending' | 'success' | 'error'>('idle')
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault()
+ setStatus('sending')
+
+ try {
+ const formPayload = {
+ name: formData.name,
+ email: formData.email,
+ message: formData.message,
+ _subject: `Nuevo mensaje de contacto de DashAI - ${formData.name}`,
+ }
+
+ console.log('Sending form data:', formPayload)
+
+ const response = await fetch(`https://formspree.io/f/mnnwakle`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ },
+ body: JSON.stringify(formPayload),
+ })
+
+ const responseData = await response.json()
+ console.log('Formspree response:', response.status, responseData)
+
+ if (response.ok) {
+ setStatus('success')
+ setFormData({ name: '', email: '', message: '' })
+ setTimeout(() => setStatus('idle'), 5000)
+ } else {
+ // Mostrar error más específico
+ const errorMessage = responseData.error || responseData.message || 'Error al enviar el mensaje'
+ console.error('Formspree error:', responseData)
+ setStatus('error')
+ setTimeout(() => setStatus('idle'), 5000)
+ }
+ } catch (error) {
+ console.error('Form submission error:', error)
+ setStatus('error')
+ setTimeout(() => setStatus('idle'), 3000)
+ }
+ }
+
+ const handleChange = (e: React.ChangeEvent) => {
+ setFormData(prev => ({
+ ...prev,
+ [e.target.name]: e.target.value
+ }))
+ }
+
+ return (
+
+ )
+}
diff --git a/components/download-section.tsx b/components/download-section.tsx
new file mode 100644
index 0000000..bf8d8f4
--- /dev/null
+++ b/components/download-section.tsx
@@ -0,0 +1,107 @@
+import { Button } from "@/components/ui/button"
+import { Card, CardContent } from "@/components/ui/card"
+import { Download, Terminal, Package } from "lucide-react"
+
+const downloads = [
+ {
+ icon: Package,
+ platform: "macOS Intel processors",
+ version: "v0.1.15",
+ size: "487 MB",
+ format: "binary",
+ link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu-x86_64",
+ },
+ {
+ icon: Package,
+ platform: "macOS ARM processors",
+ version: "v0.1.15",
+ size: "381 MB",
+ format: "binary",
+ link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu-arm64",
+ },
+ {
+ icon: Package,
+ platform: "Windows",
+ version: "v0.1.15",
+ size: "434 MB",
+ format: ".exe",
+ link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu.exe",
+ },
+ // {
+ // icon: Package,
+ // platform: "Docker",
+ // version: "latest",
+ // size: "~300 MB",
+ // format: "container",
+ // link: "#",
+ // },
+]
+
+export function DownloadSection() {
+ return (
+
+
+
+
Download DashAI
+
Beta Version
+
+ This early version lets you explore DashAI’s main features. We appreciate your feedback to help us improve before the official release.
+
+
+
+
+
+ {downloads.map((download, index) => {
+ const Icon = download.icon
+ return (
+
+
+
+
+
+ {download.platform}
+
+
+ {download.version} • {download.size}
+
+
{download.format}
+
+
+
+
+ Download
+
+
+
+
+ )
+ })}
+
+
+
+
+
+
+
Install via pip
+
For developers who prefer command-line installation
+
+
+
+ pip install dashai
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/components/features-section-old.tsx b/components/features-section-old.tsx
new file mode 100644
index 0000000..6f4a357
--- /dev/null
+++ b/components/features-section-old.tsx
@@ -0,0 +1,76 @@
+import { Card, CardContent } from "@/components/ui/card"
+import { Layers, Zap, Eye, Users, Code2, Puzzle } from "lucide-react"
+
+const features = [
+ {
+ icon: Puzzle,
+ title: "Plugin System",
+ description:
+ "Extensible architecture that allows the community to create and share plugins, expanding platform capabilities.",
+ },
+ {
+ icon: Layers,
+ title: "Modular Integration",
+ description: "Connect multiple AI models from different providers in a single unified platform.",
+ },
+ {
+ icon: Zap,
+ title: "Rapid Experimentation",
+ description: "Test different configurations and parameters in real-time without writing code.",
+ },
+ {
+ icon: Eye,
+ title: "Advanced Visualization",
+ description: "Visualize results, metrics, and model comparisons in a clear and intuitive way.",
+ },
+ {
+ icon: Users,
+ title: "For Everyone",
+ description: "Designed for both expert developers and users without technical experience.",
+ },
+ {
+ icon: Code2,
+ title: "Complete API",
+ description: "Access all functionalities through a documented and easy-to-use REST API.",
+ },
+ // {
+ // icon: Users,
+ // title: "Open Source",
+ // description: "100% open code, auditable and extensible. Contribute plugins and core improvements.",
+ // },
+]
+
+export function FeaturesSection() {
+ return (
+
+
+
+
{"Democratizing access to AI"}
+
+ {"A complete platform that eliminates barriers to entry into the world of machine learning"}
+
+
+
+
+ {features.map((feature, index) => {
+ const Icon = feature.icon
+ return (
+
+
+
+
+
+ {feature.title}
+ {feature.description}
+
+
+ )
+ })}
+
+
+
+ )
+}
diff --git a/components/features-section.tsx b/components/features-section.tsx
new file mode 100644
index 0000000..c6edc15
--- /dev/null
+++ b/components/features-section.tsx
@@ -0,0 +1,139 @@
+"use client"
+
+import { useEffect, useRef, useState } from "react"
+import { ChevronLeft, ChevronRight } from "lucide-react"
+import { Button } from "@/components/ui/button"
+
+const features = [
+ {
+ id: 1,
+ title: "Data Explorer",
+ description:
+ "Explore, clean, and prepare your data in an intuitive visual environment: perform dynamic, visual, and guided exploratory data analyses (EDA) directly within DashAI.",
+ image: "features/eda_module.png",
+ features: [
+ "Manage all your datasets in one place",
+ "Apply different conversions to your datasets easily",
+ "Generate customizable charts",
+ ],
+ },
+ {
+ id: 2,
+ title: "ML Experimentation",
+ description:
+ "Set up and manage your ML experiments with an intuitive interface. Select models, configure its hyperparameters, and define evaluation metrics without writing a single line of code.",
+ image: "features/ml_experimentation.png",
+ features: ["Model selection by task", "Experiment tracking", "One-click experiment runs"],
+ },
+ {
+ id: 3,
+ title: "Results Visualization",
+ description:
+ "Compare model performance across multiple experiments. Interactive dashboards help you identify the best performing models and understand their behavior through comprehensive metrics and visualizations.",
+ image: "features/results.png",
+ features: ["Performance comparison", "Interactive dashboards", "Custom visualizations"],
+ },
+ {
+ id: 4,
+ title: "Model Explanability",
+ description:
+ "Understand how your models make decisions. Generate feature importance plots, SHAP values, and interpretable visualizations that help you trust and debug your AI models.",
+ image: "features/explainability_module.png",
+ features: [
+ "Visual Explanations",
+ "Global y Local explicadores",
+ "Model inspection and analysis"
+ ],
+ },
+ {
+ id: 5,
+ title: "Generative Module",
+ description:
+ "Experiment with generative AI models seamlessly. Generate text, images, and other content while visualizing the generation process and fine-tuning parameters in real-time.",
+ image: "features/generative_module.png",
+ features: ["Multi-modal generation", "Real-time preview", "Parameter control"],
+ },
+]
+
+export function FeaturesSection() {
+ const [visibleFeatures, setVisibleFeatures] = useState>(new Set())
+ const featureRefs = useRef<(HTMLDivElement | null)[]>([])
+
+ useEffect(() => {
+ const observers = featureRefs.current.map((ref, index) => {
+ if (!ref) return null
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ setVisibleFeatures((prev) => new Set(prev).add(index))
+ }
+ })
+ },
+ { threshold: 0.2 }
+ )
+
+ observer.observe(ref)
+ return observer
+ })
+
+ return () => {
+ observers.forEach((observer) => observer?.disconnect())
+ }
+ }, [])
+
+ return (
+
+
+
+
+ Powerful Features
+
+
+ Discover the powerful features that make DashAI the ultimate platform for AI experimentation
+
+
+
+
+ {features.map((feature, index) => {
+ const isEven = index % 2 === 0
+ const isVisible = visibleFeatures.has(index)
+
+ return (
+
{
+ featureRefs.current[index] = el
+ }}
+ className={`flex flex-col ${
+ isEven ? "lg:flex-row" : "lg:flex-row-reverse"
+ } gap-12 items-center transition-all duration-1000 ${
+ isVisible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-12"
+ }`}
+ >
+
+
{feature.title}
+
+ {feature.description}
+
+
+
+
+
+
+
+
+
+
+ )
+ })}
+
+
+
+ )
+}
diff --git a/components/footer.tsx b/components/footer.tsx
new file mode 100644
index 0000000..5525f29
--- /dev/null
+++ b/components/footer.tsx
@@ -0,0 +1,109 @@
+import { Github, Twitter, Linkedin } from "lucide-react"
+import { siteConfig } from "@/lib/config"
+
+export function Footer() {
+ return (
+
+
+
+
+
DashAI
+
+ {"Open source platform to democratize access to artificial intelligence."}
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/components/hero-section.tsx b/components/hero-section.tsx
new file mode 100644
index 0000000..dd187bb
--- /dev/null
+++ b/components/hero-section.tsx
@@ -0,0 +1,99 @@
+"use client"
+
+import { Button } from "@/components/ui/button"
+import { Github, BookOpen, Download } from "lucide-react"
+import Image from "next/image"
+import { siteConfig } from "@/lib/config"
+
+export function HeroSection() {
+ const scrollToSection = (id: string) => {
+ const element = document.getElementById(id)
+ if (element) {
+ element.scrollIntoView({ behavior: "smooth" })
+ }
+ }
+ return (
+
+ {/* Decorative lines background */}
+
+
+
+
+
+
+
+
+
+ {"The "}
+ open source
+ {" platform for AI experimentation"}
+
+
+
+ {
+ "Integrate, experiment, and visualize AI model results through an intuitive visual interface. Built with an extensible plugin architecture for limitless customization."
+ }
+
+
+
+
+ {/*
+
+
+
{"100% Open Source"}
+
+
+
+
{"No complex setup"}
+
+
*/}
+
+
+
+ )
+}
diff --git a/components/modules-carousel.tsx b/components/modules-carousel.tsx
new file mode 100644
index 0000000..6bb555f
--- /dev/null
+++ b/components/modules-carousel.tsx
@@ -0,0 +1,203 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { ChevronLeft, ChevronRight } from "lucide-react"
+import { Button } from "@/components/ui/button"
+
+const modules = [
+ {
+ id: 1,
+ title: "Data Explorer",
+ description:
+ "Explore, clean, and prepare your data in an intuitive visual environment: perform dynamic, visual, and guided exploratory data analyses (EDA) directly within DashAI.",
+ image: "/exploratory-data-analysis-dashboard-with-charts-an.jpg",
+ features: [
+ "Manage all your datasets in one place",
+ "Apply different conversions to your datasets easily",
+ "Generate customizable charts",
+ ],
+ },
+ {
+ id: 2,
+ title: "ML Experimentation",
+ description:
+ "Set up and manage your ML experiments with an intuitive interface. Select models, configure its hyperparameters, and define evaluation metrics without writing a single line of code.",
+ image: "/config_param_600h.png",
+ features: ["Model selection by task", "Experiment tracking", "One-click experiment runs"],
+ },
+ {
+ id: 3,
+ title: "Results Visualization",
+ description:
+ "Compare model performance across multiple experiments. Interactive dashboards help you identify the best performing models and understand their behavior through comprehensive metrics and visualizations.",
+ image: "/results-1200w.png",
+ features: ["Performance comparison", "Interactive dashboards", "Custom visualizations"],
+ },
+ {
+ id: 4,
+ title: "Model Explanability",
+ description:
+ "Understand how your models make decisions. Generate feature importance plots, SHAP values, and interpretable visualizations that help you trust and debug your AI models.",
+ image: "/ai-model-explainability-interface-with-shap-values.jpg",
+ features: [
+ "Visual Explanations",
+ "Global y Local explicadores",
+ "Model inspection and analysis"
+ ],
+ },
+ {
+ id: 5,
+ title: "Generative Module",
+ description:
+ "Experiment with generative AI models seamlessly. Generate text, images, and other content while visualizing the generation process and fine-tuning parameters in real-time.",
+ image: "/generative-ai-interface-with-text-and-image-genera.jpg",
+ features: ["Multi-modal generation", "Real-time preview", "Parameter control"],
+ },
+]
+
+export function ModulesCarousel() {
+ const [currentIndex, setCurrentIndex] = useState(0)
+ const [activeButton, setActiveButton] = useState<"previous" | "next" | null>(null)
+
+ const goToPrevious = () => {
+ setActiveButton("previous")
+ setCurrentIndex((prevIndex) => (prevIndex === 0 ? modules.length - 1 : prevIndex - 1))
+ }
+
+ const goToNext = () => {
+ setActiveButton("next")
+ setCurrentIndex((prevIndex) => (prevIndex === modules.length - 1 ? 0 : prevIndex + 1))
+ }
+
+ const goToSlide = (index: number) => {
+ setCurrentIndex(index)
+ }
+
+ useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === "ArrowLeft") {
+ setActiveButton("previous")
+ setCurrentIndex((prevIndex) => (prevIndex === 0 ? modules.length - 1 : prevIndex - 1))
+ } else if (event.key === "ArrowRight") {
+ setActiveButton("next")
+ setCurrentIndex((prevIndex) => (prevIndex === modules.length - 1 ? 0 : prevIndex + 1))
+ }
+ }
+
+ window.addEventListener("keydown", handleKeyDown)
+ return () => {
+ window.removeEventListener("keydown", handleKeyDown)
+ }
+ }, [])
+
+ // Reset active button after 0.5 seconds
+ useEffect(() => {
+ if (activeButton) {
+ const timer = setTimeout(() => {
+ setActiveButton(null)
+ }, 200)
+ return () => clearTimeout(timer)
+ }
+ }, [activeButton])
+
+ const currentModule = modules[currentIndex]
+
+ return (
+
+
+
+
+ Powerful Features
+
+
+ Discover the powerful features that make DashAI the ultimate platform for AI experimentation
+
+
+
+
+ {/* Main carousel content */}
+
+
+ {/* Image side */}
+
+
+
+
+
+ {/* Content side */}
+
+ {/* Fixed header section */}
+
+
+ Feature {currentModule.id} of {modules.length}
+
+
{currentModule.title}
+
+
+ {/* Content section - auto height on mobile, scrollable on desktop */}
+
+
{currentModule.description}
+
+ {currentModule.features.map((feature, idx) => (
+
+ ))}
+
+
+
+ {/* Fixed navigation buttons */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Dots indicator */}
+
+ {modules.map((_, index) => (
+ goToSlide(index)}
+ className={`h-2 rounded-full transition-all duration-300 ${
+ index === currentIndex ? "w-8 bg-cyan-400" : "w-2 bg-gray-600 hover:bg-gray-500"
+ }`}
+ aria-label={`Go to slide ${index + 1}`}
+ />
+ ))}
+
+
+
+
+ )
+}
diff --git a/components/modules-section.tsx b/components/modules-section.tsx
new file mode 100644
index 0000000..a0896e6
--- /dev/null
+++ b/components/modules-section.tsx
@@ -0,0 +1,101 @@
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
+import { Brain, LineChart, Boxes, Workflow, Puzzle } from "lucide-react"
+
+const modules = [
+ {
+ icon: Brain,
+ title: "Model Hub",
+ description: "Model management system",
+ features: [
+ "Import models from Hugging Face, OpenAI, and more",
+ "Automatic model versioning",
+ "Performance comparison",
+ "Real-time metrics",
+ ],
+ },
+ {
+ icon: Workflow,
+ title: "Workflow Builder",
+ description: "Visual pipeline constructor",
+ features: [
+ "Intuitive drag-and-drop interface",
+ "Pre-built connectors",
+ "Parallel task execution",
+ "Integrated visual debugging",
+ ],
+ },
+ {
+ icon: LineChart,
+ title: "Analytics Dashboard",
+ description: "Advanced analytics panel",
+ features: ["Interactive results charts", "Data and report exports", "A/B model comparison", "Cost monitoring"],
+ },
+ {
+ icon: Boxes,
+ title: "Experiment Manager",
+ description: "Experiment management",
+ features: [
+ "Automatic experiment tracking",
+ "Guaranteed reproducibility",
+ "Dataset management",
+ "Team collaboration",
+ ],
+ },
+ {
+ icon: Puzzle,
+ title: "Plugin Architecture",
+ description: "Extensible plugin system",
+ features: [
+ "Create custom plugins with ease",
+ "Hot-reload plugin development",
+ "Secure plugin sandboxing",
+ "Community plugin marketplace",
+ ],
+ },
+]
+
+export function ModulesSection() {
+ return (
+
+
+
+
{"Powerful modules, easy to use"}
+
+ {"Each module is designed to solve specific problems in your ML workflow"}
+
+
+
+
+ {modules.map((module, index) => {
+ const Icon = module.icon
+ return (
+
+
+
+
+
+
+
+ {module.title}
+ {module.description}
+
+
+
+
+
+ {module.features.map((feature, idx) => (
+
+
+ {feature}
+
+ ))}
+
+
+
+ )
+ })}
+
+
+
+ )
+}
diff --git a/components/navbar.tsx b/components/navbar.tsx
new file mode 100644
index 0000000..a9a99be
--- /dev/null
+++ b/components/navbar.tsx
@@ -0,0 +1,160 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { Button } from "@/components/ui/button"
+import { Download, Github, Menu, X } from "lucide-react"
+import Image from "next/image"
+import { cn } from "@/lib/utils"
+import { siteConfig } from "@/lib/config"
+
+export function Navbar() {
+ const [isScrolled, setIsScrolled] = useState(false)
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
+
+ useEffect(() => {
+ const handleScroll = () => {
+ setIsScrolled(window.scrollY > 20)
+ }
+ window.addEventListener("scroll", handleScroll)
+ return () => window.removeEventListener("scroll", handleScroll)
+ }, [])
+
+ const scrollToSection = (id: string) => {
+ const element = document.getElementById(id)
+ if (element) {
+ element.scrollIntoView({ behavior: "smooth" })
+ setIsMobileMenuOpen(false)
+ }
+ }
+
+ return (
+
+
+
+ {/* Logo */}
+
scrollToSection("hero")}>
+
+
+
+ {/* Desktop Navigation */}
+
+ scrollToSection("features")}
+ className="text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Features
+
+ scrollToSection("download")}
+ className="text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Download
+
+ scrollToSection("community")}
+ className="text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Community
+
+ scrollToSection("support")}
+ className="text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Support
+
+ scrollToSection("contact")}
+ className="text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Contact
+
+
+
+ {/* Desktop CTA Buttons */}
+
+
+
+
+ GitHub
+
+
+
scrollToSection("download")}
+ >
+
+ Download
+
+
+
+ {/* Mobile Menu Button */}
+
setIsMobileMenuOpen(!isMobileMenuOpen)}>
+ {isMobileMenuOpen ? : }
+
+
+
+ {/* Mobile Menu */}
+ {isMobileMenuOpen && (
+
+
+
scrollToSection("features")}
+ className="text-left text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Features
+
+
scrollToSection("download")}
+ className="text-left text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Download
+
+
scrollToSection("community")}
+ className="text-left text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Community
+
+
scrollToSection("support")}
+ className="text-left text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Support
+
+
scrollToSection("contact")}
+ className="text-left text-sm font-medium hover:text-primary transition-colors cursor-pointer"
+ >
+ Contact
+
+
+
+
+ )}
+
+
+ )
+}
diff --git a/components/section-numeral.css b/components/section-numeral.css
deleted file mode 100644
index 0746ba7..0000000
--- a/components/section-numeral.css
+++ /dev/null
@@ -1,21 +0,0 @@
-.section-numeral-section-numeral {
- gap: var(--dl-space-space-halfunit);
- display: flex;
- position: relative;
- align-items: flex-start;
- flex-direction: row;
-}
-.section-numeral-divide {
- width: 100px;
- height: 1px;
- display: flex;
- margin-top: 4px;
- align-items: center;
- flex-direction: row;
- background-color: var(--dl-color-gray-black);
-}
-@media(max-width: 479px) {
- .section-numeral-divide {
- width: 20px;
- }
-}
diff --git a/components/section-numeral.html b/components/section-numeral.html
deleted file mode 100644
index d16bb71..0000000
--- a/components/section-numeral.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/components/speaker.css b/components/speaker.css
deleted file mode 100644
index 5b448b6..0000000
--- a/components/speaker.css
+++ /dev/null
@@ -1,115 +0,0 @@
-.speaker-speaker {
- gap: var(--dl-space-space-oneandhalfunits);
- width: 100%;
- display: flex;
- position: relative;
- align-items: flex-start;
- flex-direction: column;
- padding-bottom: var(--dl-space-space-threeunits);
-}
-.speaker-image {
- width: 100%;
- object-fit: cover;
- aspect-ratio: 1;
-}
-.speaker-deails {
- gap: var(--dl-space-space-halfunit);
- display: flex;
- align-items: flex-start;
- flex-direction: column;
-}
-.speaker-name {
- font-size: 28px;
- font-style: normal;
- font-weight: 600;
-}
-.speaker-position {
- gap: var(--dl-space-space-halfunit);
- width: 100%;
- display: flex;
- align-items: flex-start;
- flex-direction: row;
-}
-.speaker-point {
- width: 100%;
- height: 1px;
- display: flex;
- max-width: 40px;
- margin-top: var(--dl-space-space-halfunit);
- align-items: center;
- flex-direction: row;
- background-color: var(--dl-color-gray-black);
-}
-.speaker-caption {
- font-size: 18px;
-}
-
-
-
-
-
-
-
-
-.speaker-root-class-name8 {
- max-width: 320px;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-@media(max-width: 991px) {
- .speaker-name {
- font-size: 20px;
- }
- .speaker-point {
- margin-top: 4px;
- }
- .speaker-caption {
- font-size: 10px;
- }
-}
-@media(max-width: 767px) {
- .speaker-speaker {
- padding-bottom: var(--dl-space-space-oneandhalfunits);
- }
- .speaker-name {
- font-size: 14px;
- }
- .speaker-point {
- max-width: 20px;
- margin-top: 0px;
- }
- .speaker-caption {
- font-size: 10px;
- }
-}
-@media(max-width: 479px) {
- .speaker-point {
- width: 100%;
- max-width: 20px;
- }
-}
diff --git a/components/speaker.html b/components/speaker.html
deleted file mode 100644
index d8b6efc..0000000
--- a/components/speaker.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
diff --git a/components/supported-by-section.tsx b/components/supported-by-section.tsx
new file mode 100644
index 0000000..e8c5c16
--- /dev/null
+++ b/components/supported-by-section.tsx
@@ -0,0 +1,135 @@
+"use client"
+
+import { Card, CardContent } from "@/components/ui/card"
+
+const participatingInstitutions = [
+ {
+ name: "DCC Universidad de Chile",
+ logo: "supported-by/dcc-logo.png",
+ url: "https://dcc.uchile.cl/",
+ },
+ {
+ name: "Universidad Técnica Federico Santa María",
+ logo: "supported-by/utfsm-logo.jpg",
+ url: "https://www.usm.cl/",
+ },
+ {
+ name: "Centro Nacional de Inteligencia Artificial",
+ logo: "supported-by/cenia-logo.png",
+ url: "https://www.cenia.cl/",
+ },
+ {
+ name: "Instituto Milenio Fundamentos de los Datos",
+ logo: "supported-by/imfd-logo.png",
+ url: "https://www.imfd.cl/",
+ },
+]
+
+const fundingInstitution = {
+ name: "Institución Financiadora",
+ logo: "supported-by/idea-logo.png",
+ url: "#",
+}
+
+const partnerOrganizations = [
+ {
+ name: "Organización Asociada 1",
+ logo: "/placeholder-logo.png",
+ url: "#",
+ },
+ {
+ name: "Organización Asociada 2",
+ logo: "/placeholder-logo.png",
+ url: "#",
+ },
+]
+
+export function SupportedBySection() {
+ return (
+
+
+
+
Supported By
+
+ DashAI is made possible thanks to the collaboration and support of leading institutions and organizations
+
+
+
+
+ {/* Participating Institutions */}
+ {/*
+
+ Participating Institutions
+ */}
+
+ {participatingInstitutions.map((institution, index) => {
+ const isSmallLogo = institution.logo.includes("dcc-logo") || institution.logo.includes("utfsm-logo")
+ return (
+
window.open(institution.url, "_blank", "noopener,noreferrer")}
+ >
+
+
+
+
+ )
+ })}
+
+ {/*
*/}
+
+ {/* Funding Institution */}
+ {/*
+
Funding
+
+
window.open(fundingInstitution.url, "_blank", "noopener,noreferrer")}
+ >
+
+
+
+
+
+
*/}
+
+ {/* Partner Organizations */}
+ {/*
+
+ In Partnership With
+
+
+ {partnerOrganizations.map((organization, index) => (
+
window.open(organization.url, "_blank", "noopener,noreferrer")}
+ >
+
+
+
+
+ ))}
+
+
*/}
+
+
+
+ )
+}
+
diff --git a/components/theme-provider.tsx b/components/theme-provider.tsx
new file mode 100644
index 0000000..55c2f6e
--- /dev/null
+++ b/components/theme-provider.tsx
@@ -0,0 +1,11 @@
+'use client'
+
+import * as React from 'react'
+import {
+ ThemeProvider as NextThemesProvider,
+ type ThemeProviderProps,
+} from 'next-themes'
+
+export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
+ return {children}
+}
diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx
new file mode 100644
index 0000000..e538a33
--- /dev/null
+++ b/components/ui/accordion.tsx
@@ -0,0 +1,66 @@
+'use client'
+
+import * as React from 'react'
+import * as AccordionPrimitive from '@radix-ui/react-accordion'
+import { ChevronDownIcon } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+
+function Accordion({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function AccordionItem({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AccordionTrigger({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ svg]:rotate-180',
+ className,
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+ )
+}
+
+function AccordionContent({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ {children}
+
+ )
+}
+
+export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..9704452
--- /dev/null
+++ b/components/ui/alert-dialog.tsx
@@ -0,0 +1,157 @@
+'use client'
+
+import * as React from 'react'
+import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'
+
+import { cn } from '@/lib/utils'
+import { buttonVariants } from '@/components/ui/button'
+
+function AlertDialog({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function AlertDialogTrigger({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogPortal({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogOverlay({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+ )
+}
+
+function AlertDialogHeader({
+ className,
+ ...props
+}: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function AlertDialogFooter({
+ className,
+ ...props
+}: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function AlertDialogTitle({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogDescription({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogAction({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogCancel({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}
diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx
new file mode 100644
index 0000000..e6751ab
--- /dev/null
+++ b/components/ui/alert.tsx
@@ -0,0 +1,66 @@
+import * as React from 'react'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '@/lib/utils'
+
+const alertVariants = cva(
+ 'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
+ {
+ variants: {
+ variant: {
+ default: 'bg-card text-card-foreground',
+ destructive:
+ 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ },
+)
+
+function Alert({
+ className,
+ variant,
+ ...props
+}: React.ComponentProps<'div'> & VariantProps) {
+ return (
+
+ )
+}
+
+function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function AlertDescription({
+ className,
+ ...props
+}: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+export { Alert, AlertTitle, AlertDescription }
diff --git a/components/ui/aspect-ratio.tsx b/components/ui/aspect-ratio.tsx
new file mode 100644
index 0000000..40bb120
--- /dev/null
+++ b/components/ui/aspect-ratio.tsx
@@ -0,0 +1,11 @@
+'use client'
+
+import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio'
+
+function AspectRatio({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+export { AspectRatio }
diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx
new file mode 100644
index 0000000..aa98465
--- /dev/null
+++ b/components/ui/avatar.tsx
@@ -0,0 +1,53 @@
+'use client'
+
+import * as React from 'react'
+import * as AvatarPrimitive from '@radix-ui/react-avatar'
+
+import { cn } from '@/lib/utils'
+
+function Avatar({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AvatarImage({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AvatarFallback({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export { Avatar, AvatarImage, AvatarFallback }
diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx
new file mode 100644
index 0000000..fc4126b
--- /dev/null
+++ b/components/ui/badge.tsx
@@ -0,0 +1,46 @@
+import * as React from 'react'
+import { Slot } from '@radix-ui/react-slot'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '@/lib/utils'
+
+const badgeVariants = cva(
+ 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
+ {
+ variants: {
+ variant: {
+ default:
+ 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
+ secondary:
+ 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
+ destructive:
+ 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
+ outline:
+ 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ },
+)
+
+function Badge({
+ className,
+ variant,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'span'> &
+ VariantProps & { asChild?: boolean }) {
+ const Comp = asChild ? Slot : 'span'
+
+ return (
+
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/components/ui/breadcrumb.tsx b/components/ui/breadcrumb.tsx
new file mode 100644
index 0000000..1750ff2
--- /dev/null
+++ b/components/ui/breadcrumb.tsx
@@ -0,0 +1,109 @@
+import * as React from 'react'
+import { Slot } from '@radix-ui/react-slot'
+import { ChevronRight, MoreHorizontal } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+
+function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
+ return
+}
+
+function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
+ return (
+
+ )
+}
+
+function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
+ return (
+
+ )
+}
+
+function BreadcrumbLink({
+ asChild,
+ className,
+ ...props
+}: React.ComponentProps<'a'> & {
+ asChild?: boolean
+}) {
+ const Comp = asChild ? Slot : 'a'
+
+ return (
+
+ )
+}
+
+function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
+ return (
+
+ )
+}
+
+function BreadcrumbSeparator({
+ children,
+ className,
+ ...props
+}: React.ComponentProps<'li'>) {
+ return (
+ svg]:size-3.5', className)}
+ {...props}
+ >
+ {children ?? }
+
+ )
+}
+
+function BreadcrumbEllipsis({
+ className,
+ ...props
+}: React.ComponentProps<'span'>) {
+ return (
+
+
+ More
+
+ )
+}
+
+export {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ BreadcrumbEllipsis,
+}
diff --git a/components/ui/button-group.tsx b/components/ui/button-group.tsx
new file mode 100644
index 0000000..09d4430
--- /dev/null
+++ b/components/ui/button-group.tsx
@@ -0,0 +1,83 @@
+import { Slot } from '@radix-ui/react-slot'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '@/lib/utils'
+import { Separator } from '@/components/ui/separator'
+
+const buttonGroupVariants = cva(
+ "flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
+ {
+ variants: {
+ orientation: {
+ horizontal:
+ '[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none',
+ vertical:
+ 'flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none',
+ },
+ },
+ defaultVariants: {
+ orientation: 'horizontal',
+ },
+ },
+)
+
+function ButtonGroup({
+ className,
+ orientation,
+ ...props
+}: React.ComponentProps<'div'> & VariantProps) {
+ return (
+
+ )
+}
+
+function ButtonGroupText({
+ className,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'div'> & {
+ asChild?: boolean
+}) {
+ const Comp = asChild ? Slot : 'div'
+
+ return (
+
+ )
+}
+
+function ButtonGroupSeparator({
+ className,
+ orientation = 'vertical',
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ ButtonGroup,
+ ButtonGroupSeparator,
+ ButtonGroupText,
+ buttonGroupVariants,
+}
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
new file mode 100644
index 0000000..f64632d
--- /dev/null
+++ b/components/ui/button.tsx
@@ -0,0 +1,60 @@
+import * as React from 'react'
+import { Slot } from '@radix-ui/react-slot'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '@/lib/utils'
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+ {
+ variants: {
+ variant: {
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
+ destructive:
+ 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
+ outline:
+ 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
+ secondary:
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
+ ghost:
+ 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
+ link: 'text-primary underline-offset-4 hover:underline',
+ },
+ size: {
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
+ sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
+ icon: 'size-9',
+ 'icon-sm': 'size-8',
+ 'icon-lg': 'size-10',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ },
+ },
+)
+
+function Button({
+ className,
+ variant,
+ size,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'button'> &
+ VariantProps & {
+ asChild?: boolean
+ }) {
+ const Comp = asChild ? Slot : 'button'
+
+ return (
+
+ )
+}
+
+export { Button, buttonVariants }
diff --git a/components/ui/calendar.tsx b/components/ui/calendar.tsx
new file mode 100644
index 0000000..eaa373e
--- /dev/null
+++ b/components/ui/calendar.tsx
@@ -0,0 +1,213 @@
+'use client'
+
+import * as React from 'react'
+import {
+ ChevronDownIcon,
+ ChevronLeftIcon,
+ ChevronRightIcon,
+} from 'lucide-react'
+import { DayButton, DayPicker, getDefaultClassNames } from 'react-day-picker'
+
+import { cn } from '@/lib/utils'
+import { Button, buttonVariants } from '@/components/ui/button'
+
+function Calendar({
+ className,
+ classNames,
+ showOutsideDays = true,
+ captionLayout = 'label',
+ buttonVariant = 'ghost',
+ formatters,
+ components,
+ ...props
+}: React.ComponentProps & {
+ buttonVariant?: React.ComponentProps['variant']
+}) {
+ const defaultClassNames = getDefaultClassNames()
+
+ return (
+ svg]:rotate-180`,
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
+ className,
+ )}
+ captionLayout={captionLayout}
+ formatters={{
+ formatMonthDropdown: (date) =>
+ date.toLocaleString('default', { month: 'short' }),
+ ...formatters,
+ }}
+ classNames={{
+ root: cn('w-fit', defaultClassNames.root),
+ months: cn(
+ 'flex gap-4 flex-col md:flex-row relative',
+ defaultClassNames.months,
+ ),
+ month: cn('flex flex-col w-full gap-4', defaultClassNames.month),
+ nav: cn(
+ 'flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between',
+ defaultClassNames.nav,
+ ),
+ button_previous: cn(
+ buttonVariants({ variant: buttonVariant }),
+ 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
+ defaultClassNames.button_previous,
+ ),
+ button_next: cn(
+ buttonVariants({ variant: buttonVariant }),
+ 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
+ defaultClassNames.button_next,
+ ),
+ month_caption: cn(
+ 'flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)',
+ defaultClassNames.month_caption,
+ ),
+ dropdowns: cn(
+ 'w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5',
+ defaultClassNames.dropdowns,
+ ),
+ dropdown_root: cn(
+ 'relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md',
+ defaultClassNames.dropdown_root,
+ ),
+ dropdown: cn(
+ 'absolute bg-popover inset-0 opacity-0',
+ defaultClassNames.dropdown,
+ ),
+ caption_label: cn(
+ 'select-none font-medium',
+ captionLayout === 'label'
+ ? 'text-sm'
+ : 'rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5',
+ defaultClassNames.caption_label,
+ ),
+ table: 'w-full border-collapse',
+ weekdays: cn('flex', defaultClassNames.weekdays),
+ weekday: cn(
+ 'text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none',
+ defaultClassNames.weekday,
+ ),
+ week: cn('flex w-full mt-2', defaultClassNames.week),
+ week_number_header: cn(
+ 'select-none w-(--cell-size)',
+ defaultClassNames.week_number_header,
+ ),
+ week_number: cn(
+ 'text-[0.8rem] select-none text-muted-foreground',
+ defaultClassNames.week_number,
+ ),
+ day: cn(
+ 'relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none',
+ defaultClassNames.day,
+ ),
+ range_start: cn(
+ 'rounded-l-md bg-accent',
+ defaultClassNames.range_start,
+ ),
+ range_middle: cn('rounded-none', defaultClassNames.range_middle),
+ range_end: cn('rounded-r-md bg-accent', defaultClassNames.range_end),
+ today: cn(
+ 'bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none',
+ defaultClassNames.today,
+ ),
+ outside: cn(
+ 'text-muted-foreground aria-selected:text-muted-foreground',
+ defaultClassNames.outside,
+ ),
+ disabled: cn(
+ 'text-muted-foreground opacity-50',
+ defaultClassNames.disabled,
+ ),
+ hidden: cn('invisible', defaultClassNames.hidden),
+ ...classNames,
+ }}
+ components={{
+ Root: ({ className, rootRef, ...props }) => {
+ return (
+
+ )
+ },
+ Chevron: ({ className, orientation, ...props }) => {
+ if (orientation === 'left') {
+ return (
+
+ )
+ }
+
+ if (orientation === 'right') {
+ return (
+
+ )
+ }
+
+ return (
+
+ )
+ },
+ DayButton: CalendarDayButton,
+ WeekNumber: ({ children, ...props }) => {
+ return (
+
+
+ {children}
+
+
+ )
+ },
+ ...components,
+ }}
+ {...props}
+ />
+ )
+}
+
+function CalendarDayButton({
+ className,
+ day,
+ modifiers,
+ ...props
+}: React.ComponentProps) {
+ const defaultClassNames = getDefaultClassNames()
+
+ const ref = React.useRef(null)
+ React.useEffect(() => {
+ if (modifiers.focused) ref.current?.focus()
+ }, [modifiers.focused])
+
+ return (
+ span]:text-xs [&>span]:opacity-70',
+ defaultClassNames.day,
+ className,
+ )}
+ {...props}
+ />
+ )
+}
+
+export { Calendar, CalendarDayButton }
diff --git a/components/ui/card.tsx b/components/ui/card.tsx
new file mode 100644
index 0000000..db7dd3c
--- /dev/null
+++ b/components/ui/card.tsx
@@ -0,0 +1,92 @@
+import * as React from 'react'
+
+import { cn } from '@/lib/utils'
+
+function Card({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+}
diff --git a/components/ui/carousel.tsx b/components/ui/carousel.tsx
new file mode 100644
index 0000000..d4a768e
--- /dev/null
+++ b/components/ui/carousel.tsx
@@ -0,0 +1,241 @@
+'use client'
+
+import * as React from 'react'
+import useEmblaCarousel, {
+ type UseEmblaCarouselType,
+} from 'embla-carousel-react'
+import { ArrowLeft, ArrowRight } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+import { Button } from '@/components/ui/button'
+
+type CarouselApi = UseEmblaCarouselType[1]
+type UseCarouselParameters = Parameters
+type CarouselOptions = UseCarouselParameters[0]
+type CarouselPlugin = UseCarouselParameters[1]
+
+type CarouselProps = {
+ opts?: CarouselOptions
+ plugins?: CarouselPlugin
+ orientation?: 'horizontal' | 'vertical'
+ setApi?: (api: CarouselApi) => void
+}
+
+type CarouselContextProps = {
+ carouselRef: ReturnType[0]
+ api: ReturnType[1]
+ scrollPrev: () => void
+ scrollNext: () => void
+ canScrollPrev: boolean
+ canScrollNext: boolean
+} & CarouselProps
+
+const CarouselContext = React.createContext(null)
+
+function useCarousel() {
+ const context = React.useContext(CarouselContext)
+
+ if (!context) {
+ throw new Error('useCarousel must be used within a ')
+ }
+
+ return context
+}
+
+function Carousel({
+ orientation = 'horizontal',
+ opts,
+ setApi,
+ plugins,
+ className,
+ children,
+ ...props
+}: React.ComponentProps<'div'> & CarouselProps) {
+ const [carouselRef, api] = useEmblaCarousel(
+ {
+ ...opts,
+ axis: orientation === 'horizontal' ? 'x' : 'y',
+ },
+ plugins,
+ )
+ const [canScrollPrev, setCanScrollPrev] = React.useState(false)
+ const [canScrollNext, setCanScrollNext] = React.useState(false)
+
+ const onSelect = React.useCallback((api: CarouselApi) => {
+ if (!api) return
+ setCanScrollPrev(api.canScrollPrev())
+ setCanScrollNext(api.canScrollNext())
+ }, [])
+
+ const scrollPrev = React.useCallback(() => {
+ api?.scrollPrev()
+ }, [api])
+
+ const scrollNext = React.useCallback(() => {
+ api?.scrollNext()
+ }, [api])
+
+ const handleKeyDown = React.useCallback(
+ (event: React.KeyboardEvent) => {
+ if (event.key === 'ArrowLeft') {
+ event.preventDefault()
+ scrollPrev()
+ } else if (event.key === 'ArrowRight') {
+ event.preventDefault()
+ scrollNext()
+ }
+ },
+ [scrollPrev, scrollNext],
+ )
+
+ React.useEffect(() => {
+ if (!api || !setApi) return
+ setApi(api)
+ }, [api, setApi])
+
+ React.useEffect(() => {
+ if (!api) return
+ onSelect(api)
+ api.on('reInit', onSelect)
+ api.on('select', onSelect)
+
+ return () => {
+ api?.off('select', onSelect)
+ }
+ }, [api, onSelect])
+
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+function CarouselContent({ className, ...props }: React.ComponentProps<'div'>) {
+ const { carouselRef, orientation } = useCarousel()
+
+ return (
+
+ )
+}
+
+function CarouselItem({ className, ...props }: React.ComponentProps<'div'>) {
+ const { orientation } = useCarousel()
+
+ return (
+
+ )
+}
+
+function CarouselPrevious({
+ className,
+ variant = 'outline',
+ size = 'icon',
+ ...props
+}: React.ComponentProps) {
+ const { orientation, scrollPrev, canScrollPrev } = useCarousel()
+
+ return (
+
+
+ Previous slide
+
+ )
+}
+
+function CarouselNext({
+ className,
+ variant = 'outline',
+ size = 'icon',
+ ...props
+}: React.ComponentProps) {
+ const { orientation, scrollNext, canScrollNext } = useCarousel()
+
+ return (
+
+
+ Next slide
+
+ )
+}
+
+export {
+ type CarouselApi,
+ Carousel,
+ CarouselContent,
+ CarouselItem,
+ CarouselPrevious,
+ CarouselNext,
+}
diff --git a/components/ui/chart.tsx b/components/ui/chart.tsx
new file mode 100644
index 0000000..421fe58
--- /dev/null
+++ b/components/ui/chart.tsx
@@ -0,0 +1,353 @@
+'use client'
+
+import * as React from 'react'
+import * as RechartsPrimitive from 'recharts'
+
+import { cn } from '@/lib/utils'
+
+// Format: { THEME_NAME: CSS_SELECTOR }
+const THEMES = { light: '', dark: '.dark' } as const
+
+export type ChartConfig = {
+ [k in string]: {
+ label?: React.ReactNode
+ icon?: React.ComponentType
+ } & (
+ | { color?: string; theme?: never }
+ | { color?: never; theme: Record }
+ )
+}
+
+type ChartContextProps = {
+ config: ChartConfig
+}
+
+const ChartContext = React.createContext(null)
+
+function useChart() {
+ const context = React.useContext(ChartContext)
+
+ if (!context) {
+ throw new Error('useChart must be used within a ')
+ }
+
+ return context
+}
+
+function ChartContainer({
+ id,
+ className,
+ children,
+ config,
+ ...props
+}: React.ComponentProps<'div'> & {
+ config: ChartConfig
+ children: React.ComponentProps<
+ typeof RechartsPrimitive.ResponsiveContainer
+ >['children']
+}) {
+ const uniqueId = React.useId()
+ const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`
+
+ return (
+
+
+
+
+ {children}
+
+
+
+ )
+}
+
+const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
+ const colorConfig = Object.entries(config).filter(
+ ([, config]) => config.theme || config.color,
+ )
+
+ if (!colorConfig.length) {
+ return null
+ }
+
+ return (
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Very soon
-
Take control over AI
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Still a work in progress, DashAI is aimed to be an open
- source interactive platform to facilitate the
- experimentation of ML models for various tasks on tabular
- data, NLP and computer vision. Some of the main features of
- the software will be:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Load your datasets and train different models for the task
- you want to work on.
-
-
-
-
-
- DashAI allows you to set the parameters of your model and
- configure every step of the ML workflow with a high level of
- detail.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Load your datasets and train different models for the task
- you want to work on.
-
-
-
-
-
- DashAI allows you to set the parameters of your model and
- configure every step of the ML workflow with a high level of
- detail.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Our software has an MIT license and is intended to invite from
- practitioners to researchers to be part of the DashAI community
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Friday, Nov 04
-
-
- Saturday, Nov 05
-
-
- Sunday, Nov 06
-
-
-
-
-
-
-
- 8:00 AM - 2:00 PM GMT +1 / 10:00 AM - 4:00 PM Your local
- time (6 Hours)
-
-
Pre-event networking
-
-
-
-
Andy Smith
-
-
CEO, Opary
-
-
-
-
- Connect to chat room
-
-
-
-
-
- 3:00 PM - 3:30 PM GMT +1 / 5:00 PM - 5:30 PM Your local
- time (30 Minutes)
-
-
How to Lorem Ipsum.
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- See live
-
-
-
-
-
-
-
- 3:00 PM - 3:30 PM GMT +1 / 5:00 PM - 5:30 PM Your local
- time (30 Minutes)
-
-
How to Lorem Ipsum.
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- See live
-
-
-
-
-
-
-
- 3:00 PM - 3:30 PM GMT +1 / 5:00 PM - 5:30 PM Your local
- time (30 Minutes)
-
-
How to Lorem Ipsum.
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- See live
-
-
-
-
-
-
-
- 3:00 PM - 3:30 PM GMT +1 / 5:00 PM - 5:30 PM Your local
- time (30 Minutes)
-
-
How to Lorem Ipsum.
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- See live
-
-
-
-
-
-
-
- 8:00 PM - 10:00 PM GMT +1 / 10:00 PM - 12:00 AM Your
- local time (2 Hours)
-
-
Post-event networking
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- Connect to chat room
-
-
-
-
-
-
-
-
-
- 3:00 PM - 3:30 PM GMT +1 / 5:00 PM - 5:30 PM Your local
- time (30 Minutes)
-
-
How to Lorem Ipsum.
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- See live
-
-
-
-
-
-
-
- 8:00 AM - 2:00 PM GMT +1 / 10:00 AM - 4:00 PM Your local
- time (6 Hours)
-
-
Pre-event networking
-
-
-
-
Andy Smith
-
-
CEO, Opary
-
-
-
-
- Connect to chat room
-
-
-
-
-
- 3:00 PM - 3:30 PM GMT +1 / 5:00 PM - 5:30 PM Your local
- time (30 Minutes)
-
-
How to Lorem Ipsum.
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- See live
-
-
-
-
-
-
-
-
-
- 8:00 AM - 2:00 PM GMT +1 / 10:00 AM - 4:00 PM Your local
- time (6 Hours)
-
-
Pre-event networking
-
-
-
-
Andy Smith
-
-
CEO, Opary
-
-
-
-
- Connect to chat room
-
-
-
-
-
- 3:00 PM - 3:30 PM GMT +1 / 5:00 PM - 5:30 PM Your local
- time (30 Minutes)
-
-
How to Lorem Ipsum.
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- See live
-
-
-
-
-
-
-
- 3:00 PM - 3:30 PM GMT +1 / 5:00 PM - 5:30 PM Your local
- time (30 Minutes)
-
-
How to Lorem Ipsum.
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- See live
-
-
-
-
-
-
-
- 8:00 PM - 10:00 PM GMT +1 / 10:00 PM - 12:00 AM Your
- local time (2 Hours)
-
-
Post-event networking
-
-
-
-
Samantha Johnson
-
-
CEO, Opary
-
-
-
-
-
- Connect to chat room
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Networking
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
- do eiusmod tempor incididunt ut labore et dolore magna
- aliqua. Ut enim ad minim veniam, quis nostrud exercitation
- ullamco laboris nisi ut aliquip ex ea commodo consequat.
-
-
-
-
-
-
-
Learning
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
- do eiusmod tempor incididunt ut labore et dolore magna
- aliqua. Ut enim ad minim veniam, quis nostrud exercitation
- ullamco laboris nisi ut aliquip ex ea commodo consequat.
-
-
-
-
-
-
-
Developing
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
- do eiusmod tempor incididunt ut labore et dolore magna
- aliqua. Ut enim ad minim veniam, quis nostrud exercitation
- ullamco laboris nisi ut aliquip ex ea commodo consequat.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- “Lorem ipsum dolor sit amet consectetur “
-
-
The Guard
-
-
-
-
-
-
-
- “Neque porro quisquam est, qui dolorem ipsum quia dolor sit
- amet“
-
-
Wall Street News
-
-
-
-
- “Duis aute irure dolor in reprehenderit in voluptate velit “
-
-
Inside Business
-
-
-
-
-
- Join us at OnConf on November 22-24
-
-
- Register now
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit,
- sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Ut enim ad minim veniam, quis nostrud
- exercitation ullamco laboris nisi ut aliquip ex ea
- commodo consequat.
-
-
-
-
-
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit,
- sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Ut enim ad minim veniam, quis nostrud
- exercitation ullamco laboris nisi ut aliquip ex ea
- commodo consequat.
-
-
-
-
-
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit,
- sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Ut enim ad minim veniam, quis nostrud
- exercitation ullamco laboris nisi ut aliquip ex ea
- commodo consequat.
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit,
- sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Ut enim ad minim veniam, quis nostrud
- exercitation ullamco laboris nisi ut aliquip ex ea
- commodo consequat.
-
-
-
-
-
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit,
- sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Ut enim ad minim veniam, quis nostrud
- exercitation ullamco laboris nisi ut aliquip ex ea
- commodo consequat.
-
-
-
-
-
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit,
- sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Ut enim ad minim veniam, quis nostrud
- exercitation ullamco laboris nisi ut aliquip ex ea
- commodo consequat.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-