Todo App Source Code

Complete source code for the Todo App built with Nahir UI and K2

About This Example

This Todo App demonstrates how to build a complete application using Nahir UI, K2's component-based UI framework. The application includes:

  • Component-based architecture
  • State management
  • Event handling
  • Conditional rendering
  • List rendering
  • Filtering and sorting

The application uses Nahir UI's ramdisk caching for ultra-fast state updates and rendering, making it responsive even with large todo lists.

todo_app.k2
# Todo App Example using Nahir UI
import NahirUI

# Define the Todo item component
component TodoItem {
  props = {
    text: "",
    completed: false,
    onToggle: null,
    onDelete: null
  }
  
  render {
    element = "div"
    className = "todo-item"
    children = [
      {
        element: "input",
        type: "checkbox",
        checked: props.completed,
        onChange: props.onToggle
      },
      {
        element: "span",
        className: props.completed ? "todo-text completed" : "todo-text",
        content: props.text
      },
      {
        element: "button",
        className: "delete-button",
        onClick: props.onDelete,
        content: "Delete"
      }
    ]
  }
}

# Define the Todo App component
component TodoApp {
  state = {
    todos: [],
    newTodo: "",
    filter: "all"
  }
  
  # Generate a unique ID for a todo
  function generateId() {
    return "todo-" + Math.random().toString(36).substr(2, 9)
  }
  
  # Add a new todo
  function addTodo() {
    if (state.newTodo.trim() == "") {
      return
    }
    
    state.todos.push({
      id: generateId(),
      text: state.newTodo,
      completed: false
    })
    
    state.newTodo = ""
    updateState()
  }
  
  # Toggle a todo's completed status
  function toggleTodo(id) {
    for (todo in state.todos) {
      if (todo.id == id) {
        todo.completed = !todo.completed
        break
      }
    }
    
    updateState()
  }
  
  # Delete a todo
  function deleteTodo(id) {
    state.todos = state.todos.filter(todo => todo.id != id)
    updateState()
  }
  
  # Clear completed todos
  function clearCompleted() {
    state.todos = state.todos.filter(todo => !todo.completed)
    updateState()
  }
  
  # Set the filter
  function setFilter(filter) {
    state.filter = filter
    updateState()
  }
  
  # Get filtered todos
  function getFilteredTodos() {
    if (state.filter == "active") {
      return state.todos.filter(todo => !todo.completed)
    } else if (state.filter == "completed") {
      return state.todos.filter(todo => todo.completed)
    } else {
      return state.todos
    }
  }
  
  # Get the count of active todos
  function getActiveCount() {
    return state.todos.filter(todo => !todo.completed).length
  }
  
  # Update the component state
  function updateState() {
    # In Nahir UI, this triggers a re-render with ramdisk caching
    this.setState(state)
  }
  
  render {
    element = "div"
    className = "todo-app"
    children = [
      # Header
      {
        element: "div",
        className: "todo-header",
        children: [
          {
            element: "h2",
            content: "Nahir UI Todo App"
          },
          {
            element: "span",
            content: "K2 Language"
          }
        ]
      },
      
      # Input
      {
        element: "div",
        className: "todo-input-container",
        children: [
          {
            element: "input",
            className: "todo-input",
            placeholder: "What needs to be done?",
            value: state.newTodo,
            onChange: (e) => { state.newTodo = e.target.value }
          },
          {
            element: "button",
            className: "add-button",
            content: "Add",
            onClick: addTodo
          }
        ]
      },
      
      # Todo list
      {
        element: "ul",
        className: "todo-list",
        children: getFilteredTodos().map(todo => {
          return TodoItem.new({
            text: todo.text,
            completed: todo.completed,
            onToggle: () => toggleTodo(todo.id),
            onDelete: () => deleteTodo(todo.id)
          })
        })
      },
      
      # Footer
      {
        element: "div",
        className: "todo-footer",
        children: [
          {
            element: "span",
            className: "todo-count",
            content: getActiveCount() + " items left"
          },
          {
            element: "div",
            className: "filter-buttons",
            children: [
              {
                element: "button",
                className: state.filter == "all" ? "filter-button active" : "filter-button",
                content: "All",
                onClick: () => setFilter("all")
              },
              {
                element: "button",
                className: state.filter == "active" ? "filter-button active" : "filter-button",
                content: "Active",
                onClick: () => setFilter("active")
              },
              {
                element: "button",
                className: state.filter == "completed" ? "filter-button active" : "filter-button",
                content: "Completed",
                onClick: () => setFilter("completed")
              }
            ]
          },
          {
            element: "button",
            className: "clear-completed",
            content: "Clear completed",
            onClick: clearCompleted
          }
        ]
      }
    ]
  }
}

# Initialize with some sample todos
function initializeTodos() {
  return [
    {
      id: "todo-1",
      text: "Learn K2 language",
      completed: false
    },
    {
      id: "todo-2",
      text: "Install K2 compiler",
      completed: true
    },
    {
      id: "todo-3",
      text: "Build a Nahir UI application",
      completed: false
    },
    {
      id: "todo-4",
      text: "Deploy to production",
      completed: false
    }
  ]
}

# Create and render the Todo App
app = TodoApp.new()
app.state.todos = initializeTodos()
UI.render(app)

How It Works

The Todo App is built using two main components:

  1. TodoItem: A reusable component that represents a single todo item with checkbox, text, and delete button.
  2. TodoApp: The main application component that manages the state and renders the UI.

Key Features

  • State Management: The app maintains a state object with todos, new todo text, and current filter.
  • Event Handling: Functions like addTodo, toggleTodo, and deleteTodo handle user interactions.
  • Filtering: The getFilteredTodos function filters todos based on the current filter (all, active, completed).
  • Ramdisk Caching: Nahir UI's ramdisk caching ensures ultra-fast rendering and state updates.

Performance Optimizations

The Todo App uses several performance optimizations:

  • Component Reuse: The TodoItem component is reused for each todo, reducing memory usage.
  • Efficient Rendering: Only the necessary parts of the UI are updated when the state changes.
  • Ramdisk Caching: Component states are cached in ramdisk for microsecond access times.
  • Lazy Evaluation: Filtered todos are only computed when needed.

Running This Example

To run this example on your machine:

  1. Install K2 language: curl -sSL https://k2lang.org/install | bash
  2. Install Nahir UI: k2 install nahir-ui
  3. Save the code above as todo_app.k2
  4. Run the application: k2 todo_app.k2

The application will open in a window, or if you're in a terminal-only environment, it will render as text UI.

Ready to Build Your Own Nahir UI App?

Get started with Nahir UI and build ultra-fast user interfaces for your K2 applications.