DEV Community

artydev
artydev

Posted on

AI and Juris

I have asked Claude to create a doc for new Juris users.

Juris Framework - Complete Beginner's Guide

What is Juris?

Juris is a simple JavaScript framework that helps you build interactive web applications. Think of it like a toolkit that makes it easy to:

  • Create reusable pieces of your webpage (called "components")
  • Handle user interactions (like clicking buttons or typing in forms)
  • Keep track of data that changes (like user input or loading states)

Unlike complex frameworks, Juris uses plain JavaScript objects to describe what you want your webpage to look like.

Your First Juris App

Let's start with the simplest possible example:

// Step 1: Create a simple component
const HelloWorld = () => {
  return {
    h1: {
      text: "Hello, World!",
      style: {
        color: "blue",
        "text-align": "center"
      }
    }
  };
};

// Step 2: Create the app
const app = new Juris({
  components: {
    HelloWorld
  },
  layout: [
    { HelloWorld: {} }
  ]
});

// Step 3: Show it on the page
app.render();
Enter fullscreen mode Exit fullscreen mode

What just happened?

  1. We created a component called HelloWorld that returns a description of an h1 element
  2. We told Juris about our component and where to put it
  3. We rendered it to the page

Understanding Components

Components are like LEGO blocks for your webpage. Each component describes a piece of your user interface.

Basic Component Structure

const MyComponent = () => {
  return {
    elementName: {
      text: "What to display",
      style: { /* How it should look */ },
      // More properties...
    }
  };
};
Enter fullscreen mode Exit fullscreen mode

Different Types of Elements

const ExampleElements = () => {
  return {
    div: {
      children: [
        {
          h1: { text: "This is a heading" }
        },
        {
          p: { text: "This is a paragraph" }
        },
        {
          button: { 
            text: "Click me!",
            style: { backgroundColor: "green", color: "white" }
          }
        },
        {
          input: { 
            placeholder: "Type something here...",
            style: { padding: "10px", fontSize: "16px" }
          }
        }
      ]
    }
  };
};
Enter fullscreen mode Exit fullscreen mode

Making Things Interactive with State

State is like the "memory" of your app. It remembers things like what the user typed, whether a button was clicked, etc.

Your First Interactive App

const Counter = (props, { getState, setState }) => {
  return {
    div: {
      style: { textAlign: "center", padding: "20px" },
      children: [
        {
          h2: { 
            text: () => `Count: ${getState("count") || 0}` 
          }
        },
        {
          button: {
            text: "Add 1",
            onclick: () => {
              const currentCount = getState("count") || 0;
              setState("count", currentCount + 1);
            },
            style: { 
              padding: "10px 20px", 
              fontSize: "16px",
              margin: "10px"
            }
          }
        }
      ]
    }
  };
};

const app = new Juris({
  components: { Counter },
  states: {
    count: 0  // Starting value
  },
  layout: [
    { Counter: {} }
  ]
});

app.render();
Enter fullscreen mode Exit fullscreen mode

Key concepts:

  • getState("count") - Gets the current value
  • setState("count", newValue) - Updates the value
  • text: () => ... - Use a function for text that changes
  • onclick: () => ... - Handle button clicks

Building a Real App: Todo List

Let's build something useful - a todo list app:

// Component to add new todos
const TodoInput = (props, { getState, setState }) => {
  return {
    div: {
      style: { marginBottom: "20px" },
      children: [
        {
          input: {
            placeholder: "What needs to be done?",
            style: { 
              padding: "10px", 
              fontSize: "16px", 
              width: "300px" 
            },
            onkeypress: (e) => {
              if (e.key === 'Enter' && e.target.value.trim()) {
                const todos = getState("todos") || [];
                const newTodo = {
                  id: Date.now(),
                  text: e.target.value.trim(),
                  completed: false
                };
                setState("todos", [...todos, newTodo]);
                e.target.value = '';  // Clear input
              }
            }
          }
        }
      ]
    }
  };
};

// Component to show the list of todos
const TodoList = (props, { getState, setState }) => {
  return {
    div: {
      children: () => {
        const todos = getState("todos") || [];
        return todos.map(todo => ({
          div: {
            style: { 
              padding: "10px", 
              border: "1px solid #ddd", 
              margin: "5px 0",
              backgroundColor: todo.completed ? "#f0f0f0" : "white"
            },
            children: [
              {
                input: {
                  type: "checkbox",
                  checked: todo.completed,
                  onchange: (e) => {
                    const todos = getState("todos");
                    const updatedTodos = todos.map(t => 
                      t.id === todo.id 
                        ? { ...t, completed: e.target.checked }
                        : t
                    );
                    setState("todos", updatedTodos);
                  }
                }
              },
              {
                span: { 
                  text: todo.text,
                  style: {
                    marginLeft: "10px",
                    textDecoration: todo.completed ? "line-through" : "none"
                  }
                }
              }
            ]
          }
        }));
      }
    }
  };
};

