diff --git a/bun.lockb b/bun.lockb index 895d5db..aa18124 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index b212b70..3ab3afd 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "prismjs": "^1.29.0", "react": "^18", "react-dom": "^18", + "react-icons": "^5.4.0", "react-use-measure": "^2.1.1" }, "devDependencies": { diff --git a/src/app/page.tsx b/src/app/page.tsx index 8670d40..cd1fcbd 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -5,10 +5,12 @@ import { Container } from '@/components/container' import { Footer } from '@/components/footer' import { Gradient } from '@/components/gradient' import { InterstateRows } from '@/components/interstate-rows' +import LeftCodeTabs from '@/components/left-code-tabs' import { Link } from '@/components/link' import { LogoCluster } from '@/components/logo-cluster' import { Map } from '@/components/map' import { Navbar } from '@/components/navbar' +import RightCodeTabs from '@/components/right-code-tabs' import { Testimonials } from '@/components/testimonials' import { Heading, Subheading } from '@/components/text' import { ChevronRightIcon } from '@heroicons/react/16/solid' @@ -75,54 +77,7 @@ function BentoSection() { eyebrow="Free" title="Open Source" description="Built by the community, for the community. Always free and open source." - graphic={ -
-
-
-
-
-
-
- playlistService.jsx -
-
- artistService.jsx -
-
-
-
- { - try { - const response = await fetch("https://api.spotify.com/v1/me/playlists", { - headers: { - Authorization: \`Bearer \${accessToken}\`, - }, - }); - if (response.ok) { - const data = await response.json(); - const validPlaylists = data.items.filter(item => item && item.id); - if (validPlaylists.length > 0) { - const imageUrl = validPlaylists[0].images[0]?.url; - if (imageUrl) { - localStorage.setItem("libraryImage", imageUrl); - updateGradientColors(imageUrl, "library"); - } - } - setPlaylists(validPlaylists); - } else { - console.error("Error fetching user playlists:", response.status); - } - } catch (error) { - console.error("Error fetching user playlists:", error.message); - } -};`} - /> -
-
-
-
- } + graphic={} fade={['bottom']} className="max-lg:rounded-t-4xl lg:col-span-3 lg:rounded-tl-4xl" /> @@ -130,49 +85,7 @@ function BentoSection() { eyebrow="Simple" title="Easy Setup" description="Get up and running in minutes with our step-by-step installation guide and community support." - graphic={ -
-
-
-
-
-
-
- setup_hotspot.py -
-
- README.md -
-
-
-
-                    
-                      If you haven't already, download superbird-tool and run
-                      the setup process detailed here.
-                    
-                    
-                      Download and unzip the latest image from Releases, connect
-                      Car Thing to your computer in USB Mode (hold preset
-                      buttons 1 and 4 while connecting), and run the following
-                      from your command line:
-                    
-                    
-                      # Go into the superbird-tool repository
-                    
-                    
-                      $ cd C:\path\to\superbird-tool-main
-                    
-                    
-                      # Find device
-                    
-                    
-                      $ python superbird_tool.py --find_device
-                    
-                  
-
-
-
- } + graphic={} fade={['bottom']} className="lg:col-span-3 lg:rounded-tr-4xl" /> diff --git a/src/components/left-code-tabs.tsx b/src/components/left-code-tabs.tsx new file mode 100644 index 0000000..f59a373 --- /dev/null +++ b/src/components/left-code-tabs.tsx @@ -0,0 +1,180 @@ +import dynamic from 'next/dynamic' +import { useEffect, useState } from 'react' +import { FaJsSquare, FaReact } from 'react-icons/fa' + +const CodeBlock = dynamic(() => import('@/components/code-block'), { + ssr: false, +}) + +type TabKey = 'playlist' | 'artist' + +interface TabContent { + title: string + code: string +} + +interface TabsData { + playlist: TabContent + artist: TabContent +} + +const LeftCodeTabs = () => { + const [activeTab, setActiveTab] = useState('playlist') + const [isMounted, setIsMounted] = useState(false) + const [isChanging, setIsChanging] = useState(false) + + useEffect(() => { + setIsMounted(true) + }, []) + + const handleTabChange = (newTab: TabKey) => { + if (newTab === activeTab) return + + setIsChanging(true) + setTimeout(() => { + setActiveTab(newTab) + setIsChanging(false) + }, 150) + } + + const tabs: TabsData = { + playlist: { + title: 'playlistService.js', + code: `export const fetchUserPlaylists = async ( + accessToken, + setPlaylists, + updateGradientColors, + handleError +) => { + try { + const response = await fetch("https://api.spotify.com/v1/me/playlists", { + headers: { + Authorization: \`Bearer \${accessToken}\`, + }, + }); + if (response.ok) { + const data = await response.json(); + const validPlaylists = data.items.filter((item) => item && item.id); + if (validPlaylists.length > 0) { + const imageUrl = validPlaylists[0].images?.[0]?.url; + if (imageUrl) { + localStorage.setItem("libraryImage", imageUrl); + updateGradientColors(imageUrl, "library"); + } + } + setPlaylists(validPlaylists); + } else { + console.error("Error fetching user playlists:", response.status); + } + } catch (error) { + console.error("Error fetching user playlists:", error.message); + } +};`, + }, + artist: { + title: 'AuthSelection.jsx', + code: `const enableBluetoothDiscovery = async () => { + try { + setIsBluetoothDiscovering(true); + const response = await fetch( + "http://localhost:5000/bluetooth/discover/on", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (!response.ok) { + throw new Error("Failed to enable bluetooth discovery"); + } + + setTimeout(() => { + setIsBluetoothDiscovering(false); + fetch("http://localhost:5000/bluetooth/discover/off", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }).catch(console.error); + }, 120000); + } catch (error) { + console.error("Error enabling bluetooth discovery:", error); + setIsBluetoothDiscovering(false); + } +};`, + }, + } + + return ( +
+
+
+
+
+
+
handleTabChange('playlist')} + className="relative cursor-pointer" + > +
+
+ + {tabs.playlist.title} +
+
+
+
+
handleTabChange('artist')} + className="relative cursor-pointer" + > +
+
+ + {tabs.artist.title} +
+
+
+
+
+
+
+ {isMounted && ( +
+ +
+ )} +
+
+
+
+ ) +} + +export default LeftCodeTabs diff --git a/src/components/right-code-tabs.tsx b/src/components/right-code-tabs.tsx new file mode 100644 index 0000000..4abdb6f --- /dev/null +++ b/src/components/right-code-tabs.tsx @@ -0,0 +1,172 @@ +import dynamic from 'next/dynamic' +import { useEffect, useState } from 'react' +import { FaPython } from 'react-icons/fa' +import { RiMarkdownFill } from 'react-icons/ri' + +const CodeBlock = dynamic(() => import('@/components/code-block'), { + ssr: false, +}) + +type TabKey = 'setup' | 'readme' + +interface TabContent { + title: string + code: string +} + +interface TabsData { + setup: TabContent + readme: TabContent +} + +const RightCodeTabs = () => { + const [activeTab, setActiveTab] = useState('readme') + const [isMounted, setIsMounted] = useState(false) + const [isChanging, setIsChanging] = useState(false) + + useEffect(() => { + setIsMounted(true) + }, []) + + const handleTabChange = (newTab: TabKey) => { + if (newTab === activeTab) return + + setIsChanging(true) + setTimeout(() => { + setActiveTab(newTab) + setIsChanging(false) + }, 150) + } + + const tabs: TabsData = { + setup: { + title: 'setup_hotspot.py', + code: `def setup_hotspot(): + # Check if WiFi is available + wifi_status = check_wifi_status() + if not wifi_status: + print("Error: WiFi hardware not detected") + return False + + # Create hotspot configuration + config = { + "ssid": "Car_Thing_Setup", + "wpa_passphrase": generate_password(), + "ip_range": "192.168.4.0/24" + } + + # Apply configuration + success = apply_hotspot_config(config) + if not success: + print("Error: Failed to configure hotspot") + return False + + # Start hotspot service + if start_hotspot_service(): + print("Hotspot started successfully") + print(f"SSID: {config['ssid']}") + print(f"Password: {config['wpa_passphrase']}") + return True + else: + print("Error: Failed to start hotspot") + return False`, + }, + readme: { + title: 'README.md', + code: `# Car Thing Setup Guide + +1. Download superbird-tool and run the setup process detailed here. + +2. Download and unzip the latest image from Releases. + +3. Connect Car Thing to your computer in USB Mode: + - Hold preset buttons 1 and 4 while connecting + - Wait for device recognition + +4. Open your command line and run: + + # Go into the superbird-tool repository + $ cd C:\\path\\to\\superbird-tool-main + + # Find device + $ python superbird_tool.py --find_device + + # Flash the new image + $ python superbird_tool.py --flash path/to/nocturne.img + +5. Wait for the process to complete. + Do not disconnect the device during flashing.`, + }, + } + + return ( +
+
+
+
+
+
+
handleTabChange('setup')} + className="relative cursor-pointer" + > +
+
+ + {tabs.setup.title} +
+
+
+
+
handleTabChange('readme')} + className="relative cursor-pointer" + > +
+
+ + {tabs.readme.title} +
+
+
+
+
+
+
+ {isMounted && ( +
+ +
+ )} +
+
+
+
+ ) +} + +export default RightCodeTabs