lightfriend-add-frontend-page — community lightfriend-add-frontend-page, lightfriend, community, ide skills, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Perfect for Rust-based AI Agents needing WebAssembly frontend development capabilities. AI Assistant for dumphone users

ahtavarasmus ahtavarasmus
[65]
[7]
Updated: 3/3/2026

Agent Capability Analysis

The lightfriend-add-frontend-page skill by ahtavarasmus is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance.

Ideal Agent Persona

Perfect for Rust-based AI Agents needing WebAssembly frontend development capabilities.

Core Value

Empowers agents to create new pages in the Lightfriend Yew WebAssembly frontend using Rust, incorporating libraries like Yew and gloo_net for robust web development, and handling route enums and navigation links.

Capabilities Granted for lightfriend-add-frontend-page

Adding custom pages to the Lightfriend frontend
Creating route handlers for new page components
Implementing navigation links for seamless user experience

! Prerequisites & Limits

  • Requires Rust programming knowledge
  • Specific to Lightfriend Yew WebAssembly frontend
  • Needs access to frontend/src/pages/ and main.rs files
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

lightfriend-add-frontend-page

Install lightfriend-add-frontend-page, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command...

SKILL.md
Readonly

Adding a New Frontend Page

This skill guides you through adding a new page to the Lightfriend Yew WebAssembly frontend.

Overview

A complete page includes:

  • Page component in frontend/src/pages/
  • Route enum variant in main.rs
  • Route handler in switch function
  • Navigation link (if applicable)

Step-by-Step Process

1. Create Page Component

Create frontend/src/pages/{page_name}.rs:

rust
1use yew::prelude::*; 2use gloo_net::http::Request; 3use crate::config; 4 5#[function_component(PageName)] 6pub fn page_name() -> Html { 7 // State management 8 let data = use_state(|| None::<SomeData>); 9 let loading = use_state(|| true); 10 let error = use_state(|| None::<String>); 11 12 // Load data on mount 13 { 14 let data = data.clone(); 15 let loading = loading.clone(); 16 let error = error.clone(); 17 18 use_effect_with((), move |_| { 19 wasm_bindgen_futures::spawn_local(async move { 20 match fetch_data().await { 21 Ok(result) => { 22 data.set(Some(result)); 23 loading.set(false); 24 } 25 Err(e) => { 26 error.set(Some(e.to_string())); 27 loading.set(false); 28 } 29 } 30 }); 31 }); 32 } 33 34 html! { 35 <div class="page-container"> 36 <h1>{"Page Title"}</h1> 37 38 if *loading { 39 <p>{"Loading..."}</p> 40 } else if let Some(err) = (*error).clone() { 41 <p class="error">{err}</p> 42 } else if let Some(content) = (*data).clone() { 43 // Render content 44 <div> 45 {format!("Content: {:?}", content)} 46 </div> 47 } 48 </div> 49 } 50} 51 52// Helper functions 53async fn fetch_data() -> Result<SomeData, Box<dyn std::error::Error>> { 54 let token = /* get from context or local storage */; 55 let backend_url = config::get_backend_url(); 56 57 let response = Request::get(&format!("{}/api/endpoint", backend_url)) 58 .header("Authorization", &format!("Bearer {}", token)) 59 .send() 60 .await? 61 .json::<SomeData>() 62 .await?; 63 64 Ok(response) 65} 66 67#[derive(Clone, serde::Deserialize, serde::Serialize)] 68struct SomeData { 69 // Define your data structure 70}

2. Add Module Declaration

CRITICAL: This codebase does NOT use mod.rs files!

Instead, add the module declaration to the inline mod pages { } block in frontend/src/main.rs:

