feat: add clickable example commands to welcome screen (#23)

* feat: add clickable example commands to welcome screen

Add 4 example commands to the welcome splash screen to make the client
more friendly on cold start and to new users:
- nip 29: View relay-based groups spec
- profile verbiricha@habla.news: Explore a Nostr profile
- req -k 1 -l 20: Query recent notes
- nips: Browse all NIPs

Commands are clickable and execute directly, opening the appropriate
window without requiring users to type or use the command palette.

Changes:
- Update GrimoireWelcome component with EXAMPLE_COMMANDS constant
- Add onExecuteCommand prop to handle direct command execution
- Update WorkspaceView to pass handleExecuteCommand callback
- Use parseAndExecuteCommand from command-parser for execution

* fix: lint

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Alejandro
2025-12-22 22:41:10 +01:00
committed by GitHub
parent 5a97caffb1
commit 75500fa298
2 changed files with 61 additions and 3 deletions

View File

@@ -4,9 +4,23 @@ import { Kbd, KbdGroup } from "./ui/kbd";
interface GrimoireWelcomeProps {
onLaunchCommand: () => void;
onExecuteCommand: (command: string) => void;
}
export function GrimoireWelcome({ onLaunchCommand }: GrimoireWelcomeProps) {
const EXAMPLE_COMMANDS = [
{ command: "nip 29", description: "View relay-based groups spec" },
{
command: "profile verbiricha@habla.news",
description: "Explore a Nostr profile",
},
{ command: "req -k 1 -l 20", description: "Query recent notes" },
{ command: "nips", description: "Browse all NIPs" },
];
export function GrimoireWelcome({
onLaunchCommand,
onExecuteCommand,
}: GrimoireWelcomeProps) {
return (
<div className="h-full w-full flex items-center justify-center">
<div className="flex flex-col items-center gap-8">
@@ -65,6 +79,27 @@ export function GrimoireWelcome({ onLaunchCommand }: GrimoireWelcomeProps) {
<span>Launch Command</span>
</Button>
</div>
{/* Example commands */}
<div className="flex flex-col items-start gap-2 w-full max-w-md">
<p className="text-muted-foreground text-xs font-mono mb-1">
Try these commands:
</p>
{EXAMPLE_COMMANDS.map(({ command, description }) => (
<button
key={command}
onClick={() => onExecuteCommand(command)}
className="w-full text-left px-3 py-2 rounded-md border border-border hover:border-accent hover:bg-accent/5 transition-colors group"
>
<div className="font-mono text-sm text-foreground group-hover:text-accent transition-colors">
{command}
</div>
<div className="text-xs text-muted-foreground mt-0.5">
{description}
</div>
</button>
))}
</div>
</div>
</div>
);

View File

@@ -4,15 +4,35 @@ import { WindowToolbar } from "./WindowToolbar";
import { WindowTile } from "./WindowTitle";
import { GrimoireWelcome } from "./GrimoireWelcome";
import { useAppShell } from "./layouts/AppShellContext";
import { parseAndExecuteCommand } from "@/lib/command-parser";
export function WorkspaceView() {
const { state, updateLayout, removeWindow } = useGrimoire();
const { state, updateLayout, removeWindow, addWindow } = useGrimoire();
const { openCommandLauncher } = useAppShell();
const handleRemoveWindow = (id: string) => {
removeWindow(id);
};
const handleExecuteCommand = async (commandString: string) => {
const result = await parseAndExecuteCommand(
commandString,
state.activeAccount?.pubkey,
);
if (result.error || !result.props || !result.command) {
console.error("Failed to execute command:", result.error);
return;
}
addWindow(
result.command.appId,
result.props,
commandString,
result.globalFlags?.windowProps?.title,
);
};
const renderTile = (id: string, path: MosaicBranch[]) => {
const window = state.windows[id];
@@ -48,7 +68,10 @@ export function WorkspaceView() {
return (
<>
{activeWorkspace.layout === null ? (
<GrimoireWelcome onLaunchCommand={openCommandLauncher} />
<GrimoireWelcome
onLaunchCommand={openCommandLauncher}
onExecuteCommand={handleExecuteCommand}
/>
) : (
<Mosaic
renderTile={renderTile}