diff --git a/apps/web/package.json b/apps/web/package.json index c8526dac..cfd98f55 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -45,6 +45,7 @@ "react": "^19.2.0", "react-dom": "^19.2.0", "react-icons": "^5.5.0", + "react-is": "^19.2.5", "recharts": "^3.6.0", "sonner": "^2.0.7", "tailwindcss": "^4.1.18", diff --git a/apps/web/src/components/landing/Landing.tsx b/apps/web/src/components/landing/Landing.tsx index 22155448..079ea5fd 100644 --- a/apps/web/src/components/landing/Landing.tsx +++ b/apps/web/src/components/landing/Landing.tsx @@ -11,7 +11,7 @@ import { LocalAccess } from "./local-access"; export const Landing = () => { return ( <> -
+
Don't want to use our random subdomains? No problem. Connect your own domain in seconds and get automatic SSL certificates.
+
Added on {new Date().toLocaleDateString()}
@@ -101,7 +101,7 @@ const PluginTabs = () => {
Learn more →
@@ -186,65 +186,65 @@ export const DeveloperExperience = () => {
return (
-
-
+
+
First-class
developer experience
-
-
-
+
+
+
-
+
-
+
Online in one line
-
+
One command, you're online. Seriously, try for yourself.
-
+
$ outray 3000
-
+
-
+
- Don't fw CLI?
+ Don't fw CLI?
-
+
Use our plugins to embed OutRay directly into your build tool.
-
+
-
+
-
+
Instant Observability
-
+
View live traffic happening on your APIs in real-time the second
it goes online.
-
+
{visibleLogs.map((log) => (
{
transition: { duration: 0.2 },
}}
transition={{ duration: 0.4, type: "spring", bounce: 0 }}
- className="flex items-center gap-3 p-3 rounded-xl bg-white/5 border border-white/5"
+ className="flex items-center gap-2 sm:gap-3 p-2.5 sm:p-3 rounded-xl bg-white/5 border border-white/5"
>
- {log.status}
- {log.method}
- {log.path}
- {log.time}
+ {log.status}
+ {log.method}
+ {log.path}
+ {log.time}
))}
diff --git a/apps/web/src/components/landing/hero.tsx b/apps/web/src/components/landing/hero.tsx
index 5aaa59e9..4fba9d88 100644
--- a/apps/web/src/components/landing/hero.tsx
+++ b/apps/web/src/components/landing/hero.tsx
@@ -50,25 +50,9 @@ export const Hero = () => {
-
-
-
- {/* posthog.capture("yc_badge_clicked")}
- className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/5 border border-white/10 text-sm text-white/60 backdrop-blur-sm hover:bg-white/10 transition-colors"
- initial={{ opacity: 0, y: -10 }}
- animate={{ opacity: 1, y: 0 }}
- transition={{ duration: 0.5 }}
- >
-
-
- Y
-
-
- Not backed by Y Combinator
- */}
+
+
+
{
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1 }}
>
-
+
setExposeHovered(true)}
onMouseLeave={() => setExposeHovered(false)}
>
- {/* Hidden streaming logs behind */}
{
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.3, type: "spring", bounce: 0 }}
- className="flex items-center whitespace-nowrap h-4"
+ className="flex items-center whitespace-nowrap h-3 sm:h-4"
>
- {log.method}
- {log.path}
+ {log.method}
+ {log.path}
{log.status}
))}
- {/* Front card that rotates */}
{
Expose
{" "}
- your local server
to the internet
+ your local server
to the internet
{
Get Started Free{" "}
{
(
New
-
+
Unlimited{" "}
.local
{" "}
domains
-
+
Test on any device in your network. Just add --local and your app is
instantly accessible at a memorable .local domain.
-
+
- mDNS Discovery
-
+
mDNS Discovery
+
Auto-discovered by all devices via Bonjour/Avahi
@@ -39,8 +39,8 @@ export const LocalAccess = () => (
- Trusted HTTPS
-
+
Trusted HTTPS
+
Automatic certificates with mkcert - no browser warnings
@@ -50,8 +50,8 @@ export const LocalAccess = () => (
- Zero Config
-
+
Zero Config
+
No port forwarding, no firewall rules, no DNS setup
@@ -59,7 +59,7 @@ export const LocalAccess = () => (
{/* Right - Terminal demo */}
-
+
@@ -67,17 +67,17 @@ export const LocalAccess = () => (
-
+
$ outray 3000 --local
-
- ✨ Tunnel:{" "}
- https://my-app.outray.app
+
+ ✨ Tunnel:
+ https://my-app.outray.app
-
- 📡 Local:{" "}
- https://my-app.local
+
+ 📡 Local:
+ https://my-app.local
diff --git a/apps/web/src/components/landing/multiple-protocols.tsx b/apps/web/src/components/landing/multiple-protocols.tsx
index 640f599e..a647e12c 100644
--- a/apps/web/src/components/landing/multiple-protocols.tsx
+++ b/apps/web/src/components/landing/multiple-protocols.tsx
@@ -4,11 +4,11 @@ export const MultipleProtocols = () => (
-
+
Any protocol,
anywhere.
-
+
OutRay isn't limited to just web traffic. Tunnel any TCP or UDP
service securely to your local machine with a single command.
@@ -25,14 +25,14 @@ export const MultipleProtocols = () => (
HTTP/HTTPS
-
+
Instant secure URLs for your local web servers, webhooks, and
APIs.
- outray http 3000
-
+ outray http 3000
+
@@ -47,13 +47,13 @@ export const MultipleProtocols = () => (
TCP Tunnels
-
+
Expose databases, SSH, RDP, and other TCP services securely.
- outray tcp 5432
-
+ outray tcp 5432
+
@@ -68,13 +68,13 @@ export const MultipleProtocols = () => (
UDP Tunnels
-
+
Perfect for game servers, streaming, and real-time applications.
- outray udp 25565
-
+ outray udp 25565
+
diff --git a/apps/web/src/components/landing/navbar.tsx b/apps/web/src/components/landing/navbar.tsx
index 4802852c..1513a753 100644
--- a/apps/web/src/components/landing/navbar.tsx
+++ b/apps/web/src/components/landing/navbar.tsx
@@ -110,7 +110,7 @@ export const Navbar = () => {
: "bg-transparent py-6"
}`}
>
-
+
-
+
It just works
-
+
-
+
-
+
-
+
100% Open Source
-
+
We believe in transparency and community. OutRay is built in the
open, so you can inspect the code, contribute features, or
self-host the entire platform on your own infrastructure.
@@ -20,7 +20,7 @@ export function OpenSource() {
href="https://github.com/akinloluwami/outray"
target="_blank"
rel="noopener noreferrer"
- className="inline-flex items-center gap-2 px-6 py-3 rounded-full bg-white text-black font-medium hover:bg-gray-200 transition-colors"
+ className="inline-flex items-center gap-2 px-6 py-3 rounded-full bg-white text-black text-sm sm:text-base font-medium hover:bg-gray-200 transition-colors"
>
Star on GitHub
@@ -29,7 +29,7 @@ export function OpenSource() {
href="https://discord.gg/DncjGcCHDg"
target="_blank"
rel="noopener noreferrer"
- className="inline-flex items-center gap-2 px-6 py-3 rounded-full bg-white/5 border border-white/10 text-white font-medium hover:bg-white/10 transition-colors"
+ className="inline-flex items-center gap-2 px-6 py-3 rounded-full bg-white/5 border border-white/10 text-white text-sm sm:text-base font-medium hover:bg-white/10 transition-colors"
>
Join Community
@@ -37,18 +37,17 @@ export function OpenSource() {
-
-
-
+
+
-
+
Auditable Security
-
+
Verify our security claims by inspecting the source code
yourself.
@@ -57,8 +56,8 @@ export function OpenSource() {
- Community Driven
-
+
Community Driven
+
Built with feedback and contributions from developers like
you.
@@ -67,8 +66,8 @@ export function OpenSource() {
- Self-Hostable
-
+
Self-Hostable
+
Run the entire stack on your own servers. No vendor lock-in.
@@ -76,8 +75,8 @@ export function OpenSource() {
- Free Forever
-
+
Free Forever
+
The core features will always be free and open source.
diff --git a/apps/web/src/components/overview/overview-card.tsx b/apps/web/src/components/overview/overview-card.tsx
index 17129037..b106b5a2 100644
--- a/apps/web/src/components/overview/overview-card.tsx
+++ b/apps/web/src/components/overview/overview-card.tsx
@@ -29,19 +29,19 @@ export function OverviewCard({
: "text-red-400 bg-red-500/10 border-red-500/20";
return (
-
-
-
- {icon}
+
+
+
+ {React.cloneElement(icon as React.ReactElement, { size: 18 })}
{(change !== undefined || trend !== "neutral") && (
{trend === "up" ? (
-
+
) : trend === "down" ? (
-
+
) : null}
{showDash
? "-"
@@ -53,17 +53,17 @@ export function OverviewCard({
-
+
{value}
-
+
{title}
{subValue && (
<>
•
- {subValue}
+ {subValue}
>
)}
diff --git a/apps/web/src/components/overview/overview-header.tsx b/apps/web/src/components/overview/overview-header.tsx
index 8da51386..6a6522eb 100644
--- a/apps/web/src/components/overview/overview-header.tsx
+++ b/apps/web/src/components/overview/overview-header.tsx
@@ -9,7 +9,7 @@ export function OverviewHeader({
onNewTunnelClick: () => void;
}) {
return (
-
+
Overview
@@ -22,9 +22,9 @@ export function OverviewHeader({
onClick={onNewTunnelClick}
disabled={isAtLimit}
leftIcon={ }
- className="shrink-0"
+ className="w-full sm:w-auto shrink-0"
>
- New Tunnel
+ New Tunnel
);
diff --git a/apps/web/src/components/overview/request-activity-card.tsx b/apps/web/src/components/overview/request-activity-card.tsx
index 36db3978..fa53a588 100644
--- a/apps/web/src/components/overview/request-activity-card.tsx
+++ b/apps/web/src/components/overview/request-activity-card.tsx
@@ -49,13 +49,13 @@ export function RequestActivityCard({
});
return (
-
+
{isPlaceholderData && (
)}
-
+
@@ -63,12 +63,12 @@ export function RequestActivityCard({
Traffic over time
-
+
{["1h", "24h", "7d", "30d"].map((range) => (
{!chartData || chartData.length === 0 ? (
-
+
No traffic data available yet
) : (
-
+
@@ -106,14 +106,15 @@ export function RequestActivityCard({
`${value}`}
diff --git a/apps/web/src/components/overview/stats-summary.tsx b/apps/web/src/components/overview/stats-summary.tsx
index 1d54908a..a6317ead 100644
--- a/apps/web/src/components/overview/stats-summary.tsx
+++ b/apps/web/src/components/overview/stats-summary.tsx
@@ -13,7 +13,7 @@ export type OverviewStats = {
export function StatsSummary({ stats }: { stats?: OverviewStats | null }) {
return (
-
+
+
{/* Mobile header */}
-
+
{/* Desktop sidebar - hidden on mobile */}
-
+
{/*
*/}
-
+
diff --git a/apps/web/src/routes/pricing.tsx b/apps/web/src/routes/pricing.tsx
index 310e8cee..c1e986ca 100644
--- a/apps/web/src/routes/pricing.tsx
+++ b/apps/web/src/routes/pricing.tsx
@@ -47,13 +47,13 @@ function PricingPage() {
-
+
-
-
+
+
Simple, transparent pricing
-
+
Start for free, upgrade as you grow. No hidden fees.
@@ -70,10 +70,10 @@ function PricingPage() {
{
value: "year" as const,
label: (
-
+
Yearly
-
- 2 months free
+
+ -2 months
),
@@ -87,7 +87,7 @@ function PricingPage() {
-
+
{plans.map((plan) => {
const f = plan.features as {
maxTunnels: number;
@@ -108,16 +108,16 @@ function PricingPage() {
return (
{plan.id === "beam" && (
<>
-
+
✨
Recommended
✨
@@ -125,31 +125,31 @@ function PricingPage() {
>
)}
-
+
{plan.name}
-
+
${displayPriceUSD}
- {intervalLabel}
+ {intervalLabel}
{showNGN && displayPriceNGN > 0 && (
-
+
₦{displayPriceNGN.toLocaleString()}
-
+
{intervalLabel}
)}
-
+
-