rust
1mod pages { 2 pub mod home; 3 pub mod landing; 4 pub mod {page_name}; // Add your new page here 5 // ... other pages 6}

NEVER create a mod.rs file - this is a common mistake. Lightfriend uses named module files (e.g., home.rs, landing.rs) and declares them in the inline module block in main.rs.

3. Add Route Variant

In frontend/src/main.rs, add a route variant to the Route enum:

rust
1#[derive(Clone, Routable, PartialEq)] 2pub enum Route { 3 #[at("/")] 4 Home, 5 #[at("/page-name")] 6 PageName, 7 // ... other routes 8 #[not_found] 9 #[at("/404")] 10 NotFound, 11}

4. Add Route Handler

In the switch() function in frontend/src/main.rs, add:

rust
1fn switch(route: Route) -> Html { 2 match route { 3 Route::Home => html! { <Home /> }, 4 Route::PageName => html! { <PageName /> }, 5 // ... other routes 6 Route::NotFound => html! { <h1>{"404 - Page Not Found"}</h1> }, 7 } 8}

If the page should appear in navigation, add to the Nav component in frontend/src/main.rs:

rust
1#[function_component(Nav)] 2fn nav() -> Html { 3 html! { 4 <nav> 5 <Link<Route> to={Route::Home}>{"Home"}</Link<Route>> 6 <Link<Route> to={Route::PageName}>{"Page Name"}</Link<Route>> 7 // ... other links 8 </nav> 9 } 10}

6. Test the Page

bash
1cd frontend && trunk serve

Navigate to http://localhost:8080/page-name

Common Patterns

Protected Routes (Require Auth)

rust
1use yew_hooks::use_local_storage; 2 3#[function_component(ProtectedPage)] 4pub fn protected_page() -> Html { 5 let token = use_local_storage::<String>("token".to_string()); 6 7 if token.is_none() { 8 // Redirect to login 9 let navigator = use_navigator().unwrap(); 10 navigator.push(&Route::Login); 11 return html! {}; 12 } 13 14 html! { 15 <div>{"Protected content"}</div> 16 } 17}

Page with Form

rust
1use web_sys::HtmlInputElement; 2 3#[function_component(FormPage)] 4pub fn form_page() -> Html { 5 let name_ref = use_node_ref(); 6 let email_ref = use_node_ref(); 7 let submitting = use_state(|| false); 8 9 let on_submit = { 10 let name_ref = name_ref.clone(); 11 let email_ref = email_ref.clone(); 12 let submitting = submitting.clone(); 13 14 Callback::from(move |e: SubmitEvent| { 15 e.prevent_default(); 16 let submitting = submitting.clone(); 17 18 let name = name_ref.cast::<HtmlInputElement>() 19 .unwrap() 20 .value(); 21 let email = email_ref.cast::<HtmlInputElement>() 22 .unwrap() 23 .value(); 24 25 submitting.set(true); 26 27 wasm_bindgen_futures::spawn_local(async move { 28 match submit_form(name, email).await { 29 Ok(_) => { 30 // Handle success 31 } 32 Err(e) => { 33 // Handle error 34 } 35 } 36 submitting.set(false); 37 }); 38 }) 39 }; 40 41 html! { 42 <form onsubmit={on_submit}> 43 <input 44 ref={name_ref} 45 type="text" 46 placeholder="Name" 47 required=true 48 /> 49 <input 50 ref={email_ref} 51 type="email" 52 placeholder="Email" 53 required=true 54 /> 55 <button type="submit" disabled={*submitting}> 56 if *submitting { 57 {"Submitting..."} 58 } else { 59 {"Submit"} 60 } 61 </button> 62 </form> 63 } 64} 65 66async fn submit_form(name: String, email: String) -> Result<(), Box<dyn std::error::Error>> { 67 let token = /* get from context */; 68 69 Request::post(&format!("{}/api/submit", config::get_backend_url())) 70 .header("Authorization", &format!("Bearer {}", token)) 71 .json(&serde_json::json!({ 72 "name": name, 73 "email": email, 74 }))? 75 .send() 76 .await?; 77 78 Ok(()) 79}

Page with Context

rust
1use yew::prelude::*; 2 3#[derive(Clone, PartialEq)] 4pub struct UserContext { 5 pub user_id: i32, 6 pub email: String, 7} 8 9#[function_component(ContextPage)] 10pub fn context_page() -> Html { 11 let user_ctx = use_context::<UserContext>() 12 .expect("UserContext not found"); 13 14 html! { 15 <div> 16 <p>{format!("User ID: {}", user_ctx.user_id)}</p> 17 <p>{format!("Email: {}", user_ctx.email)}</p> 18 </div> 19 } 20}

Page with Route Parameters

rust
1#[derive(Clone, Routable, PartialEq)] 2pub enum Route { 3 #[at("/users/:id")] 4 UserDetail { id: i32 }, 5} 6 7#[derive(Properties, PartialEq)] 8pub struct UserDetailProps { 9 pub id: i32, 10} 11 12#[function_component(UserDetail)] 13pub fn user_detail(props: &UserDetailProps) -> Html { 14 let user_data = use_state(|| None::<User>); 15 16 { 17 let user_data = user_data.clone(); 18 let user_id = props.id; 19 20 use_effect_with(user_id, move |_| { 21 wasm_bindgen_futures::spawn_local(async move { 22 if let Ok(user) = fetch_user(user_id).await { 23 user_data.set(Some(user)); 24 } 25 }); 26 }); 27 } 28 29 html! { 30 <div> 31 if let Some(user) = (*user_data).clone() { 32 <h1>{user.name}</h1> 33 } 34 </div> 35 } 36} 37 38// In switch function: 39fn switch(route: Route) -> Html { 40 match route { 41 Route::UserDetail { id } => html! { <UserDetail id={id} /> }, 42 // ... 43 } 44}

Page with Multiple API Calls

rust
1#[function_component(DashboardPage)] 2pub fn dashboard_page() -> Html { 3 let stats = use_state(|| None::<Stats>); 4 let activity = use_state(|| None::<Vec<Activity>>); 5 let loading = use_state(|| true); 6 7 { 8 let stats = stats.clone(); 9 let activity = activity.clone(); 10 let loading = loading.clone(); 11 12 use_effect_with((), move |_| { 13 wasm_bindgen_futures::spawn_local(async move { 14 // Fetch multiple endpoints in parallel 15 let (stats_result, activity_result) = tokio::join!( 16 fetch_stats(), 17 fetch_activity() 18 ); 19 20 if let Ok(s) = stats_result { 21 stats.set(Some(s)); 22 } 23 if let Ok(a) = activity_result { 24 activity.set(Some(a)); 25 } 26 27 loading.set(false); 28 }); 29 }); 30 } 31 32 html! { 33 <div> 34 if *loading { 35 <p>{"Loading dashboard..."}</p> 36 } else { 37 <div> 38 {render_stats(&stats)} 39 {render_activity(&activity)} 40 </div> 41 } 42 </div> 43 } 44}

Styling

Lightfriend uses CSS style blocks within the html! macro, NOT inline Tailwind classes.

Common pattern:

rust
1html! { 2 <div class="page-container"> 3 <h1 class="page-title">{"Title"}</h1> 4 <div class="content-grid"> 5 <div class="card"> 6 {"Card content"} 7 </div> 8 </div> 9 10 <style> 11 {r#" 12 .page-container { 13 max-width: 1200px; 14 margin: 0 auto; 15 padding: 2rem; 16 } 17 .page-title { 18 font-size: 2rem; 19 font-weight: bold; 20 margin-bottom: 1rem; 21 } 22 .content-grid { 23 display: grid; 24 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); 25 gap: 1rem; 26 } 27 .card { 28 background: white; 29 border-radius: 8px; 30 box-shadow: 0 2px 4px rgba(0,0,0,0.1); 31 padding: 1rem; 32 } 33 "#} 34 </style> 35 </div> 36}

Testing Checklist

  • Page renders without errors
  • Route works in browser
  • Navigation link works (if added)
  • API calls succeed
  • Loading states display correctly
  • Error states display correctly
  • Authentication checks work (if protected)
  • Mobile responsive (if applicable)

File Reference

  • Page components: frontend/src/pages/{page}.rs
  • Routes: frontend/src/main.rs (Route enum + switch function)
  • Navigation: frontend/src/main.rs (Nav component)
  • Shared components: frontend/src/components/
  • Backend config: frontend/src/config.rs

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is lightfriend-add-frontend-page?

Perfect for Rust-based AI Agents needing WebAssembly frontend development capabilities. AI Assistant for dumphone users

How do I install lightfriend-add-frontend-page?

Run the command: npx killer-skills add ahtavarasmus/lightfriend/lightfriend-add-frontend-page. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for lightfriend-add-frontend-page?

Key use cases include: Adding custom pages to the Lightfriend frontend, Creating route handlers for new page components, Implementing navigation links for seamless user experience.

Which IDEs are compatible with lightfriend-add-frontend-page?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for lightfriend-add-frontend-page?

Requires Rust programming knowledge. Specific to Lightfriend Yew WebAssembly frontend. Needs access to frontend/src/pages/ and main.rs files.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add ahtavarasmus/lightfriend/lightfriend-add-frontend-page. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use lightfriend-add-frontend-page immediately in the current project.

Related Skills

Looking for an alternative to lightfriend-add-frontend-page or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI