diff --git a/next copy.config.mjs b/next copy.config.mjs new file mode 100644 index 0000000..4678774 --- /dev/null +++ b/next copy.config.mjs @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {}; + +export default nextConfig; diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..007b058 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/CompanyNewsWidget.tsx b/src/components/CompanyNewsWidget.tsx index d8a315b..9659b23 100644 --- a/src/components/CompanyNewsWidget.tsx +++ b/src/components/CompanyNewsWidget.tsx @@ -45,8 +45,20 @@ const CompanyNewsWidget = ({ symbol }: CompanyNewsWidgetProps) => { } }, [symbol]); + const SkeletonLoader = () => ( +
+ {Array.from({ length: 3 }).map((_, index) => ( +
+
+
+
+
+ ))} +
+ ); + if (loading) { - return

Loading...

; + return ; } if (error) { @@ -57,7 +69,7 @@ const CompanyNewsWidget = ({ symbol }: CompanyNewsWidgetProps) => {

Company News for {symbol}

- {news.map((article) => ( + {news.slice(0, 20).map((article) => (

{article.headline}

diff --git a/src/components/CompanyProfileCard.tsx b/src/components/CompanyProfileCard.tsx index 77c25b1..2bf471c 100644 --- a/src/components/CompanyProfileCard.tsx +++ b/src/components/CompanyProfileCard.tsx @@ -23,10 +23,12 @@ interface CompanyProfileData { const CompanyProfileCard = ({ ticker }: CompanyProfileProps) => { const [profile, setProfile] = useState(null); const [error, setError] = useState(''); + const [loading, setLoading] = useState(true); const fetchCompanyProfile = async (ticker: string) => { setError(''); try { + setLoading(true); const res = await fetch(`/api/profile?symbol=${ticker}`); const data = await res.json(); if (data.error) { @@ -38,6 +40,8 @@ const CompanyProfileCard = ({ ticker }: CompanyProfileProps) => { } catch (err) { setError('Failed to fetch company profile'); setProfile(null); + } finally { + setLoading(false); } }; @@ -47,8 +51,39 @@ const CompanyProfileCard = ({ ticker }: CompanyProfileProps) => { } }, [ticker]); - if (!profile) { - return error ?

{error}

:

Loading...

; + const SkeletonLoader = () => ( +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ); + + if (loading) { + return ; + } + + if (error) { + return

{error}

; } return ( diff --git a/src/components/FinancialsWidget.tsx b/src/components/FinancialsWidget.tsx index ee714d5..5a5e0db 100644 --- a/src/components/FinancialsWidget.tsx +++ b/src/components/FinancialsWidget.tsx @@ -58,8 +58,19 @@ const FinancialsWidget = ({ symbol }: FinancialsWidgetProps) => { } }, [symbol]); + const SkeletonLoader = () => ( +
+

+
+ {Array.from({ length: 6 }).map((_, index) => ( +
+ ))} +
+
+ ); + if (loading) { - return

Loading...

; + return ; } if (error) { @@ -71,7 +82,7 @@ const FinancialsWidget = ({ symbol }: FinancialsWidgetProps) => { } return ( -
+

Basic Financials for {symbol}

{formattedData.map((data, index) => ( diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..528d2e9 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,12 @@ +// components/Footer.tsx +const Footer = () => { + return ( +
+
+

this project is open-source and is available at github.com/ryanamay or code.lgbt/ryanamay

+
+
+ ); + }; + + export default Footer; \ No newline at end of file diff --git a/src/components/HeadTemplate.tsx b/src/components/HeadTemplate.tsx new file mode 100644 index 0000000..0c0b0fd --- /dev/null +++ b/src/components/HeadTemplate.tsx @@ -0,0 +1,15 @@ +// components/HeadTemplate.tsx +import Head from 'next/head'; + +const HeadTemplate = () => { + return ( + + Twinkle - Track Your Stocks + + + + + ); +}; + +export default HeadTemplate; \ No newline at end of file diff --git a/src/components/HeroSection.tsx b/src/components/HeroSection.tsx new file mode 100644 index 0000000..37ce35c --- /dev/null +++ b/src/components/HeroSection.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { FaArrowUp } from 'react-icons/fa'; + +const HeroSection = () => { + return ( +
+ ); +}; + +export default HeroSection; \ No newline at end of file diff --git a/src/components/NavigationBar.tsx b/src/components/NavigationBar.tsx index cd6bd8c..0c88b32 100644 --- a/src/components/NavigationBar.tsx +++ b/src/components/NavigationBar.tsx @@ -1,43 +1,46 @@ -import { useState, useEffect } from 'react' -import SearchBar from './SearchBar' -import Link from 'next/link' -import ThemeSwitcher from './ThemeSwitcher' -import { IoSparkles } from 'react-icons/io5' -import { FaHamburger } from 'react-icons/fa' -import { GiHamburgerMenu } from 'react-icons/gi' +import { useState } from 'react'; +import SearchBar from './SearchBar'; +import Link from 'next/link'; +import ThemeSwitcher from './ThemeSwitcher'; +import { IoSparkles } from 'react-icons/io5'; interface NavigationBarProps { - onSelectSymbol: (symbol: string) => void + onSelectSymbol: (symbol: string) => void; } const NavigationBar = ({ onSelectSymbol }: NavigationBarProps) => { - const [currency, setCurrency] = useState('USD') - const [watchlistView, setWatchlistView] = useState('priceChange') - const [dropdownOpen, setDropdownOpen] = useState(false) + const [currency, setCurrency] = useState('USD'); + const [watchlistView, setWatchlistView] = useState('priceChange'); + const [dropdownOpen, setDropdownOpen] = useState(false); const handleCurrencyChange = (event: React.ChangeEvent) => { - setCurrency(event.target.value) - } + setCurrency(event.target.value); + }; const handleWatchlistViewChange = (event: React.ChangeEvent) => { - setWatchlistView(event.target.value) - } + setWatchlistView(event.target.value); + }; + + const resetSymbol = () => { + onSelectSymbol(''); + }; return ( -