feat: Add ecosystem hub with deployment dashboard and protocol feature pages#4
feat: Add ecosystem hub with deployment dashboard and protocol feature pages#4ankitkr104 wants to merge 3 commits into
Conversation
…e pages This comprehensive update introduces the complete Tectonic protocol ecosystem interface with four new feature pages and enhanced navigation. ## Key Changes ### 🎯 New Pages Added (4 new feature pages) 1. **Deployments Dashboard** (app/deployments/page.tsx) - Live reserve ratio monitoring across all EVM chains - Contract health status with visual indicators - Mint/Redeem interface with real-time oracle prices - Interactive deployment cards with chain-specific data - Protocol overview section with sparkline charts 2. **Equity Coins Hub** (app/equity/page.tsx) - Detailed equity coin listings for all deployments - Per-deployment yield tracking and APR calculations - Price charts, leverage exposure, and supply metrics - Buy/Sell interface with status indicators 3. **Force Redemption Monitor** (app/force-redemption/page.tsx) - Real-time monitoring of reserve ratio health - Visual reserve ratio scale and safe threshold indicators - Detailed explanation of force redemption mechanism - One-click redemption interface for crisis scenarios 4. **StablePay Feature Page** (app/stablepay/page.tsx) - Interactive payment flow animation demo - Live checkout simulation (ETH to stablecoin conversion) - Technical flow explanation with step-by-step breakdown - Fee structure and settlement details ### 🧩 Component Updates - **New Navbar Component** (components/Navbar.tsx) - Global navigation with active link highlighting - Wallet connection modal with MetaMask, WalletConnect, Coinbase support - Connected wallet dropdown with address copy, chain info, balance display - Mobile responsive hamburger menu - Animated active state indicators - **Homepage Updates** (app/page.tsx) - Integrated Navbar component - Added HeroTypewriter component for animated hero text - Updated hero section with typewriter effect - Removed legacy status column from deployment table - Enhanced mobile responsiveness ### 📐 Configuration & Styling - **GitHub Pages Deployment** (next.config.ts) - Added static export configuration - BasePath and assetPrefix for GitHub Pages - Unoptimized images for static hosting - **CSS Enhancements** (app/globals.css) - Active navigation link styling with persistent underline - Improved visual hierarchy and transitions - **Documentation Update** (README.md) - Complete rewrite with better structure - Added Table of Contents - Expanded feature descriptions - Improved Getting Started section - Added Roadmap and Community integration links ## 🎨 Design Consistency - All new pages follow the existing amber/gold color palette (#fbbf24) - Consistent card design with warm off-white backgrounds (#fbf6ec) - Unified border styling with #e7dac4 - Status indicators: Emerald (healthy), Amber (warning), Red (danger/force redemption) - Matching typography and spacing across all components ## ✨ Features Included - Real-time data displays with mock API data - Animated transitions and interactive elements - Fully responsive design (mobile, tablet, desktop) - Accessibility features (ARIA labels, semantic HTML) - Modal dialogs for mint/redeem operations - Wallet connection management - Network chain indicators with color coding ## 📱 Responsive Design - Mobile-first approach with proper breakpoints - Touch-friendly interactive elements - Collapsible navigation menu for mobile - Adaptive card grids (1, 2, 3 columns based on screen size) ## 🔗 Navigation Structure ` / (home) ├── /deployments (Deployment Dashboard) ├── /equity (Equity Coins Hub) ├── /force-redemption (Force Redemption Monitor) └── /stablepay (StablePay Feature) ` ## 🚀 Ready for Deployment - Static export ready for GitHub Pages - All images optimized for static hosting - No server-side dependencies - Fast static site generation
|
Warning Review limit reached
More reviews will be available in 26 minutes and 6 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
WalkthroughThis PR introduces a comprehensive multi-page dashboard system for the Tectonic EVM Web UI. It adds three interconnected monitoring pages (Deployments, Equity, Force Redemption), a StablePay demo, an integrated wallet-connected navbar, homepage integration, a shared component library, and GitHub Pages deployment configuration. ChangesDashboard Pages and Navigation Infrastructure
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…pages - Fix property name references in app/equity/page.tsx: - c.border → c.cardBorder - c.bg → c.headerBg - c.bbg → c.badgeBg - c.bt → c.badgeBorder - c.dot → c.dotColor (with proper dot element) - Fix property name references in app/force-redemption/page.tsx: - c.bbg → c.badgeBg - c.bt → c.badgeBorder - c.dot → c.dotColor (with proper dot element) - c.bar → c.barColor These fixes resolve TypeScript compilation errors in the build.
There was a problem hiding this comment.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
app/page.tsx (3)
513-513:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix the invalid Tailwind shadow utility.
At Line 513,
shadow-[0_10px_28_rgba(15,23,42,0.06)]is malformed (28is missingpx), so this shadow class won’t compile/apply as intended.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/page.tsx` at line 513, The Tailwind shadow utility in the div class string is malformed: replace the invalid fragment "shadow-[0_10px_28_rgba(15,23,42,0.06)]" (seen in the div with classes including rounded-2xl border bg-white/80 p-5 text-center) with a valid arbitrary shadow such as "shadow-[0_10px_28px_rgba(15,23,42,0.06)]" so the "28" includes the missing "px" and the shadow compiles/applies correctly.
141-163: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy liftExternalize user-visible strings to i18n resources.
This page introduces substantial inline UI copy; move it to resource files to satisfy localization requirements and avoid hardcoded English in components.
As per coding guidelines, "Internationalization: User-visible strings should be externalized to resource files (i18n)."Also applies to: 219-253, 280-285, 347-348, 380-385, 490-493, 551-552
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/page.tsx` around lines 141 - 163, The page contains hardcoded user-visible strings in the feature objects (properties title, emoji, desc) and elsewhere; extract these strings into your i18n resource files and replace the literals with lookup calls (e.g., t('features.forcedRedemptions.title'), t('features.forcedRedemptions.desc')) used by your app's translation helper; update the feature array (the objects with title/emoji/desc/color) and all other occurrences noted (lines ~219-253, 280-285, 347-348, 380-385, 490-493, 551-552) to reference the i18n keys, keep non-user-visible values like color unchanged, and ensure the component (page/component that renders these features) imports and uses the translation function so the UI strings come from the resource files.Source: Coding guidelines
305-305:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winReplace placeholder
href="#"links in user-facing CTAs.These anchors are currently dead/stale targets (for example at Lines 305, 321, 474, 482, 530, 557, 564, 571, 610-611, 620-621, 628-630), which degrades navigation and trust in core calls-to-action.
Also applies to: 321-321, 474-474, 482-482, 530-530, 557-557, 564-564, 571-571, 610-611, 620-621, 628-630
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/page.tsx` at line 305, Several user-facing CTA anchors use placeholder href="#" (e.g., the <a className="text-yellow-600 font-medium hover:underline">Learn more →</a> instances), which yields dead links; replace each placeholder link with the correct destination (internal route path or external URL) or convert the element to Next.js <Link> when routing within the app, and add an appropriate aria-label; for external targets include rel="noopener noreferrer" and target="_blank" as needed. Locate all occurrences by searching for the "Learn more →" text and the "text-yellow-600 font-medium hover:underline" class (and other CTA anchors called out in the comment) and update their hrefs or switch to Link accordingly so CTAs navigate to meaningful pages. Ensure accessibility attributes are present and remove any remaining '#' hrefs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/deployments/page.tsx`:
- Around line 168-180: The footer currently renders anchors with placeholder
href="#" in the map expressions for labels (the arrays used in the three blocks
that render ["Docs","Contracts","GitHub"], ["Discord","Twitter","Forum"], and
["Whitepaper","Blog","Press"]), causing broken links; update those renderings so
any item without a real URL is not an interactive anchor — either supply the
correct URL for that label (e.g., replace "#" with the real destination) or
render a non-clickable element (span or a visually/semantically disabled link
with aria-disabled and no href) for labels that aren’t ready, and ensure
GitHub/Discord/Twitter keep their external anchor behavior when real URLs exist.
- Around line 129-191: The PageShell component currently contains hardcoded UI
strings (e.g., the back link "← Back to Deployments", heading/subtitle, all
footer and list labels inside PageShell) which must be externalized to i18n
resources: replace literal JSX strings in PageShell with calls to your
translation API (e.g., t('deployments.back'), t('deployments.title'),
t('footer.protocol'), etc.), create matching keys in the locale resource files,
and load/use the translation hook or HOC at the top of PageShell (or pass
translated props) so the component consumes stable keys instead of literals;
update all other hardcoded blocks noted in the comment (the repeated
footer/sections around the component) similarly and ensure externalized keys
cover headings, link labels, list items and copyright text.
- Around line 223-239: The overlay markup (the top-level div with backdrop and
the inner dialog header that uses mode and d) must be converted into an
accessible dialog: add role="dialog" and aria-modal="true" to the dialog
container, add an aria-labelledby pointing to the header h3 (give the h3 a
stable id), and ensure the close button uses aria-label; wire Escape key
handling to call onClose and restore focus to the element that opened the
dialog; implement basic focus management (move initial focus into the
dialog—preferably to the first focusable control such as the close button—and
trap tab/shift+tab inside the dialog while open). Ensure backdrop click behavior
remains (existing onClick comparing e.target === e.currentTarget) and that these
changes are applied to both occurrences referenced in the file.
- Around line 388-398: The effect schedules requestAnimationFrame loops (tick)
but never cancels them, so add a cleanup that cancels the pending animation
frame on unmount: inside the useEffect that uses countDone, target, dur, s0,
tick, and setTvl, capture the requestAnimationFrame id(s) (assign the return
value of requestAnimationFrame to a variable and update it each time tick
re-schedules) and return a cleanup function that calls cancelAnimationFrame on
that id; this ensures tick stops and setTvl won't run after unmount.
- Around line 216-250: The mint asset selector (state variable asset and
setAsset) can diverge from the quote source used to compute receive (which
always uses d.oraclePrice and d.reserveAsset), causing incorrect quotes; fix by
removing the free selector and binding the control to the deployment's reserve
asset (use d.reserveAsset as the only option and initialize asset to
d.reserveAsset), or if you intend to support multiple reserve assets, implement
per-asset pricing logic: replace the single d.oraclePrice usage with a lookup
that picks the correct oracle price for the selected asset (e.g.,
getOraclePriceFor(asset) and use that in receive) and populate the <select>
options from deployment-supported assets instead of hardcoded ETH/WBTC/MATIC;
ensure setAsset updates the price lookup so receive recalculates correctly.
In `@app/equity/page.tsx`:
- Around line 16-154: This page has many hard-coded user strings (titles,
subtitles, badge text, stat labels, explainer items, card labels, button text,
table headers) — move all user-visible strings into your i18n resource files and
replace inline literals with i18n lookups (e.g., using useTranslation/t or a
translate function) inside the component; specifically update references used in
this file such as EQUITY_COINS, DEPLOYMENTS, the top-level title/subtitle/badge,
each label in the stats map, the explainer items array, the card header/status
text (c.label, button texts "Buy"/"Sell"/"Exit Position"), and the table header
literals to use locale keys, and add the necessary import (useTranslation) and
key names in your locale JSON so the component calls t('equity.title'),
t('equity.stats.teqtLabel'), etc., rather than embedding strings.
- Around line 64-72: The card component is using the old statusCfg aliases
(c.border/c.bg/c.bbg/c.bt/c.dot/bar) which don't match the provider contract;
update all references to use the provider field names instead (replace c.border
→ c.cardBorder, c.bg → c.headerBg, c.bbg → c.badgeBg, c.bt → c.badgeText, c.dot
→ c.dotColor and any bar → barColor) wherever the component renders (e.g., in
the JSX that uses eq and c in page.tsx and the other page with the same pattern)
so the className/style lookups align with the provider's
cardBorder/headerBg/badgeBg/badgeText/dotColor/barColor keys.
In `@app/force-redemption/page.tsx`:
- Around line 18-169: The page hardcodes all user-facing strings (e.g., the page
title "Force Redemption Monitor", subtitle, badge "Monitoring Active", banner
headings/descriptions, the "How Force Redemption Works" card items,
ReserveWidget label, table headers, button labels "Force Redeem"/"Monitor", and
the Reserve Ratio Scale labels) and must be externalized to i18n resource keys;
create keys for each literal (including the array of step items and table header
labels) and replace inline strings with i18n lookups in this component, the
mapped item arrays, and any child components like ReserveWidget; ensure dynamic
strings (e.g., banner "Force Redemption Active — {names}" and
dangerList/warningList joins, ratio/pct values) use interpolation/placeholders
from the i18n resources, and propagate locale props or use the existing i18n
hook (e.g., useLocale/useTranslation) so statusCfg, DEPLOYMENTS labels and
buttons render with localized text while preserving existing identifiers such as
dangerList, warningList, ReserveWidget, DEPLOYMENTS, statusCfg, and
setRedeemTarget.
In `@app/globals.css`:
- Around line 422-426: The rule .active-nav-link::after uses !important which
blocks overrides; change it to a more specific selector such as
.nav-link.active-nav-link::after (or increase specificity by combining
parent/class context) and remove the !important declarations so the underline
state is controlled by normal cascade and theming; update the selector for the
transform and opacity properties in the active-nav-link::after rule and ensure
no other conflicting rules rely on !important.
In `@app/stablepay/page.tsx`:
- Line 25: The anchor using href="#" inside the detail renderer for the "Payment
Successful" item (the detail: () => ... JSX in app/stablepay/page.tsx) should
not navigate; either replace the <a href="#">View on Explorer →</a> with a
<button> styled like a link (keeping classes like text-xs text-amber-600
hover:underline) or add an onClick handler that calls e.preventDefault() and any
intended handler; apply the same change to the other similar anchor instance
mentioned (the other detail renderer around the same component).
- Around line 7-213: The file currently hardcodes all user-visible strings —
externalize them to i18n resources: replace inline labels and text found in
PaymentFlow (step labels in the steps array, button text used in the CTA, input
placeholder/aria text, amount USD display, the step detail strings), and the
page-level strings in StablePayPage (title, subtitle, badge text, value
proposition items, technical flow items, table headers and rows) with keys
looked up from your i18n layer (e.g., t('stablepay.checkout.title') etc.);
update usages in functions/components PaymentFlow and StablePayPage to call the
translator (or use Trans components) and move all strings into locale
JSON/resource files, ensuring interpolation for dynamic values like amount and
method and keeping existing keys consistent with the UI structure.
- Around line 21-26: The steps array and its per-step detail callbacks are being
recreated on every render; extract them out of the component by creating a small
factory like buildSteps(amount, method) that returns the steps array (or by
exporting a constant for truly static entries) so you only allocate new objects
when amount/method change; update usages of steps in the component to call
buildSteps(amount, method) (or use the exported constant) and ensure the detail
entries no longer close over component scope but receive amount/method as
parameters or already-resolved JSX so you avoid recreating function instances
each render (refer to the steps variable and each detail callback in the diff).
- Around line 141-210: The component recreates three static arrays on every
render (the value props array mapped to item, the technical flow steps array
mapped to s, and the fee table rows array mapped from tuples), so extract them
as top-level constants (e.g., VALUE_PROPS, TECHNICAL_STEPS, FEE_ROWS) outside
the component in the same module and replace the inline arrays in the JSX with
those constants; keep the existing keys (item.title, s.n, action) and mapping
logic (the .map callbacks and JSX blocks) unchanged so the render behavior is
identical.
- Around line 42-48: The amount input lacks an associated label and allows
zero/negative values; add an accessible label linked to the input (use an id on
the input and a <label htmlFor="..."> or add aria-label) and enforce validation
on the amount state (in the onChange/onBlur handlers) so values below 1 are
rejected or clamped to a minimum of 1; update the input element referenced by
value={amount} and onChange={e => setAmount(...)} to parse the numeric value,
ignore or correct invalid/non-positive numbers, and set a min attribute
(min={1}) to reinforce browser-level validation.
- Around line 13-18: The start function schedules multiple timeouts (setTimeouts
setting setStep and setRunning) but doesn't clear them on unmount; change this
by storing each timer id in a ref (e.g., timersRef) when calling start, add a
useEffect that returns a cleanup which iterates timersRef to clearTimeout all
pending timers and resets the ref, and ensure you import useRef and useEffect
from React; also clear any existing timers at the start of start() before
scheduling new ones to avoid duplicates.
In `@components/Navbar.tsx`:
- Around line 355-359: The Docs nav entry in NAV_ITEMS uses an in-page anchor
("`#docs`") which can be a dead link on routes without that anchor; update
NAV_ITEMS so the Docs item points to a stable route (for example change the href
value for the object with label "Docs" from "`#docs`" to "/docs" or another
guaranteed route/id) and ensure any route-generation or Link/Menu rendering
logic continues to use NAV_ITEMS unchanged.
In `@next.config.ts`:
- Around line 5-13: The config currently hardcodes repoName
("Tectonic-EVM-WebUI") which breaks basePath/assetPrefix for forks or renames;
replace the static repoName with a value derived from the GITHUB_REPOSITORY
environment variable when isGitHubPagesBuild is true. Update nextConfig to
compute repoSlug = process.env.GITHUB_REPOSITORY?.split("/")[1] ||
repoNameFallback and use that repoSlug for basePath and assetPrefix (referencing
repoName, basePath, assetPrefix, and isGitHubPagesBuild) so CI-provided
repository names drive the paths while preserving a sensible fallback.
In `@README.md`:
- Around line 93-108: The README's project tree is outdated and omits new files
introduced in this PR; update the ASCII tree to include the new navigation and
pages by adding entries for components/Navbar.tsx and the app routes
app/deployments/page.tsx, app/equity/page.tsx, app/force-redemption/page.tsx,
and app/stablepay/page.tsx so the structure matches the repository; ensure the
filenames match the exact casing used in the repo and place each file under the
correct directory node (components/ and app/) in the displayed tree.
- Around line 193-204: The ordered list in README.md is broken by an unindented
code block between steps 4 and 5 which triggers markdown linters; fix the list
by either converting step 4 to a single inline sentence ("Run `npm run build`
and `npm run lint` to verify your changes") or by indenting the fenced code
block so it belongs to step 4 (e.g., indent the triple-backtick fence and its
contents under the "4. Run:" line) so the numbering (steps 1–5) remains
continuous and lint-safe.
---
Outside diff comments:
In `@app/page.tsx`:
- Line 513: The Tailwind shadow utility in the div class string is malformed:
replace the invalid fragment "shadow-[0_10px_28_rgba(15,23,42,0.06)]" (seen in
the div with classes including rounded-2xl border bg-white/80 p-5 text-center)
with a valid arbitrary shadow such as "shadow-[0_10px_28px_rgba(15,23,42,0.06)]"
so the "28" includes the missing "px" and the shadow compiles/applies correctly.
- Around line 141-163: The page contains hardcoded user-visible strings in the
feature objects (properties title, emoji, desc) and elsewhere; extract these
strings into your i18n resource files and replace the literals with lookup calls
(e.g., t('features.forcedRedemptions.title'),
t('features.forcedRedemptions.desc')) used by your app's translation helper;
update the feature array (the objects with title/emoji/desc/color) and all other
occurrences noted (lines ~219-253, 280-285, 347-348, 380-385, 490-493, 551-552)
to reference the i18n keys, keep non-user-visible values like color unchanged,
and ensure the component (page/component that renders these features) imports
and uses the translation function so the UI strings come from the resource
files.
- Line 305: Several user-facing CTA anchors use placeholder href="#" (e.g., the
<a className="text-yellow-600 font-medium hover:underline">Learn more →</a>
instances), which yields dead links; replace each placeholder link with the
correct destination (internal route path or external URL) or convert the element
to Next.js <Link> when routing within the app, and add an appropriate
aria-label; for external targets include rel="noopener noreferrer" and
target="_blank" as needed. Locate all occurrences by searching for the "Learn
more →" text and the "text-yellow-600 font-medium hover:underline" class (and
other CTA anchors called out in the comment) and update their hrefs or switch to
Link accordingly so CTAs navigate to meaningful pages. Ensure accessibility
attributes are present and remove any remaining '#' hrefs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 91c4bc52-7666-4471-a784-736f925dc794
📒 Files selected for processing (9)
README.mdapp/deployments/page.tsxapp/equity/page.tsxapp/force-redemption/page.tsxapp/globals.cssapp/page.tsxapp/stablepay/page.tsxcomponents/Navbar.tsxnext.config.ts
| export function PageShell({ title, subtitle, badge, children }: { | ||
| title: string; subtitle: string; badge?: React.ReactNode; children: React.ReactNode; | ||
| }) { | ||
| return ( | ||
| <> | ||
| <Navbar /> | ||
| <div className="pt-[68px] border-b border-[#e7dac4] bg-white"> | ||
| <div className="max-w-7xl mx-auto px-4 sm:px-6 py-8 flex items-start justify-between flex-wrap gap-4"> | ||
| <div> | ||
| <Link href="/deployments" | ||
| className="text-xs font-semibold text-amber-600 hover:text-amber-700 transition flex items-center gap-1 mb-3"> | ||
| ← Back to Deployments | ||
| </Link> | ||
| <h1 className="text-2xl md:text-3xl font-bold text-[#1a1a1a]">{title}</h1> | ||
| <p className="text-gray-500 text-sm mt-1 max-w-xl">{subtitle}</p> | ||
| </div> | ||
| {badge} | ||
| </div> | ||
| </div> | ||
| <main className="min-h-screen bg-[#fbf6ec] pb-24"> | ||
| <div className="max-w-7xl mx-auto px-4 sm:px-6 py-8">{children}</div> | ||
| </main> | ||
| {/* footer — identical to homepage */} | ||
| <footer className="relative overflow-hidden border-t border-amber-200 bg-gradient-to-br from-amber-50 via-white to-orange-50 px-6 pt-14 pb-4"> | ||
| <div className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-amber-300 to-transparent opacity-80" /> | ||
| <div className="pointer-events-none absolute -left-16 bottom-0 h-40 w-40 rounded-full bg-amber-200/30 blur-3xl" /> | ||
| <div className="pointer-events-none absolute right-0 top-10 h-44 w-44 rounded-full bg-orange-200/30 blur-3xl" /> | ||
| <div className="relative mx-auto max-w-7xl px-2 pt-4 pb-0 md:px-6"> | ||
| <div className="grid gap-10 md:grid-cols-[1.25fr_1fr_1fr_1fr] md:gap-12"> | ||
| <div className="max-w-sm"> | ||
| <div className="logo-hover-wrap mb-4 flex items-center gap-3 text-slate-900"> | ||
| <Image src="/Logo.svg" alt="Tectonic logo" width={160} height={44} className="logo-hover-zoom h-9 w-auto object-contain" /> | ||
| <span className="text-xl font-black tracking-[0.22em]">TECTONIC</span> | ||
| </div> | ||
| <p className="max-w-xs text-sm leading-6 text-slate-600">Next-generation stablecoin protocol.</p> | ||
| </div> | ||
| <div> | ||
| <h4 className="mb-4 text-sm font-semibold uppercase tracking-[0.22em] text-amber-700">Protocol</h4> | ||
| <ul className="space-y-3 text-sm text-slate-700"> | ||
| {["Docs","Contracts","GitHub"].map(l=><li key={l}><a href={l==="GitHub"?"https://github.com/StabilityNexus/Tectonic-EVM-WebUI":"#"} target={l==="GitHub"?"_blank":undefined} rel={l==="GitHub"?"noopener noreferrer":undefined} className="transition hover:text-amber-700 hover:underline hover:underline-offset-4">{l}</a></li>)} | ||
| </ul> | ||
| </div> | ||
| <div> | ||
| <h4 className="mb-4 text-sm font-semibold uppercase tracking-[0.22em] text-amber-700">Community</h4> | ||
| <ul className="space-y-3 text-sm text-slate-700"> | ||
| {["Discord","Twitter","Forum"].map(l=><li key={l}><a href={l==="Discord"?"https://discord.com/channels/995968619034984528/1503320626096635935":"#"} target={l==="Discord"?"_blank":undefined} rel={l==="Discord"?"noopener noreferrer":undefined} className="transition hover:text-amber-700 hover:underline hover:underline-offset-4">{l}</a></li>)} | ||
| </ul> | ||
| </div> | ||
| <div> | ||
| <h4 className="mb-4 text-sm font-semibold uppercase tracking-[0.22em] text-amber-700">Resources</h4> | ||
| <ul className="space-y-3 text-sm text-slate-700"> | ||
| {["Whitepaper","Blog","Press"].map(l=><li key={l}><a href="#" className="transition hover:text-amber-700 hover:underline hover:underline-offset-4">{l}</a></li>)} | ||
| </ul> | ||
| </div> | ||
| </div> | ||
| <div className="mt-24 border-t border-amber-200/80 pt-6"> | ||
| <p className="text-center text-sm text-slate-600">© 2026 Tectonic Protocol. All rights reserved.</p> | ||
| </div> | ||
| </div> | ||
| </footer> | ||
| </> | ||
| ); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift
Move the UI copy into locale resources instead of JSX literals.
Headings, button labels, status text, feature descriptions, and footer copy are all hardcoded in the component tree. That locks the dashboard to one language and makes future localization require code edits throughout the route. Please lift the copy into an i18n resource layer and keep stable keys in the component code.
As per coding guidelines, Internationalization: User-visible strings should be externalized to resource files (i18n).
Also applies to: 214-301, 420-703
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/deployments/page.tsx` around lines 129 - 191, The PageShell component
currently contains hardcoded UI strings (e.g., the back link "← Back to
Deployments", heading/subtitle, all footer and list labels inside PageShell)
which must be externalized to i18n resources: replace literal JSX strings in
PageShell with calls to your translation API (e.g., t('deployments.back'),
t('deployments.title'), t('footer.protocol'), etc.), create matching keys in the
locale resource files, and load/use the translation hook or HOC at the top of
PageShell (or pass translated props) so the component consumes stable keys
instead of literals; update all other hardcoded blocks noted in the comment (the
repeated footer/sections around the component) similarly and ensure externalized
keys cover headings, link labels, list items and copyright text.
Source: Coding guidelines
| {["Docs","Contracts","GitHub"].map(l=><li key={l}><a href={l==="GitHub"?"https://github.com/StabilityNexus/Tectonic-EVM-WebUI":"#"} target={l==="GitHub"?"_blank":undefined} rel={l==="GitHub"?"noopener noreferrer":undefined} className="transition hover:text-amber-700 hover:underline hover:underline-offset-4">{l}</a></li>)} | ||
| </ul> | ||
| </div> | ||
| <div> | ||
| <h4 className="mb-4 text-sm font-semibold uppercase tracking-[0.22em] text-amber-700">Community</h4> | ||
| <ul className="space-y-3 text-sm text-slate-700"> | ||
| {["Discord","Twitter","Forum"].map(l=><li key={l}><a href={l==="Discord"?"https://discord.com/channels/995968619034984528/1503320626096635935":"#"} target={l==="Discord"?"_blank":undefined} rel={l==="Discord"?"noopener noreferrer":undefined} className="transition hover:text-amber-700 hover:underline hover:underline-offset-4">{l}</a></li>)} | ||
| </ul> | ||
| </div> | ||
| <div> | ||
| <h4 className="mb-4 text-sm font-semibold uppercase tracking-[0.22em] text-amber-700">Resources</h4> | ||
| <ul className="space-y-3 text-sm text-slate-700"> | ||
| {["Whitepaper","Blog","Press"].map(l=><li key={l}><a href="#" className="transition hover:text-amber-700 hover:underline hover:underline-offset-4">{l}</a></li>)} |
There was a problem hiding this comment.
Replace the href="#" footer placeholders before shipping.
Docs, Contracts, Twitter, Forum, Whitepaper, Blog, and Press currently look interactive but only jump to the top of the current page. If those destinations are not ready yet, render plain text or a disabled state instead of broken links.
Also applies to: 675-696
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/deployments/page.tsx` around lines 168 - 180, The footer currently
renders anchors with placeholder href="#" in the map expressions for labels (the
arrays used in the three blocks that render ["Docs","Contracts","GitHub"],
["Discord","Twitter","Forum"], and ["Whitepaper","Blog","Press"]), causing
broken links; update those renderings so any item without a real URL is not an
interactive anchor — either supply the correct URL for that label (e.g., replace
"#" with the real destination) or render a non-clickable element (span or a
visually/semantically disabled link with aria-disabled and no href) for labels
that aren’t ready, and ensure GitHub/Discord/Twitter keep their external anchor
behavior when real URLs exist.
| {[ | ||
| { icon:"🔷", title:"Pay with ETH", desc:"Customers use native assets without worrying about stablecoin acquisition." }, | ||
| { icon:"🔄", title:"Auto-convert via oracle", desc:"The protocol fetches the live price and mints exactly the right amount of TUSD." }, | ||
| { icon:"💵", title:"Merchant gets stables", desc:"Merchants receive predictable stablecoin settlement, zero slippage exposure." }, | ||
| ].map(item => ( | ||
| <div key={item.title} className="rounded-2xl bg-white border border-amber-100 p-5 shadow-sm"> | ||
| <div className="text-2xl mb-2">{item.icon}</div> | ||
| <div className="font-bold text-sm text-slate-900 mb-1">{item.title}</div> | ||
| <p className="text-xs text-slate-500 leading-5">{item.desc}</p> | ||
| </div> | ||
| ))} | ||
| </div> | ||
|
|
||
| {/* interactive flow */} | ||
| <div className="mb-8"> | ||
| <h2 className="text-xl font-black text-slate-900 mb-2">Interactive Payment Demo</h2> | ||
| <p className="text-slate-500 text-sm mb-5">Edit the amount, pick a payment method, then click Continue to watch the flow animate.</p> | ||
| <PaymentFlow /> | ||
| </div> | ||
|
|
||
| {/* how it works */} | ||
| <div className="rounded-3xl border border-amber-100 bg-white p-6 shadow-sm mb-6"> | ||
| <h3 className="font-black text-slate-900 text-lg mb-5">Technical Flow</h3> | ||
| <div className="grid sm:grid-cols-4 gap-4"> | ||
| {[ | ||
| { n:"01", title:"ETH sent to contract", desc:"Customer triggers the payment transaction from their wallet." }, | ||
| { n:"02", title:"Oracle queries price", desc:"Chainlink or equivalent fetches live ETH/USD at the moment of payment." }, | ||
| { n:"03", title:"Reserve ratio checked", desc:"Protocol verifies minting won't push reserve below the safe threshold." }, | ||
| { n:"04", title:"TUSD minted & settled", desc:"Stablecoins are minted at 0.3% fee and transferred directly to the merchant." }, | ||
| ].map(s => ( | ||
| <div key={s.n} className="rounded-2xl bg-amber-50 p-4"> | ||
| <div className="text-2xl font-black text-amber-300 mb-2">{s.n}</div> | ||
| <div className="font-bold text-sm text-slate-800 mb-1">{s.title}</div> | ||
| <p className="text-xs text-slate-500 leading-5">{s.desc}</p> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| </div> | ||
|
|
||
| {/* fee table */} | ||
| <div className="rounded-2xl bg-white border border-amber-100 shadow-sm overflow-hidden"> | ||
| <div className="px-5 py-4 border-b border-slate-100 bg-slate-50/60"> | ||
| <h3 className="font-bold text-xs uppercase tracking-wider text-slate-500">Fee Structure</h3> | ||
| </div> | ||
| <div className="overflow-x-auto"> | ||
| <table className="w-full text-sm"> | ||
| <thead> | ||
| <tr className="border-b border-slate-100"> | ||
| {["Action", "Fee", "Recipient", "Notes"].map(h => ( | ||
| <th key={h} className="px-5 py-3 text-left text-[10px] font-bold uppercase tracking-widest text-slate-400">{h}</th> | ||
| ))} | ||
| </tr> | ||
| </thead> | ||
| <tbody className="divide-y divide-slate-50"> | ||
| {[ | ||
| ["Mint (StablePay)", "0.3%", "Equity coin holders", "Taken from minted stablecoin amount"], | ||
| ["Redeem", "0.3%", "Equity coin holders", "Taken from returned reserve asset"], | ||
| ["Force Redemption", "0.0%", "—", "No fee during crisis mode"], | ||
| ].map(([action, fee, recipient, notes]) => ( | ||
| <tr key={action} className="hover:bg-amber-50/30 transition"> | ||
| <td className="px-5 py-4 font-semibold text-slate-900">{action}</td> | ||
| <td className="px-5 py-4 font-black text-amber-600">{fee}</td> | ||
| <td className="px-5 py-4 text-slate-600 text-xs">{recipient}</td> | ||
| <td className="px-5 py-4 text-slate-400 text-xs">{notes}</td> | ||
| </tr> | ||
| ))} | ||
| </tbody> | ||
| </table> | ||
| </div> | ||
| </div> |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Extract static data arrays to constants outside the component.
The value props (lines 141-145), technical flow steps (lines 165-169), and fee table rows (lines 195-198) are all recreated on every render. Since this data is static, these arrays should be defined as constants outside the component to improve performance.
♻️ Proposed refactor
+const VALUE_PROPS = [
+ { icon:"🔷", title:"Pay with ETH", desc:"Customers use native assets without worrying about stablecoin acquisition." },
+ { icon:"🔄", title:"Auto-convert via oracle", desc:"The protocol fetches the live price and mints exactly the right amount of TUSD." },
+ { icon:"💵", title:"Merchant gets stables", desc:"Merchants receive predictable stablecoin settlement, zero slippage exposure." },
+] as const;
+
+const TECHNICAL_FLOW = [
+ { n:"01", title:"ETH sent to contract", desc:"Customer triggers the payment transaction from their wallet." },
+ { n:"02", title:"Oracle queries price", desc:"Chainlink or equivalent fetches live ETH/USD at the moment of payment." },
+ { n:"03", title:"Reserve ratio checked", desc:"Protocol verifies minting won't push reserve below the safe threshold." },
+ { n:"04", title:"TUSD minted & settled", desc:"Stablecoins are minted at 0.3% fee and transferred directly to the merchant." },
+] as const;
+
+const FEE_TABLE_ROWS = [
+ ["Mint (StablePay)", "0.3%", "Equity coin holders", "Taken from minted stablecoin amount"],
+ ["Redeem", "0.3%", "Equity coin holders", "Taken from returned reserve asset"],
+ ["Force Redemption", "0.0%", "—", "No fee during crisis mode"],
+] as const;
+
export default function StablePayPage() {
return (
<PageShell>
{/* value props */}
<div className="grid sm:grid-cols-3 gap-4 mb-8">
- {[
- { icon:"🔷", title:"Pay with ETH", desc:"Customers use native assets without worrying about stablecoin acquisition." },
- { icon:"🔄", title:"Auto-convert via oracle", desc:"The protocol fetches the live price and mints exactly the right amount of TUSD." },
- { icon:"💵", title:"Merchant gets stables", desc:"Merchants receive predictable stablecoin settlement, zero slippage exposure." },
- ].map(item => (
+ {VALUE_PROPS.map(item => (
{/* ... */}
))}
</div>
{/* technical flow */}
<div className="grid sm:grid-cols-4 gap-4">
- {[
- { n:"01", title:"ETH sent to contract", desc:"Customer triggers the payment transaction from their wallet." },
- { n:"02", title:"Oracle queries price", desc:"Chainlink or equivalent fetches live ETH/USD at the moment of payment." },
- { n:"03", title:"Reserve ratio checked", desc:"Protocol verifies minting won't push reserve below the safe threshold." },
- { n:"04", title:"TUSD minted & settled", desc:"Stablecoins are minted at 0.3% fee and transferred directly to the merchant." },
- ].map(s => (
+ {TECHNICAL_FLOW.map(s => (
{/* ... */}
))}
</div>
{/* fee table */}
<tbody className="divide-y divide-slate-50">
- {[
- ["Mint (StablePay)", "0.3%", "Equity coin holders", "Taken from minted stablecoin amount"],
- ["Redeem", "0.3%", "Equity coin holders", "Taken from returned reserve asset"],
- ["Force Redemption", "0.0%", "—", "No fee during crisis mode"],
- ].map(([action, fee, recipient, notes]) => (
+ {FEE_TABLE_ROWS.map(([action, fee, recipient, notes]) => (
{/* ... */}
))}
</tbody>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/stablepay/page.tsx` around lines 141 - 210, The component recreates three
static arrays on every render (the value props array mapped to item, the
technical flow steps array mapped to s, and the fee table rows array mapped from
tuples), so extract them as top-level constants (e.g., VALUE_PROPS,
TECHNICAL_STEPS, FEE_ROWS) outside the component in the same module and replace
the inline arrays in the JSX with those constants; keep the existing keys
(item.title, s.n, action) and mapping logic (the .map callbacks and JSX blocks)
unchanged so the render behavior is identical.
**next.config.ts:** - Replace hardcoded repo slug with GITHUB_REPOSITORY-derived value - Fixes broken routing for forks and template reuse **components/Navbar.tsx:** - Fix non-functional '#docs' link to valid homepage route - Prevents dead link on pages without anchor **app/deployments/page.tsx (MRModal):** - Add role='dialog' and aria-modal='true' for accessibility - Add aria-labelledby linking to dialog header - Add aria-label to close button - Implement Escape key handler for keyboard navigation - Fix asset selector to lock to deployment's reserve asset (removes state mutation) - Replaces free selector dropdown with read-only input field **app/deployments/page.tsx (useEffect):** - Cancel requestAnimationFrame on component unmount - Prevents animation callbacks running on unmounted component - Fixes potential memory leaks and React warnings **app/stablepay/page.tsx:** - Add useRef to track timeout IDs - Clear all pending timeouts on component unmount - Prevent state updates on unmounted component - Fixes memory leaks from setTimeout callbacks **README.md:** - Update project structure to reflect all new pages and components - Add descriptions for each new feature page - Fix markdown list interrupted by code block (improves linting)
This comprehensive update introduces the complete Tectonic protocol ecosystem interface with four new feature pages and enhanced navigation.
Key Changes
🎯 New Pages Added (4 new feature pages)
Deployments Dashboard (app/deployments/page.tsx)
Equity Coins Hub (app/equity/page.tsx)
Force Redemption Monitor (app/force-redemption/page.tsx)
StablePay Feature Page (app/stablepay/page.tsx)
🧩 Component Updates
New Navbar Component (components/Navbar.tsx)
Homepage Updates (app/page.tsx)
📐 Configuration & Styling
GitHub Pages Deployment (next.config.ts)
CSS Enhancements (app/globals.css)
Documentation Update (README.md)
🎨 Design Consistency
✨ Features Included
📱 Responsive Design
🔗 Navigation Structure
/ (home) ├── /deployments (Deployment Dashboard) ├── /equity (Equity Coins Hub) ├── /force-redemption (Force Redemption Monitor) └── /stablepay (StablePay Feature)🚀 Ready for Deployment
Recordings:
new.mp4
Additional Notes:
AI Usage Disclosure:
We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact. AI slop is strongly discouraged and may lead to banning and blocking. Do not spam our repos with AI slop.
Check one of the checkboxes below:
I have used the following AI models and tools: TODO
Checklist
Summary by CodeRabbit
New Features
Documentation
Style
Chores