Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions app/_components/custom-room-id-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ export function CustomRoomIdForm() {
<CollapsibleTrigger asChild>
<Button variant="ghost" className="text-muted-foreground text-xs">
<ChevronRightIcon className={cn("transition-transform", isOpen && "rotate-90")} />
Need a custom room ID?
需要自定义房间 ID?
</Button>
</CollapsibleTrigger>
<CollapsibleContent className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<Label htmlFor="custom-id">Custom Room ID</Label>
<Label htmlFor="custom-id">自定义房间 ID</Label>
<Input id="custom-id" placeholder="my-presentation-room" value={customRoomId} onChange={(e) => setCustomRoomId(e.target.value)} />
<span className="text-muted-foreground text-sm md:max-w-90">Must start and end with a letter or number. Dashes, underscores, and spaces allowed in between.</span>
<span className="text-muted-foreground text-sm md:max-w-90">必须以字母或数字开头和结尾。中间允许使用连字符、下划线和空格。</span>
</div>
<Button variant="outline" disabled={!customRoomId} asChild={!!customRoomId}>
<Link href={`/host?room=${customRoomId}`}>Create Room with Custom ID</Link>
<Link href={`/host?room=${customRoomId}`}>使用自定义 ID 创建房间</Link>
</Button>
</CollapsibleContent>
</Collapsible>
Expand Down
1 change: 1 addition & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@

body {
@apply bg-background text-foreground;
font-family: var(--font-inter), "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
}

button:not(:disabled),
Expand Down
18 changes: 9 additions & 9 deletions app/host/_components/share-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,25 @@ interface ShareOptionsProps {
export function ShareOptions({ roomId }: ShareOptionsProps) {
function copyRoomId() {
navigator.clipboard.writeText(roomId);
toast.success("Room code copied!", {
description: "Share this code with others to let them join your room."
toast.success("房间代码已复制!", {
description: "将此代码分享给他人,让他们加入您的房间。"
});
}

function copyShareableLink() {
const shareableUrl = `${window.location.origin}/join?room=${roomId}`;
navigator.clipboard.writeText(shareableUrl);
toast.success("Shareable link copied!", {
description: "Share this link with others to let them join your room directly."
toast.success("共享链接已复制!", {
description: "将此链接分享给他人,让他们直接加入您的房间。"
});
}

return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-2">
<p className="text-muted-foreground text-sm">Room Code</p>
<p className="text-muted-foreground text-sm">房间代码</p>
<code className="bg-muted flex w-full items-center justify-between gap-2 rounded-lg p-3 font-mono text-sm tracking-tight">
{roomId || "Generating room code..."}
{roomId || "正在生成房间代码..."}
<Button variant="ghost" size="sm" onClick={copyRoomId} disabled={!roomId} className="text-muted-foreground size-4">
<CopyIcon />
</Button>
Expand All @@ -41,14 +41,14 @@ export function ShareOptions({ roomId }: ShareOptionsProps) {
<span className="w-full border-t" />
</div>
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background text-muted-foreground px-2">or</span>
<span className="bg-background text-muted-foreground px-2"></span>
</div>
</div>

<div className="flex flex-col gap-2">
<p className="text-muted-foreground text-sm">Shareable Link</p>
<p className="text-muted-foreground text-sm">共享链接</p>
<code className="bg-muted flex w-full items-center justify-between gap-2 rounded-lg p-3 font-mono text-sm tracking-tight">
{roomId ? `${window.location.origin}/join?room=${roomId}` : "Generating link..."}
{roomId ? `${window.location.origin}/join?room=${roomId}` : "正在生成链接..."}
<Button variant="ghost" size="sm" onClick={copyShareableLink} disabled={!roomId} className="text-muted-foreground size-4">
<CopyIcon />
</Button>
Expand Down
30 changes: 15 additions & 15 deletions app/host/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function HostPage() {
});

newPeer.on("error", (err) => {
toast.error("Failed to create room", {
toast.error("创建房间失败", {
description: err.message
});
router.push("/");
Expand All @@ -47,8 +47,8 @@ export default function HostPage() {
};
} catch (error) {
console.error("Error initializing peer:", error);
toast.error("Failed to create room", {
description: "Please try again."
toast.error("创建房间失败", {
description: "请重试。"
});
router.push("/");
}
Expand All @@ -58,11 +58,11 @@ export default function HostPage() {
if (!peer) return;

if (!activeStream && connections.length > 0) {
toast.info("New viewer connected", {
description: "Click to start sharing your screen.",
toast.info("新观众已连接", {
description: "点击开始共享您的屏幕。",
duration: Infinity,
action: {
label: "Start Sharing",
label: "开始共享",
onClick: async () => {
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
Expand All @@ -72,8 +72,8 @@ export default function HostPage() {
setActiveStream(stream);
} catch (err) {
console.error("Screen sharing error:", err);
toast.error("Screen sharing error", {
description: "Failed to start screen sharing. Please try again."
toast.error("屏幕共享错误", {
description: "启动屏幕共享失败。请重试。"
});
}
}
Expand Down Expand Up @@ -101,8 +101,8 @@ export default function HostPage() {
}
setConnections([]);
setRoomId("");
toast.info("Session ended", {
description: "Your screen sharing session has been terminated."
toast.info("会话已结束", {
description: "您的屏幕共享会话已终止。"
});
router.push("/");
}
Expand All @@ -113,30 +113,30 @@ export default function HostPage() {
<Button variant="outline" asChild>
<Link href="/" className="flex items-center self-start">
<ArrowLeft />
Back to Home
返回首页
</Link>
</Button>

<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Monitor />
Your Screen Sharing Room
您的屏幕共享房间
</CardTitle>
<CardDescription>Share your room code or link with others to let them view your screen. To share audio as well, ensure you're using Chrome or Edge, and select the option to share a tab.</CardDescription>
<CardDescription>与他人分享您的房间代码或链接,让他们查看您的屏幕。如需同时共享音频,请确保使用 Chrome Edge 浏览器,并选择“共享标签页”选项。</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<ShareOptions roomId={roomId} />
<div className="bg-muted/50 flex items-center justify-between rounded-lg p-4">
<div className="text-muted-foreground flex items-center gap-2">
<Users className="size-4" />
<span className="text-sm">Current Viewers</span>
<span className="text-sm">当前观众人数</span>
</div>
<span className="text-lg font-semibold">{connections.length}</span>
</div>
{activeStream && (
<Button variant="destructive" onClick={endSession} className="self-end">
Stop sharing
停止共享
</Button>
)}
</CardContent>
Expand Down
26 changes: 13 additions & 13 deletions app/join/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export default function JoinPage() {

function joinRoom(roomIdToJoin: string = roomId) {
if (!roomIdToJoin.trim()) {
toast.error("Room code required", {
description: "Please enter a valid room code."
toast.error("需要房间代码", {
description: "请输入有效的房间代码。"
});
return;
}
Expand All @@ -55,8 +55,8 @@ export default function JoinPage() {
const connection = peer.connect(roomIdToJoin);

connection.on("open", () => {
toast.success("Connected!", {
description: "Waiting for host to share their screen..."
toast.success("已连接!", {
description: "正在等待房主共享屏幕..."
});
});

Expand All @@ -71,17 +71,17 @@ export default function JoinPage() {
setIsConnecting(false);
setRoomId("");
setActiveStream(null);
toast.error("Disconnected", {
description: "The session has been ended."
toast.error("已断开连接", {
description: "会话已结束。"
});
});
});

peer.on("error", (err) => {
console.error("Peer error:", err);
setIsConnecting(false);
toast.error("Connection failed", {
description: "Could not connect to the room. Please check the room code and try again."
toast.error("连接失败", {
description: "无法连接到房间。请检查房间代码并重试。"
});
});
}
Expand All @@ -91,24 +91,24 @@ export default function JoinPage() {
<Button variant="outline" asChild>
<Link href="/" className="flex items-center self-start">
<ArrowLeft />
Back to Home
返回首页
</Link>
</Button>

<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Users />
Join a Room
加入房间
</CardTitle>
<CardDescription>Enter the room code to join and view the shared screen</CardDescription>
<CardDescription>输入房间代码以加入并查看共享屏幕</CardDescription>
</CardHeader>
<CardContent>
{!activeStream ? (
<div className="flex flex-col gap-4">
<Input placeholder="Enter room code" value={roomId} onChange={(e) => setRoomId(e.target.value)} disabled={isConnecting} />
<Input placeholder="输入房间代码" value={roomId} onChange={(e) => setRoomId(e.target.value)} disabled={isConnecting} />
<Button className="w-full" onClick={() => joinRoom()} disabled={isConnecting || !roomId.trim()}>
{isConnecting ? "Connecting..." : "Join Room"}
{isConnecting ? "正在连接..." : "加入房间"}
</Button>
</div>
) : (
Expand Down
31 changes: 10 additions & 21 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,27 @@ import { ClarityScript } from "@/components/clarity-script";
import { Toaster } from "@/components/ui/sonner";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import Link from "next/link";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });
const inter = Inter({
subsets: ["latin"],
variable: "--font-inter"
});

export const metadata = {
title: "Screen Share - Share Your Screen Instantly",
description: "Share your screen instantly with anyone using a simple room code. No downloads or sign-ups required.",
keywords: ["screen sharing", "webrtc", "online screen share", "browser screen sharing", "free screen sharing", "share your screen", "share screen", "screen share"],
title: "屏幕共享 - 即时共享您的屏幕",
description: "使用简单的房间代码即可立即与任何人共享您的屏幕。无需下载或注册。",
keywords: ["屏幕共享", "webrtc", "在线屏幕共享", "浏览器屏幕共享", "免费屏幕共享", "共享您的屏幕", "共享屏幕", "屏幕分享"],
other: {
"google-site-verification": process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION || ""
}
} satisfies Metadata;

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className={inter.className}>
<main className="from-background to-muted flex min-h-screen flex-col justify-between bg-linear-to-b">
{children}
<footer className="text-muted-foreground px-4 py-8 text-center text-sm">
Built by{" "}
<Link href="https://tonghohin.vercel.app" className="underline" target="_blank">
Hin
</Link>
. The source code is available on{" "}
<Link href="https://github.com/tonghohin/screen-sharing" className="underline" target="_blank">
Github
</Link>
.
</footer>
</main>
<html lang="zh-CN">
<body className={`${inter.variable} antialiased`}>
<main className="from-background to-muted flex min-h-screen flex-col justify-between bg-linear-to-b">{children}</main>
<ClarityScript />
<Toaster richColors />
</body>
Expand Down
20 changes: 10 additions & 10 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ export default function Home() {
return (
<div className="mx-auto flex max-w-4xl flex-col gap-8 px-4 py-8">
<div className="flex flex-col gap-4 text-center">
<h1 className="text-4xl font-bold tracking-tight sm:text-6xl">Share Your Screen Instantly</h1>
<p className="text-primary text-xl">Create a room, share the code, and start presenting to your audience in seconds.</p>
<h1 className="text-4xl font-bold tracking-tight sm:text-6xl">立即共享您的屏幕</h1>
<p className="text-primary text-xl">创建房间,分享代码,即可在几秒钟内向观众进行演示。</p>
</div>
<div className="grid gap-4 md:grid-cols-2">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Monitor />
Start Sharing
开始共享
</CardTitle>
<CardDescription>Create a room and share your screen with others</CardDescription>
<CardDescription>创建房间并与他人共享您的屏幕</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<Link href="/host">
<Button className="w-full">Create Room</Button>
<Button className="w-full">创建房间</Button>
</Link>
<CustomRoomIdForm />
</CardContent>
Expand All @@ -32,23 +32,23 @@ export default function Home() {
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Users />
Join a Room
加入房间
</CardTitle>
<CardDescription>Enter a room code to view someone's screen</CardDescription>
<CardDescription>输入房间代码以查看他人的屏幕</CardDescription>
</CardHeader>
<CardContent>
<Link href="/join">
<Button variant="outline" className="w-full">
Join Room
加入房间
</Button>
</Link>
</CardContent>
</Card>
</div>
<Alert>
<AlertCircle />
<AlertTitle>Note</AlertTitle>
<AlertDescription>Screen sharing isn’t supported on mobile devices. Mobile users can still join a room to view screens shared by others.</AlertDescription>
<AlertTitle>备注</AlertTitle>
<AlertDescription>移动设备不支持屏幕共享。移动用户仍可以加入房间观看他人共享的屏幕。</AlertDescription>
</Alert>
</div>
);
Expand Down
Loading