// Main app component
const TodoApp = () => {
  return {
    div: {
      style: { 
        maxWidth: "600px", 
        margin: "0 auto", 
        padding: "20px" 
      },
      children: [
        {
          h1: { 
            text: "My Todo List",
            style: { textAlign: "center" }
          }
        },
        { TodoInput: {} },
        { TodoList: {} }
      ]
    }
  };
};

// Create and run the app
const app = new Juris({
  components: {
    TodoApp,
    TodoInput,
    TodoList
  },
  states: {
    todos: []
  },
  layout: [
    { TodoApp: {} }
  ]
});

app.render();
Enter fullscreen mode Exit fullscreen mode

Adding External Services

Sometimes you need to do things like make API calls or log information. Juris lets you define "services" for this:

// Define services
const app = new Juris({
  services: {
    api: {
      saveData: (data) => {
        console.log("Saving:", data);
        // Here you could send to a server
        localStorage.setItem('myAppData', JSON.stringify(data));
      },
      loadData: () => {
        const saved = localStorage.getItem('myAppData');
        return saved ? JSON.parse(saved) : null;
      }
    }
  },
  components: {
    SaveButton: (props, { getState, setState, api }) => {
      return {
        button: {
          text: "Save Data",
          onclick: () => {
            const currentData = getState("userData");
            api.saveData(currentData);
            alert("Data saved!");
          }
        }
      };
    }
  },
  // ... rest of app config
});
Enter fullscreen mode Exit fullscreen mode

Listening to Changes

You can "subscribe" to changes in your app's state to do things like save data automatically:

// Save todos whenever they change
app.subscribe("todos", (oldTodos, newTodos) => {
  console.log(`Todo count changed from ${oldTodos?.length || 0} to ${newTodos.length}`);
  // Auto-save to browser storage
  localStorage.setItem('todos', JSON.stringify(newTodos));
});
Enter fullscreen mode Exit fullscreen mode

Loading Data When App Starts

const app = new Juris({
  // ... your components and config
  states: {
    todos: JSON.parse(localStorage.getItem('todos') || '[]')
  }
});
Enter fullscreen mode Exit fullscreen mode

Common Patterns and Tips

1. Handling Forms

const ContactForm = (props, { getState, setState }) => {
  return {
    form: {
      children: [
        {
          input: {
            placeholder: "Your name",
            oninput: (e) => setState("name", e.target.value)
          }
        },
        {
          input: {
            placeholder: "Your email", 
            type: "email",
            oninput: (e) => setState("email", e.target.value)
          }
        },
        {
          button: {
            text: "Submit",
            onclick: (e) => {
              e.preventDefault();
              const name = getState("name");
              const email = getState("email");
              alert(`Hello ${name}! We'll contact you at ${email}`);
            }
          }
        }
      ]
    }
  };
};
Enter fullscreen mode Exit fullscreen mode

2. Conditional Rendering

const LoginStatus = (props, { getState }) => {
  return {
    div: {
      text: () => {
        const user = getState("currentUser");
        return user ? `Welcome, ${user.name}!` : "Please log in";
      }
    }
  };
};
Enter fullscreen mode Exit fullscreen mode

3. Lists and Loops

const ShoppingList = (props, { getState }) => {
  return {
    ul: {
      children: () => {
        const items = getState("shoppingItems") || [];
        return items.map(item => ({
          li: { text: item.name }
        }));
      }
    }
  };
};
Enter fullscreen mode Exit fullscreen mode

Next Steps

Now that you understand the basics:

  1. Practice: Try building small apps like a calculator, weather display, or photo gallery
  2. Experiment: Try different HTML elements, CSS styles, and event handlers
  3. Build bigger: Combine multiple components to create more complex applications
  4. Learn async: Explore loading data from APIs using async components

Quick Reference

Component Structure

const MyComponent = (props, { getState, setState, ...services }) => {
  return {
    elementName: {
      text: "content" || () => "dynamic content",
      style: { cssProperty: "value" },
      children: [/* array of child elements */],
      onclick: (event) => { /* handle clicks */ },
      oninput: (event) => { /* handle input */ }
    }
  };
};
Enter fullscreen mode Exit fullscreen mode

App Setup

const app = new Juris({
  services: { /* your services */ },
  components: { /* your components */ },
  states: { /* initial state */ },
  layout: [{ ComponentName: { prop: "value" } }]
});

app.render();
app.subscribe("stateKey", (old, new) => { /* react to changes */ });
Enter fullscreen mode Exit fullscreen mode

That's it! You now know enough Juris to build real applications. Start small, experiment, and have fun building!

Top comments (0)