diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..70e0ccf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,33 @@ +name: CI + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x, 20.x] + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint + + - name: Build + run: npm run build diff --git a/.gitignore b/.gitignore index 7fa9a66..1627065 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,7 @@ next-env.d.ts # local clones / tooling base-bridge/ + +# IDE +.vscode/ +.idea/ diff --git a/README.md b/README.md index ce218a7..e570b47 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Terminally Onchain +![CI](https://github.com/AdekunleBamz/sol2base/actions/workflows/ci.yml/badge.svg) +
Terminally Onchain Bridge
diff --git a/src/app/globals.css b/src/app/globals.css index bf1db73..cad69e2 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -121,3 +121,93 @@ body { text-transform: uppercase !important; letter-spacing: 1px !important; } + +/* Additional Animations */ +@keyframes slide-in { + from { + opacity: 0; + transform: translateY(-8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes pulse-subtle { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.7; + } +} + +.animate-slide-in { + animation: slide-in 0.2s ease-out; +} + +.animate-fade-in { + animation: fade-in 0.3s ease-out; +} + +.animate-pulse-subtle { + animation: pulse-subtle 2s ease-in-out infinite; +} + +/* Focus visible styles for accessibility */ +:focus-visible { + outline: 2px solid rgba(0, 255, 0, 0.5); + outline-offset: 2px; +} + +/* Smooth scrolling */ +html { + scroll-behavior: smooth; +} + +/* Custom scrollbar for terminal aesthetic */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.3); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb { + background: rgba(0, 255, 0, 0.3); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(0, 255, 0, 0.5); +} + +/* Selection styling */ +::selection { + background: rgba(0, 255, 0, 0.3); + color: #00ff00; +} + +/* Terminal cursor blink */ +.terminal-cursor { + display: inline-block; + width: 8px; + height: 1.2em; + background: #00ff00; + animation: blink 1s step-end infinite; + vertical-align: text-bottom; + margin-left: 2px; +} diff --git a/src/app/page.tsx b/src/app/page.tsx index d92d573..b88ba34 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -2,6 +2,9 @@ import { MainContent } from '../components/MainContent'; import { WalletConnection } from '../components/WalletConnection'; +import { Footer } from '../components/Footer'; +import { NetworkStatus, useNetworkStatus } from '../components/NetworkStatus'; +import { KeyboardShortcuts } from '../components/terminal/KeyboardShortcuts'; import { useNetwork } from '../contexts/NetworkContext'; import { ENVIRONMENT_CHOICES, @@ -12,6 +15,7 @@ import { export default function Home() { const { config, environment, setEnvironment } = useNetwork(); + const { solanaStatus, baseStatus, solanaLatency, baseLatency } = useNetworkStatus(); return (
@@ -27,6 +31,12 @@ export default function Home() {

+
+ + + +
+

+ Click a command to insert it • Use ↑↓ in terminal +

+
+ + )} + + ); +}; + +// Hook to manage command history +export const useCommandHistory = (maxHistory: number = 50) => { + const [commands, setCommands] = useState([]); + const [historyIndex, setHistoryIndex] = useState(-1); + + const addCommand = useCallback( + (command: string) => { + const trimmed = command.trim(); + if (!trimmed) return; + + setCommands((prev) => { + // Avoid duplicates at the top + if (prev[0] === trimmed) return prev; + return [trimmed, ...prev].slice(0, maxHistory); + }); + setHistoryIndex(-1); + }, + [maxHistory] + ); + + const navigateHistory = useCallback( + (direction: 'up' | 'down'): string | null => { + if (commands.length === 0) return null; + + let newIndex = historyIndex; + if (direction === 'up') { + newIndex = Math.min(historyIndex + 1, commands.length - 1); + } else { + newIndex = Math.max(historyIndex - 1, -1); + } + + setHistoryIndex(newIndex); + return newIndex >= 0 ? commands[newIndex] : null; + }, + [commands, historyIndex] + ); + + const resetNavigation = useCallback(() => { + setHistoryIndex(-1); + }, []); + + return { + commands, + addCommand, + navigateHistory, + resetNavigation, + }; +}; diff --git a/src/components/terminal/KeyboardShortcuts.tsx b/src/components/terminal/KeyboardShortcuts.tsx new file mode 100644 index 0000000..5ac59c1 --- /dev/null +++ b/src/components/terminal/KeyboardShortcuts.tsx @@ -0,0 +1,94 @@ +'use client'; + +import React, { useState } from 'react'; + +interface Shortcut { + keys: string[]; + description: string; +} + +const SHORTCUTS: Shortcut[] = [ + { keys: ['Enter'], description: 'Execute command' }, + { keys: ['↑', '↓'], description: 'Navigate command history' }, + { keys: ['Ctrl', 'L'], description: 'Clear terminal logs' }, + { keys: ['Ctrl', 'C'], description: 'Cancel current operation' }, + { keys: ['Tab'], description: 'Auto-complete command' }, + { keys: ['Esc'], description: 'Close modals/dialogs' }, +]; + +export const KeyboardShortcuts: React.FC = () => { + const [isExpanded, setIsExpanded] = useState(false); + + return ( +
+ + + {isExpanded && ( +
+

+ + + + Keyboard Shortcuts +

+
    + {SHORTCUTS.map((shortcut, index) => ( +
  • + {shortcut.description} + + {shortcut.keys.map((key, keyIndex) => ( + + {key} + + ))} + +
  • + ))} +
+

+ Type help for all commands +

+
+ )} +
+ ); +};