Skip to content

Commit cb6a544

Browse files
authored
Merge pull request #80 from evalstate/feat/landing-refresh
Add Codex CLI to the Settings Page
2 parents 75a9209 + ecfc7b2 commit cb6a544

File tree

2 files changed

+137
-41
lines changed

2 files changed

+137
-41
lines changed

packages/app/src/web/components/SettingsCopyPage.tsx

Lines changed: 84 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card';
22
import { Button } from './ui/button';
3+
import { CopyButton } from './ui/copy-button';
34
import hfLogoWithTitle from '../hf-logo-with-title.svg';
45
import {
56
Copy,
67
Settings,
7-
CheckCircle,
88
Search,
99
Rocket,
1010
ChevronDown,
@@ -670,20 +670,77 @@ const CLIENT_CONFIGS: ClientConfig[] = [
670670
],
671671
},
672672
},
673+
{
674+
id: 'codex-cli',
675+
name: 'Codex CLI',
676+
icon: (
677+
<svg
678+
className="h-5 w-5"
679+
xmlns="http://www.w3.org/2000/svg"
680+
width="1em"
681+
height="1em"
682+
fill="none"
683+
viewBox="0 0 32 32"
684+
>
685+
<path
686+
stroke="#000"
687+
strokeLinecap="round"
688+
strokeWidth="2.484"
689+
d="M22.356 19.797H17.17M9.662 12.29l1.979 3.576a.511.511 0 0 1-.005.504l-1.974 3.409M30.758 16c0 8.15-6.607 14.758-14.758 14.758-8.15 0-14.758-6.607-14.758-14.758C1.242 7.85 7.85 1.242 16 1.242c8.15 0 14.758 6.608 14.758 14.758Z"
690+
></path>
691+
</svg>
692+
),
693+
instructions: [
694+
{
695+
type: 'text',
696+
content: (
697+
<a
698+
href="https://github.com/openai/codex"
699+
target="_blank"
700+
rel="noopener noreferrer"
701+
className="inline-flex items-center space-x-2 text-primary hover:underline cursor-pointer"
702+
>
703+
<span>Codex CLI Instructions are at: https://github.com/openai/codex</span>
704+
<ExternalLink className="h-3 w-3" />
705+
</a>
706+
),
707+
},
708+
{
709+
type: 'text',
710+
content: (
711+
<span>
712+
Edit your <code className="bg-muted px-1 py-0.5 rounded text-xs font-mono">~/.codex/config.toml</code> and
713+
include the below:
714+
</span>
715+
),
716+
},
717+
{
718+
type: 'code',
719+
content: `[mcp_servers.huggingface]
720+
command = "npx"
721+
args = ["-y", "mcp-remote@latest", "https://huggingface.co/mcp?login"]`,
722+
copyable: true,
723+
},
724+
],
725+
actionButtons: [
726+
{
727+
type: 'external',
728+
label: 'Codex CLI Instructions',
729+
url: 'https://github.com/openai/codex',
730+
variant: 'outline',
731+
},
732+
],
733+
},
673734
];
674735

675736
export function SettingsCopyPage() {
676-
const [copied, setCopied] = useState(false);
677737
const [expandedClients, setExpandedClients] = useState<Set<string>>(new Set());
678738

679739
// Handler for copying MCP URL
680740
const handleCopyMcpUrl = async () => {
681741
const mcpUrl = `https://huggingface.co/mcp?login`;
682-
683742
try {
684743
await navigator.clipboard.writeText(mcpUrl);
685-
setCopied(true);
686-
setTimeout(() => setCopied(false), 2000);
687744
} catch (err) {
688745
console.error('Failed to copy URL:', err);
689746
}
@@ -707,15 +764,6 @@ export function SettingsCopyPage() {
707764
});
708765
};
709766

