Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
137 changes: 137 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
@import "tailwindcss";
@import "tw-animate-css";

@custom-variant dark (&:is(.dark *));

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}

:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--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.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--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(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}

@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}

@layer utilities {
@keyframes spin-slow {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

.animate-spin-slow {
animation: spin-slow 3s linear infinite;
}
}
70 changes: 70 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/components/theme-provider";
import { Navbar } from "@/components/navbar";
import Footer from "@/components/Footer";
import { Toaster } from "@/components/ui/sonner";
import { Providers } from "@/components/Providers";
import { TooltipProvider } from "@/components/ui/tooltip";
import AgreementModal from "@/components/AgreementModal";

const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});

const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});

export const metadata: Metadata = {
title: "Predictoor",
description: "Predictoor - AI-powered predictions",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning>
<body
className={`
${geistSans.variable}
${geistMono.variable}
antialiased
bg-background
text-foreground
`}
>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<TooltipProvider>
<Providers>
{/* Layout colonne plein écran */}
<div className="min-h-screen flex flex-col">
<Navbar />

<main className="flex-1 px-4 py-8 md:px-10">
{children}
</main>

<Footer />
</div>

<Toaster position="top-right" />
<AgreementModal />
</Providers>
</TooltipProvider>
</ThemeProvider>
</body>
</html>
);
}
28 changes: 28 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use client"

import { useState } from "react"
import { TimeFrameSwitch } from "@/components/TimeFrameSwitch"
import { AssetsContainer } from "@/components/AssetsContainer"
import { SearchBar, SearchFilters } from "@/components/SearchBar"

export default function Home() {
const [filters, setFilters] = useState<SearchFilters>({
ticker: "",
platform: "all"
})

return (
<main className="w-full">
<div className="mb-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<p className="font-bold">
Accurate price predictions for your favorite crypto assets
</p>
<TimeFrameSwitch />
</div>

<SearchBar filters={filters} onFiltersChange={setFilters} />

<AssetsContainer filters={filters} />
</main>
)
}
59 changes: 59 additions & 0 deletions app/providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// "use client";

// import { RainbowKitProvider } from "@rainbow-me/rainbowkit";
// import "@rainbow-me/rainbowkit/styles.css";
// import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
// import { ReactNode, useMemo } from "react";

// import AppProvider from "@/contexts/AppProvider";
// import {
// EEthereumClientStatus,
// useEthereumClient,
// } from "@/hooks/useEthereumClient";
// import MainWrapper from "@/components/MainWrapper";
// import { NotConnectedWarning } from "@/components/NotConnectedWarning";

// const queryClient = new QueryClient();

// type ProvidersProps = {
// children: ReactNode;
// };

// export function Providers({ children }: ProvidersProps) {
// const { wagmiConfig, chains, clientStatus } = useEthereumClient();

// const hasConfig = useMemo(
// () => Boolean(wagmiConfig) && chains.length > 0,
// [wagmiConfig, chains],
// );

// const isDisconnected = clientStatus === EEthereumClientStatus.DISCONNECTED;

// if (isDisconnected) {
// return (
// <MainWrapper withBanner={false} isWalletActive={false}>
// <NotConnectedWarning clientStatus={clientStatus} />
// </MainWrapper>
// );
// }

// if (!hasConfig) {
// return (
// <MainWrapper withBanner={false} isWalletActive={false}>
// <div className="flex items-center justify-center py-10 text-sm text-muted-foreground">
// Initializing wallet…
// </div>
// </MainWrapper>
// );
// }

// return (
// <QueryClientProvider client={queryClient}>
// <AppProvider wagmiConfig={wagmiConfig}>
// <RainbowKitProvider modalSize="compact" initialChain={chains[0]}>
// <MainWrapper>{children}</MainWrapper>
// </RainbowKitProvider>
// </AppProvider>
// </QueryClientProvider>
// );
// }
22 changes: 22 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$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": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}
31 changes: 31 additions & 0 deletions components/Accuracy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Loader2 } from 'lucide-react'
import { cn } from '@/lib/utils'

export default function Accuracy({ accuracy }: { accuracy: number }) {
// function receives accuracy as a number and returns a string
// if accuracy has no decimals, add ".0" to the end
// if accuracy has decimals, return accuracy with one decimal
const getFormattedAccuracy = (accuracy: number): string => {
if (accuracy % 1 === 0) {
return `${accuracy}.0`
} else {
return `${accuracy.toFixed(1)}`
}
}

return (
<div className={cn(
"flex items-center gap-1",
"text-sm font-medium"
)}>
{accuracy !== undefined && accuracy !== null ? (
<span className="font-semibold tabular-nums">
{getFormattedAccuracy(accuracy)}
</span>
) : (
<Loader2 className="h-3 w-3 animate-spin text-muted-foreground" />
)}
<span className="text-muted-foreground">%</span>
</div>
)
}
Loading