710-
// Handler for copying config examples
711-
const copyConfigExample = async (config: string) => {
712-
try {
713-
await navigator.clipboard.writeText(config);
714-
} catch (err) {
715-
console.error('Failed to copy config:', err);
716-
}
717-
};
718-
719767
// Handler for action buttons
720768
const handleActionButton = async (button: ActionButton) => {
721769
switch (button.type) {
@@ -773,14 +821,13 @@ export function SettingsCopyPage() {
773821
<code className="text-foreground font-mono">{step.content}</code>
774822
</pre>
775823
{step.copyable && (
776-
<Button
824+
<CopyButton
825+
content={step.content as string}
777826
variant="ghost"
778827
size="sm"
779-
onClick={() => copyConfigExample(step.content)}
780-
className="absolute top-2 right-2 h-6 px-2 text-xs transition-all duration-200 hover:bg-secondary hover:scale-110"
781-
>
782-
<Copy className="h-3 w-3" />
783-
</Button>
828+
iconOnly
829+
className="absolute top-2 right-2 h-6 px-2 text-xs"
830+
/>
784831
)}
785832
</div>
786833
);
@@ -793,7 +840,7 @@ export function SettingsCopyPage() {
793840
variant={step.button.variant || 'default'}
794841
size="sm"
795842
onClick={() => handleActionButton(step.button!)}
796-
className="ml-auto"
843+
className="ml-auto cursor-pointer"
797844
>
798845
{step.button.type === 'external' && <ExternalLink className="h-4 w-4 mr-2" />}
799846
{step.button.type === 'download' && <Download className="h-4 w-4 mr-2" />}
@@ -818,7 +865,7 @@ export function SettingsCopyPage() {
818865
<div className="bg-gradient-to-b from-primary/5 to-background px-8 pt-12 pb-8">
819866
<div className="max-w-4xl mx-auto text-center">
820867
<img src={hfLogoWithTitle} alt="Hugging Face" className="h-16 mx-auto mb-8" />
821-
<h1 className="text-3xl font-bold text-foreground mb-4">Welcome to the Hugging Face MCP Server</h1>
868+
<h2 className="text-3xl font-bold text-foreground mb-4">Welcome to the Hugging Face MCP Server</h2>
822869
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
823870
Connect assistants to the Hub and thousands of AI Apps
824871
</p>
@@ -853,14 +900,13 @@ export function SettingsCopyPage() {
853900
className="w-full px-4 py-3 pr-12 text-sm font-mono bg-muted border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/20 h-12 cursor-pointer hover:bg-muted/80 transition-colors"
854901
onClick={handleCopyMcpUrl}
855902
/>
856-
<Button
903+
<CopyButton
904+
content="https://huggingface.co/mcp?login"
905+
variant="secondary"
857906
size="sm"
858-
onClick={handleCopyMcpUrl}
859-
className="absolute right-2 top-1/2 transform -translate-y-1/2 h-8 px-2 hover:bg-secondary/80 transition-colors"
860-
variant={copied ? 'default' : 'secondary'}
861-
>
862-
{copied ? <CheckCircle className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
863-
</Button>
907+
iconOnly
908+
className="absolute right-2 top-1/2 transform -translate-y-1/2 h-8 px-2"
909+
/>
864910
</div>
865911
</div>
866912

@@ -884,7 +930,7 @@ export function SettingsCopyPage() {
884930
<Button
885931
size="sm"
886932
onClick={handleGoToSettings}
887-
className="absolute right-2 top-1/2 transform -translate-y-1/2 h-8 px-2 hover:bg-secondary/80 transition-colors"
933+
className="absolute right-2 top-1/2 transform -translate-y-1/2 h-8 px-2 hover:bg-secondary/80 transition-colors cursor-pointer"
888934
variant="secondary"
889935
>
890936
<ExternalLink className="h-4 w-4" />
@@ -936,7 +982,7 @@ export function SettingsCopyPage() {
936982
variant={button.variant || 'default'}
937983
size="sm"
938984
onClick={() => handleActionButton(button)}
939-
className="h-8"
985+
className="h-8 cursor-pointer"
940986
>
941987
{button.type === 'external' && <ExternalLink className="h-4 w-4 mr-2" />}
942988
{button.type === 'download' && <Download className="h-4 w-4 mr-2" />}
@@ -981,15 +1027,12 @@ export function SettingsCopyPage() {
9811027
<pre className="bg-muted p-3 rounded-md text-xs overflow-x-auto">
9821028
<code className="text-foreground font-mono">{client.configExample}</code>
9831029
</pre>
984-
<Button
1030+
<CopyButton
1031+
content={client.configExample!}
9851032
variant="ghost"
9861033
size="sm"
987-
onClick={() => copyConfigExample(client.configExample!)}
988-
className="absolute top-2 right-2 h-6 px-2 text-xs transition-all duration-200 hover:bg-secondary hover:scale-110"
989-
>
990-
<Copy className="h-3 w-3 mr-1" />
991-
Copy
992-
</Button>
1034+
className="absolute top-2 right-2 h-6 px-2 text-xs"
1035+
/>
9931036
</div>
9941037
)}
9951038

@@ -1032,14 +1075,14 @@ export function SettingsCopyPage() {
10321075
<Search className="h-5 w-5 text-primary mt-0.5" />
10331076
<div>
10341077
<h4 className="font-semibold text-sm text-foreground">Search Models and Datasets</h4>
1035-
<p className="text-sm text-muted-foreground">Browse and discover ML models</p>
1078+
<p className="text-sm text-muted-foreground">Discover Models and Trends</p>
10361079
</div>
10371080
</div>
10381081
<div className="flex items-start space-x-3">
10391082
<Rocket className="h-5 w-5 text-primary mt-0.5" />
10401083
<div>
1041-
<h4 className="font-semibold text-sm text-foreground">Run Spaces</h4>
1042-
<p className="text-sm text-muted-foreground">Interact with AI applications</p>
1084+
<h4 className="font-semibold text-sm text-foreground">Discover Spaces</h4>
1085+
<p className="text-sm text-muted-foreground">Add the latest AI Applications</p>
10431086
</div>
10441087
</div>
10451088
<div className="flex items-start space-x-3">
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { useState } from 'react';
2+
import { Button } from './button';
3+
import { Copy as CopyIcon, CheckCircle } from 'lucide-react';
4+
5+
interface CopyButtonProps {
6+
content: string;
7+
label?: string;
8+
copiedLabel?: string;
9+
variant?: 'default' | 'secondary' | 'outline' | 'ghost';
10+
size?: 'sm' | 'default';
11+
className?: string;
12+
iconOnly?: boolean;
13+
}
14+
15+
export function CopyButton({
16+
content,
17+
label = 'Copy',
18+
copiedLabel = 'Copied',
19+
variant = 'ghost',
20+
size = 'sm',
21+
className = '',
22+
iconOnly = false,
23+
}: CopyButtonProps) {
24+
const [copied, setCopied] = useState(false);
25+
26+
const handleCopy = async () => {
27+
try {
28+
await navigator.clipboard.writeText(content);
29+
setCopied(true);
30+
setTimeout(() => setCopied(false), 1800);
31+
} catch (err) {
32+
console.error('Failed to copy content:', err);
33+
}
34+
};
35+
36+
return (
37+
<Button
38+
variant={variant}
39+
size={size}
40+
onClick={handleCopy}
41+
aria-label={copied ? copiedLabel : label}
42+
className={`transition-all duration-200 hover:scale-110 cursor-pointer ${className}`}
43+
>
44+
{copied ? (
45+
<CheckCircle className={iconOnly ? 'h-3 w-3' : 'h-3 w-3 mr-1'} />
46+
) : (
47+
<CopyIcon className={iconOnly ? 'h-3 w-3' : 'h-3 w-3 mr-1'} />
48+
)}
49+
{!iconOnly && (copied ? copiedLabel : label)}
50+
</Button>
51+
);
52+
}
53+

0 commit comments

Comments
 (0)